def checkperms(state): for file in ALIASFILE, VIRTFILE: if state.VERBOSE: print C_('checking permissions on %(file)s') stat = None try: stat = os.stat(file) except OSError, e: if e.errno <> errno.ENOENT: raise if stat and (stat[ST_MODE] & targetmode) <> targetmode: state.ERRORS += 1 octmode = oct(stat[ST_MODE]) print C_('%(file)s permissions must be 0664 (got %(octmode)s)'), if state.FIX: print C_('(fixing)') os.chmod(file, stat[ST_MODE] | targetmode) else: print # Make sure the corresponding .db files are owned by the Mailman user. # We don't need to check the group ownership of the file, since # check_perms checks this itself. dbfile = file + '.db' stat = None try: stat = os.stat(dbfile) except OSError, e: if e.errno <> errno.ENOENT: raise continue
def fix_url(mlist, *args): try: opts, args = getopt.getopt(args, 'u:v', ['urlhost=', 'verbose']) except getopt.error as 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 # Make sure list is locked. if not mlist.Locked(): if verbose: print(C_('Locking list')) mlist.Lock() if urlhost: web_page_url = mm_cfg.DEFAULT_URL_PATTERN % urlhost mailhost = mm_cfg.VIRTUAL_HOSTS.get(urlhost.lower(), urlhost) else: web_page_url = mm_cfg.DEFAULT_URL_PATTERN % mm_cfg.DEFAULT_URL_HOST mailhost = mm_cfg.DEFAULT_EMAIL_HOST if verbose: print(C_('Setting web_page_url to: %(web_page_url)s')) mlist.web_page_url = web_page_url if verbose: print(C_('Setting host_name to: %(mailhost)s')) mlist.host_name = mailhost print(C_('Saving list')) mlist.Save() mlist.Unlock()
def __init__(self, basedir=None, reload=1, database=None): # If basedir isn't provided, assume the current directory if basedir is None: self.basedir = os.getcwd() else: basedir = os.path.expanduser(basedir) self.basedir = basedir self.database = database # If the directory doesn't exist, create it. This code shouldn't get # run anymore, we create the directory in Archiver.py. It should only # get used by legacy lists created that are only receiving their first # message in the HTML archive now -- Marc try: os.stat(self.basedir) except os.error as errdata: errno, errmsg = errdata if errno != 2: raise os.error(errdata) else: self.message(C_('Creating archive directory ') + self.basedir) omask = os.umask(0) try: os.mkdir(self.basedir, self.DIRMODE) finally: os.umask(omask) # Try to load previously pickled state try: if not reload: raise IOError f = open(os.path.join(self.basedir, 'pipermail.pck'), 'r') self.message(C_('Reloading pickled archive state')) d = pickle.load(f) f.close() for key, value in list(d.items()): setattr(self, key, value) except (IOError, EOFError): # No pickled version, so initialize various attributes self.archives = [] # Archives self._dirty_archives = [] # Archives that will have to be updated self.sequence = 0 # Sequence variable used for # numbering articles self.update_TOC = 0 # Does the TOC need updating? # # make the basedir variable work when passed in as an __init__ arg # and different from the one in the pickle. Let the one passed in # as an __init__ arg take precedence if it's stated. This way, an # archive can be moved from one place to another and still work. # if basedir != self.basedir: self.basedir = basedir
def create(mlist, cgi=False, nolock=False, quiet=False): if mlist is None: return listname = mlist.internal_name() fieldsz = len(listname) + len('-unsubscribe') if cgi: # If a list is being created via the CGI, the best we can do is send # an email message to mailman-owner requesting that the proper aliases # be installed. sfp = StringIO() if not quiet: print(_(""" The mailing list `%(listname)s' has been created via the through-the-web interface. In order to complete the activation of this mailing list, the proper /etc/aliases (or equivalent) file must be updated. The program `newaliases' may also have to be run. Here are the entries for the /etc/aliases file: """), file=sfp) outfp = sfp else: if not quiet: print( C_("""\ To finish creating your mailing list, you must edit your /etc/aliases (or equivalent) file by adding the following lines, and possibly running the `newaliases' program: """)) print(C_("""\ ## %(listname)s mailing list""")) outfp = sys.stdout # Common path for k, v in makealiases(listname): print(k + ':', ((fieldsz - len(k)) * ' '), v, file=outfp) # If we're using the command line interface, we're done. For ttw, we need # to actually send the message to mailman-owner now. if not cgi: print(file=outfp) return # Send the message to the site -owner so someone can do something about # this request. siteowner = Utils.get_site_email(extra='owner') # Should this be sent in the site list's preferred language? msg = Message.UserNotification( siteowner, siteowner, _('Mailing list creation request for list %(listname)s'), sfp.getvalue(), mm_cfg.DEFAULT_SERVER_LANGUAGE) msg.send(mlist)
def checkperms(state): for file in ALIASFILE, VIRTFILE: if state.VERBOSE: print(C_('checking permissions on %(file)s')) stat = None try: stat = os.stat(file) except OSError as e: if e.errno != errno.ENOENT: raise if stat and (stat[ST_MODE] & targetmode) != targetmode: state.ERRORS += 1 octmode = oct(stat[ST_MODE]) print(C_('%(file)s permissions must be 0664 (got %(octmode)s)'), end=' ') if state.FIX: print(C_('(fixing)')) os.chmod(file, stat[ST_MODE] | targetmode) else: print() # Make sure the corresponding .db files are owned by the Mailman user. # We don't need to check the group ownership of the file, since # check_perms checks this itself. dbfile = file + '.db' stat = None try: stat = os.stat(dbfile) except OSError as e: if e.errno != errno.ENOENT: raise continue if state.VERBOSE: print(C_('checking ownership of %(dbfile)s')) user = mm_cfg.MAILMAN_USER ownerok = stat[ST_UID] == pwd.getpwnam(user)[2] if not ownerok: try: owner = pwd.getpwuid(stat[ST_UID])[0] except KeyError: owner = 'uid %d' % stat[ST_UID] print(C_( '%(dbfile)s owned by %(owner)s (must be owned by %(user)s'), end=' ') state.ERRORS += 1 if state.FIX: print(C_('(fixing)')) uid = pwd.getpwnam(user)[2] gid = grp.getgrnam(mm_cfg.MAILMAN_GROUP)[2] os.chown(dbfile, uid, gid) else: print() if stat and (stat[ST_MODE] & targetmode) != targetmode: state.ERRORS += 1 octmode = oct(stat[ST_MODE]) print(C_('%(dbfile)s permissions must be 0664 (got %(octmode)s)'), end=' ') if state.FIX: print(C_('(fixing)')) os.chmod(dbfile, stat[ST_MODE] | targetmode) else: print()
def usage(code, msg=''): if code: fd = sys.stderr else: fd = sys.stdout print(C_(__doc__.replace('%', '%%')), file=fd) if msg: print(msg, file=fd) sys.exit(code)
def usage(code, msg=''): if code: fd = sys.stderr else: fd = sys.stdout print >> fd, C_(__doc__.replace('%', '%%')) if msg: print >> fd, msg sys.exit(code)
def update_archive(self, archive): self.archive = archive self.message(C_("Updating index files for archive [%(archive)s]")) arcdir = os.path.join(self.basedir, archive) self.__set_parameters(archive) for hdr in ('Date', 'Subject', 'Author'): self._update_simple_index(hdr, archive, arcdir) self._update_thread_index(archive, arcdir)
def convert(mlist): for attr in ('msg_header', 'msg_footer', 'digest_header', 'digest_footer', 'autoresponse_postings_text', 'autoresponse_admin_text', 'autoresponse_request_text'): s = getattr(mlist, attr) t = Utils.to_dollar(s) setattr(mlist, attr, t) mlist.use_dollar_strings = 1 print(C_('Saving list')) mlist.Save()
def reset_pw(mlist, *args): try: opts, args = getopt.getopt(args, 'v', ['verbose']) except getopt.error as 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(C_('Changing passwords for list: %(listname)s')) for member in mlist.getMembers(): randompw = Utils.MakeRandomPassword() mlist.setMemberPassword(member, randompw) if verbose: print(C_('New password for member %(member)40s: %(randompw)s')) mlist.Save()
def _update_thread_index(self, archive, arcdir): self.message(C_(" Thread")) self._open_index_file_as_stdout(arcdir, "thread") self.type = 'Thread' self.write_index_header() # To handle the prev./next in thread pointers, we need to # track articles 5 at a time. # Get the first 5 articles L = [None] * 5 i = 2 msgid = self.database.first(self.archive, 'thread') while msgid is not None and i < 5: L[i] = self.database.getArticle(self.archive, msgid) i = i + 1 msgid = self.database.next(self.archive, 'thread') while L[2] is not None: article = L[2] artkey = None if article is not None: artkey = article.threadKey if artkey is not None: self.write_threadindex_entry(article, artkey.count('-') - 1) if (archive, article.msgid) in self.database.changed: a1 = L[1] a3 = L[3] self.update_article(arcdir, article, a1, a3) if a3 is not None: self.database.changed[(archive, a3.msgid)] = None if a1 is not None: key = archive, a1.msgid if key not in self.database.changed: self.update_article(arcdir, a1, L[0], L[2]) else: del self.database.changed[key] if L[0]: L[0].finished_update_article() L = L[1:] # Rotate the list if msgid is None: L.append(msgid) else: L.append(self.database.getArticle(self.archive, msgid)) msgid = self.database.next(self.archive, 'thread') self.write_index_footer() self._restore_stdout()
def dump(self, listnames, password_scheme): print >> self._fp, '<?xml version="1.0" encoding="UTF-8"?>' self._push_element( 'mailman', **{ 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:noNamespaceSchemaLocation': 'ssi-1.0.xsd', }) for listname in sorted(listnames): try: mlist = MailList(listname, lock=False) except Errors.MMUnknownListError: print >> sys.stderr, C_('No such list: %(listname)s') continue self._dump_list(mlist, password_scheme) self._pop_element('mailman')
def parseargs(): parser = optparse.OptionParser(version=mm_cfg.VERSION, usage=C_("""\ %%prog [options] Export the configuration and members of a mailing list in XML format.""")) parser.add_option('-o', '--outputfile', metavar='FILENAME', default=None, type='string', help=C_("""\ Output XML to FILENAME. If not given, or if FILENAME is '-', standard out is used.""")) parser.add_option('-p', '--password-scheme', default='none', type='string', help=C_("""\ Specify the RFC 2307 style hashing scheme for passwords included in the output. Use -P to get a list of supported schemes, which are case-insensitive.""")) parser.add_option('-P', '--list-hash-schemes', default=False, action='store_true', help=C_("""\ List the supported password hashing schemes and exit. The scheme labels are case-insensitive.""")) parser.add_option('-l', '--listname', default=[], action='append', type='string', metavar='LISTNAME', dest='listnames', help=C_("""\ The list to include in the output. If not given, then all mailing lists are included in the XML output. Multiple -l flags may be given.""")) opts, args = parser.parse_args() if args: parser.print_help() parser.error(C_('Unexpected arguments')) if opts.list_hash_schemes: for label in SCHEMES: print label.upper() sys.exit(0) if opts.password_scheme.lower() not in SCHEMES: parser.error(C_('Invalid password scheme')) return parser, opts, args
def remove(mlist, cgi=False): listname = mlist.internal_name() fieldsz = len(listname) + len('-unsubscribe') if cgi: # If a list is being removed via the CGI, the best we can do is send # an email message to mailman-owner requesting that the appropriate # aliases be deleted. sfp = StringIO() print(_("""\ The mailing list `%(listname)s' has been removed via the through-the-web interface. In order to complete the de-activation of this mailing list, the appropriate /etc/aliases (or equivalent) file must be updated. The program `newaliases' may also have to be run. Here are the entries in the /etc/aliases file that should be removed: """), file=sfp) outfp = sfp else: print( C_(""" To finish removing your mailing list, you must edit your /etc/aliases (or equivalent) file by removing the following lines, and possibly running the `newaliases' program: ## %(listname)s mailing list""")) outfp = sys.stdout # Common path for k, v in makealiases(listname): print(k + ':', ((fieldsz - len(k)) * ' '), v, file=outfp) # If we're using the command line interface, we're done. For ttw, we need # to actually send the message to mailman-owner now. if not cgi: print(file=outfp) return siteowner = Utils.get_site_email(extra='owner') # Should this be sent in the site list's preferred language? msg = Message.UserNotification( siteowner, siteowner, _('Mailing list removal request for list %(listname)s'), sfp.getvalue(), mm_cfg.DEFAULT_SERVER_LANGUAGE) msg['Date'] = email.utils.formatdate(localtime=1) outq = get_switchboard(mm_cfg.OUTQUEUE_DIR) outq.enqueue(msg, recips=[siteowner], nodecorate=1)
def close(self): "Close an archive, save its state, and update any changed archives." self.update_dirty_archives() self.update_TOC = 0 self.write_TOC() # Save the collective state self.message( C_('Pickling archive state into ') + os.path.join(self.basedir, 'pipermail.pck')) self.database.close() del self.database omask = os.umask(0o07) try: f = open(os.path.join(self.basedir, 'pipermail.pck'), 'wb') finally: os.umask(omask) pickle.dump(self.getstate(), f) f.close()
def processUnixMailbox(self, input, start=None, end=None): mbox = ArchiverMailbox(input, self.maillist) if start is None: start = 0 counter = 0 if start: mbox.skipping(True) while counter < start: try: m = next(mbox) except Errors.DiscardMessage: continue if m is None: return counter += 1 if start: mbox.skipping(False) while 1: try: pos = input.tell() m = next(mbox) except Errors.DiscardMessage: continue except Exception: syslog('error', 'uncaught archiver exception at filepos: %s', pos) raise if m is None: break if m == '': # It was an unparseable message continue msgid = m.get('message-id', 'n/a') self.message(C_('#%(counter)05d %(msgid)s')) a = self._makeArticle(m, self.sequence) self.sequence += 1 self.add_article(a) if end is not None and counter >= end: break counter += 1
opts, args = getopt.getopt(args, 'u:v', ['from-is-list-value=', 'verbose']) except getopt.error, msg: usage(1, msg) verbose = 0 f_value = 0 for opt, arg in opts: if opt in ('-u', '--from-is-list-value'): f_value = int(arg) elif opt in ('-v', '--verbose'): verbose = 1 # Make sure list is locked. if not mlist.Locked(): if verbose: print C_('Locking list') mlist.Lock() if verbose: old_f_value = mlist.from_is_list print C_('Setting from_is_list from: %(old_f_value)s to: %(f_value)s') mlist.from_is_list = f_value print C_('Saving list') mlist.Save() mlist.Unlock() if __name__ == '__main__': usage(0)
# 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. """Convert a list's interpolation strings from %-strings to $-strings. This script is intended to be run as a bin/withlist script, i.e. % bin/withlist -l -r convert <mylist> """ import paths from Mailman import Utils from Mailman.i18n import C_ def convert(mlist): for attr in ('msg_header', 'msg_footer', 'digest_header', 'digest_footer', 'autoresponse_postings_text', 'autoresponse_admin_text', 'autoresponse_request_text'): s = getattr(mlist, attr) t = Utils.to_dollar(s) setattr(mlist, attr, t) mlist.use_dollar_strings = 1 print(C_('Saving list')) mlist.Save() if __name__ == '__main__': print(C_(__doc__.replace('%', '%%')))
def usage(code, msg=''): print C_(__doc__.replace('%', '%%')) if msg: print msg sys.exit(code)
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 # Make sure list is locked. if not mlist.Locked(): if verbose: print C_('Locking list') mlist.Lock() if urlhost: web_page_url = mm_cfg.DEFAULT_URL_PATTERN % urlhost mailhost = mm_cfg.VIRTUAL_HOSTS.get(urlhost.lower(), urlhost) else: web_page_url = mm_cfg.DEFAULT_URL_PATTERN % mm_cfg.DEFAULT_URL_HOST mailhost = mm_cfg.DEFAULT_EMAIL_HOST if verbose: print C_('Setting web_page_url to: %(web_page_url)s') mlist.web_page_url = web_page_url if verbose: print C_('Setting host_name to: %(mailhost)s') mlist.host_name = mailhost print C_('Saving list')
os.chmod(file, stat[ST_MODE] | targetmode) else: print # Make sure the corresponding .db files are owned by the Mailman user. # We don't need to check the group ownership of the file, since # check_perms checks this itself. dbfile = file + '.db' stat = None try: stat = os.stat(dbfile) except OSError, e: if e.errno <> errno.ENOENT: raise continue if state.VERBOSE: print C_('checking ownership of %(dbfile)s') user = mm_cfg.MAILMAN_USER ownerok = stat[ST_UID] == pwd.getpwnam(user)[2] if not ownerok: try: owner = pwd.getpwuid(stat[ST_UID])[0] except KeyError: owner = 'uid %d' % stat[ST_UID] print C_( '%(dbfile)s owned by %(owner)s (must be owned by %(user)s'), state.ERRORS += 1 if state.FIX: print C_('(fixing)') uid = pwd.getpwnam(user)[2] gid = grp.getgrnam(mm_cfg.MAILMAN_GROUP)[2] os.chown(dbfile, uid, gid)
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 C_('Changing passwords for list: %(listname)s') for member in mlist.getMembers(): randompw = Utils.MakeRandomPassword() mlist.setMemberPassword(member, randompw) if verbose: print C_('New password for member %(member)40s: %(randompw)s') mlist.Save() if __name__ == '__main__': usage(0)