Esempio n. 1
0
def remove_list(fqdn_listname, mailing_list=None):
    """Remove the list and all associated artifacts and subscriptions."""
    removeables = []
    # mailing_list will be None when only residual archives are being removed.
    if mailing_list is not None:
        # Remove all subscriptions, regardless of role.
        for member in mailing_list.subscribers.members:
            member.unsubscribe()
        # Delete the mailing list from the database.
        getUtility(IListManager).delete(mailing_list)
        # Do the MTA-specific list deletion tasks
        call_name(config.mta.incoming).create(mailing_list)
        # Remove the list directory.
        removeables.append(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
    # Remove any stale locks associated with the list.
    for filename in os.listdir(config.LOCK_DIR):
        fn_listname = filename.split('.')[0]
        if fn_listname == fqdn_listname:
            removeables.append(os.path.join(config.LOCK_DIR, filename))
    # Now that we know what files and directories to delete, delete them.
    for target in removeables:
        if not os.path.exists(target):
            pass
        elif os.path.islink(target):
            os.unlink(target)
        elif os.path.isdir(target):
            shutil.rmtree(target)
        elif os.path.isfile(target):
            os.unlink(target)
        else:
            log.error('Could not delete list artifact: %s', target)
Esempio n. 2
0
def remove_list(mlist):
    """Remove the list and all associated artifacts and subscriptions."""
    fqdn_listname = mlist.fqdn_listname
    removeables = []
    # Delete the mailing list from the database.
    getUtility(IListManager).delete(mlist)
    # Do the MTA-specific list deletion tasks
    call_name(config.mta.incoming).delete(mlist)
    # Remove the list directory.
    removeables.append(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
    # Remove any stale locks associated with the list.
    for filename in os.listdir(config.LOCK_DIR):
        fn_listname, dot, rest = filename.partition('.')
        if fn_listname == fqdn_listname:
            removeables.append(os.path.join(config.LOCK_DIR, filename))
    # Now that we know what files and directories to delete, delete them.
    for target in removeables:
        if not os.path.exists(target):
            pass
        elif os.path.islink(target):
            os.unlink(target)
        elif os.path.isdir(target):
            shutil.rmtree(target)
        elif os.path.isfile(target):
            os.unlink(target)
        else:
            log.error('Could not delete list artifact: %s', target)
Esempio n. 3
0
def initialize_3():
    """Third initialization step.

    * Post-hook
    """
    # Run the post-hook if there is one.
    config = mailman.config.config
    if config.mailman.post_hook:
        call_name(config.mailman.post_hook)
Esempio n. 4
0
def remove_list(mlist):
    """Remove the list and all associated artifacts and subscriptions."""
    # Remove the list's data directory, if it exists.
    with suppress(FileNotFoundError):
        shutil.rmtree(mlist.data_path)
    # Delete the mailing list from the database.
    getUtility(IListManager).delete(mlist)
    # Do the MTA-specific list deletion tasks
    call_name(config.mta.incoming).delete(mlist)
Esempio n. 5
0
def remove_list(mlist):
    """Remove the list and all associated artifacts and subscriptions."""
    # Remove the list's data directory, if it exists.
    with suppress(FileNotFoundError):
        shutil.rmtree(mlist.data_path)
    # Delete the mailing list from the database.
    getUtility(IListManager).delete(mlist)
    # Do the MTA-specific list deletion tasks
    call_name(config.mta.incoming).delete(mlist)
Esempio n. 6
0
def initialize_3():
    """Third initialization step.

    * Post-hook
    """
    # Run the post-hook if there is one.
    config = mailman.config.config
    if config.mailman.post_hook:
        call_name(config.mailman.post_hook)
Esempio n. 7
0
def remove_list(mlist):
    """Remove the list and all associated artifacts and subscriptions."""
    fqdn_listname = mlist.fqdn_listname
    # Delete the mailing list from the database.
    getUtility(IListManager).delete(mlist)
    # Do the MTA-specific list deletion tasks
    call_name(config.mta.incoming).delete(mlist)
    # Remove the list directory, if it exists.
    try:
        shutil.rmtree(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
    except OSError as error:
        if error.errno != errno.ENOENT:
            raise
Esempio n. 8
0
def remove_list(mlist):
    """Remove the list and all associated artifacts and subscriptions."""
    fqdn_listname = mlist.fqdn_listname
    # Delete the mailing list from the database.
    getUtility(IListManager).delete(mlist)
    # Do the MTA-specific list deletion tasks
    call_name(config.mta.incoming).delete(mlist)
    # Remove the list directory, if it exists.
    try:
        shutil.rmtree(os.path.join(config.LIST_DATA_DIR, fqdn_listname))
    except OSError as error:
        if error.errno != errno.ENOENT:
            raise
Esempio n. 9
0
def start(ctx, force, generate_alias_file, run_as_user, quiet):
    # Although there's a potential race condition here, it's a better user
    # experience for the parent process to refuse to start twice, rather than
    # having it try to start the master, which will error exit.
    status, lock = master_state()
    if status is WatcherState.conflict:
        ctx.fail(_('GNU Mailman is already running'))
    elif status in (WatcherState.stale_lock, WatcherState.host_mismatch):
        if not force:
            ctx.fail(
                _('A previous run of GNU Mailman did not exit '
                  'cleanly ({}).  Try using --force'.format(status.name)))
    # Daemon process startup according to Stevens, Advanced Programming in the
    # UNIX Environment, Chapter 13.
    pid = os.fork()
    if pid:
        # parent
        if not quiet:
            print(_("Starting Mailman's master runner"))
        if generate_alias_file:
            if not quiet:
                print(_("Generating MTA alias maps"))
            call_name(config.mta.incoming).regenerate()
        return
    # child: Create a new session and become the session leader, but since we
    # won't be opening any terminal devices, don't do the ultra-paranoid
    # suggestion of doing a second fork after the setsid() call.
    os.setsid()
    # Instead of cd'ing to root, cd to the Mailman runtime directory.  However,
    # before we do that, set an environment variable used by the subprocesses
    # to calculate their path to the $VAR_DIR.
    os.environ['MAILMAN_VAR_DIR'] = config.VAR_DIR
    os.chdir(config.VAR_DIR)
    # Exec the master watcher.
    execl_args = [
        sys.executable,
        sys.executable,
        os.path.join(config.BIN_DIR, 'master'),
    ]
    if force:
        execl_args.append('--force')
    # Always pass the configuration file path to the master process, so there's
    # no confusion about which one is being used.
    execl_args.extend(['-C', config.filename])
    qlog.debug('starting: %s', execl_args)
    os.execl(*execl_args)
    # We should never get here.
    raise RuntimeError('os.execl() failed')
Esempio n. 10
0
 def archivers(self):
     """Iterate over all the enabled archivers."""
     for section in self._config.getByCategory("archiver", []):
         if not as_boolean(section.enable):
             continue
         class_path = section["class"]
         yield call_name(class_path)
Esempio n. 11
0
 def confirm(self, store, token, expunge=True):
     # Token can come in as a unicode, but it's stored in the database as
     # bytes.  They must be ascii.
     pendings = store.query(Pended).filter_by(token=str(token))
     if pendings.count() == 0:
         return None
     assert pendings.count() == 1, (
         'Unexpected token count: {0}'.format(pendings.count()))
     pending = pendings[0]
     pendable = UnpendedPendable()
     # Find all PendedKeyValue entries that are associated with the pending
     # object's ID.  Watch out for type conversions.
     entries = store.query(PendedKeyValue).filter(
         PendedKeyValue.pended_id == pending.id)
     for keyvalue in entries:
         if keyvalue.value is not None and '\1' in keyvalue.value:
             type_name, value = keyvalue.value.split('\1', 1)
             pendable[keyvalue.key] = call_name(type_name, value)
         else:
             pendable[keyvalue.key] = keyvalue.value
         if expunge:
             store.delete(keyvalue)
     if expunge:
         store.delete(pending)
     return pendable
Esempio n. 12
0
 def create():
     """See `IDatabaseFactory`."""
     database_class_name = config.database['class']
     database = call_name(database_class_name)
     verifyObject(IDatabase, database)
     adapted_database = getAdapter(
         database, ITemporaryDatabase, database.TAG)
     return adapted_database
Esempio n. 13
0
def create_list(fqdn_listname, owners=None, style_name=None):
    """Create the named list and apply styles.

    The mailing may not exist yet, but the domain specified in `fqdn_listname`
    must exist.

    :param fqdn_listname: The fully qualified name for the new mailing list.
    :type fqdn_listname: string
    :param owners: The mailing list owners.
    :type owners: list of string email addresses
    :param style_name: The name of the style to apply to the newly created
        list.  If not given, the default is taken from the configuration file.
    :type style_name: string
    :return: The new mailing list.
    :rtype: `IMailingList`
    :raises BadDomainSpecificationError: when the hostname part of
        `fqdn_listname` does not exist.
    :raises ListAlreadyExistsError: when the mailing list already exists.
    :raises InvalidEmailAddressError: when the fqdn email address is invalid.
    """
    if owners is None:
        owners = []
    # This raises InvalidEmailAddressError if the address is not a valid
    # posting address.  Let these percolate up.
    getUtility(IEmailValidator).validate(fqdn_listname)
    listname, domain = fqdn_listname.split('@', 1)
    if domain not in getUtility(IDomainManager):
        raise BadDomainSpecificationError(domain)
    mlist = getUtility(IListManager).create(fqdn_listname)
    style = getUtility(IStyleManager).get(
        config.styles.default if style_name is None else style_name)
    if style is not None:
        style.apply(mlist)
    # Coordinate with the MTA, as defined in the configuration file.
    call_name(config.mta.incoming).create(mlist)
    # Create any owners that don't yet exist, and subscribe all addresses as
    # owners of the mailing list.
    user_manager = getUtility(IUserManager)
    for owner_address in owners:
        address = user_manager.get_address(owner_address)
        if address is None:
            user = user_manager.create_user(owner_address)
            address = list(user.addresses)[0]
        mlist.subscribe(address, MemberRole.owner)
    return mlist
Esempio n. 14
0
def create_list(fqdn_listname, owners=None, style_name=None):
    """Create the named list and apply styles.

    The mailing may not exist yet, but the domain specified in `fqdn_listname`
    must exist.

    :param fqdn_listname: The fully qualified name for the new mailing list.
    :type fqdn_listname: string
    :param owners: The mailing list owners.
    :type owners: list of string email addresses
    :param style_name: The name of the style to apply to the newly created
        list.  If not given, the default is taken from the configuration file.
    :type style_name: string
    :return: The new mailing list.
    :rtype: `IMailingList`
    :raises BadDomainSpecificationError: when the hostname part of
        `fqdn_listname` does not exist.
    :raises ListAlreadyExistsError: when the mailing list already exists.
    :raises InvalidEmailAddressError: when the fqdn email address is invalid.
    """
    if owners is None:
        owners = []
    # This raises InvalidEmailAddressError if the address is not a valid
    # posting address.  Let these percolate up.
    getUtility(IEmailValidator).validate(fqdn_listname)
    listname, domain = fqdn_listname.split('@', 1)
    if domain not in getUtility(IDomainManager):
        raise BadDomainSpecificationError(domain)
    mlist = getUtility(IListManager).create(fqdn_listname)
    style = getUtility(IStyleManager).get(
        config.styles.default if style_name is None else style_name)
    if style is not None:
        style.apply(mlist)
    # Coordinate with the MTA, as defined in the configuration file.
    call_name(config.mta.incoming).create(mlist)
    # Create any owners that don't yet exist, and subscribe all addresses as
    # owners of the mailing list.
    user_manager = getUtility(IUserManager)
    for owner_address in owners:
        address = user_manager.get_address(owner_address)
        if address is None:
            user = user_manager.create_user(owner_address)
            address = list(user.addresses)[0]
        mlist.subscribe(address, MemberRole.owner)
    return mlist
Esempio n. 15
0
 def archivers(self):
     """Iterate over all the archivers."""
     for section in self._config.getByCategory('archiver', []):
         class_path = section['class'].strip()
         if len(class_path) == 0:
             continue
         archiver = call_name(class_path)
         archiver.is_enabled = as_boolean(section.enable)
         yield archiver
Esempio n. 16
0
 def archivers(self):
     """Iterate over all the archivers."""
     for section in self._config.getByCategory('archiver', []):
         class_path = section['class'].strip()
         if len(class_path) == 0:
             continue
         archiver = call_name(class_path)
         archiver.is_enabled = as_boolean(section.enable)
         yield archiver
Esempio n. 17
0
 def create():
     """See `IDatabaseFactory`."""
     database_class = config.database['class']
     database = call_name(database_class)
     verifyObject(IDatabase, database)
     database.initialize()
     database.load_migrations()
     database.commit()
     return database
Esempio n. 18
0
 def create():
     """See `IDatabaseFactory`."""
     with Lock(os.path.join(config.LOCK_DIR, 'dbcreate.lck')):
         database_class = config.database['class']
         database = call_name(database_class)
         verifyObject(IDatabase, database)
         database.initialize()
         SchemaManager(database).setup_database()
         database.commit()
         return database
Esempio n. 19
0
 def create():
     """See `IDatabaseFactory`."""
     with Lock(os.path.join(config.LOCK_DIR, 'dbcreate.lck')):
         database_class = config.database['class']
         database = call_name(database_class)
         verifyObject(IDatabase, database)
         database.initialize()
         SchemaManager(database).setup_database()
         database.commit()
         return database
Esempio n. 20
0
 def process(self, args):
     """See `ICLISubCommand`."""
     if args.format is not None and args.simple:
         self.parser.error(_('Cannot use both -s and -f'))
         # Does not return.
     output = None
     if args.output == '-':
         output = sys.stdout
     elif args.output is None:
         output = None
     else:
         output = args.output
     if args.simple:
         Dummy().regenerate(output)
     else:
         format_arg = (config.mta.incoming
                       if args.format is None
                       else args.format)
         # Call the MTA-specific regeneration method.
         call_name(format_arg).regenerate(output)
Esempio n. 21
0
 def create():
     """See `IDatabaseFactory`."""
     database_class = config.database['class']
     database = call_name(database_class)
     verifyObject(IDatabase, database)
     database.initialize()
     Model.metadata.create_all(database.engine)
     database.commit()
     # Make _reset() a bound method of the database instance.
     database._reset = types.MethodType(_reset, database)
     return database
Esempio n. 22
0
 def create():
     """See `IDatabaseFactory`."""
     database_class = config.database['class']
     database = call_name(database_class)
     verifyObject(IDatabase, database)
     database.initialize()
     database.load_migrations()
     database.commit()
     # Make _reset() a bound method of the database instance.
     database._reset = types.MethodType(_reset, database)
     return database
Esempio n. 23
0
def initialize_2(debug=False, propagate_logs=None):
    """Second initialization step.

    * Logging
    * Pre-hook
    * Rules
    * Chains
    * Pipelines
    * Commands

    :param debug: Should the database layer be put in debug mode?
    :type debug: boolean
    :param propagate_logs: Should the log output propagate to stderr?
    :type propagate_logs: boolean or None
    """
    # Create the queue and log directories if they don't already exist.
    mailman.core.logging.initialize(propagate_logs)
    # Run the pre-hook if there is one.
    config = mailman.config.config
    if config.mailman.pre_hook:
        call_name(config.mailman.pre_hook)
    # Instantiate the database class, ensure that it's of the right type, and
    # initialize it.  Then stash the object on our configuration object.
    database_class = config.database['class']
    database = call_name(database_class)
    verifyObject(IDatabase, database)
    database.initialize(debug)
    config.db = database
    # Initialize the rules and chains.  Do the imports here so as to avoid
    # circular imports.
    from mailman.app.commands import initialize as initialize_commands
    from mailman.app.events import initialize as initialize_events
    from mailman.core.chains import initialize as initialize_chains
    from mailman.core.pipelines import initialize as initialize_pipelines
    from mailman.core.rules import initialize as initialize_rules
    # Order here is somewhat important.
    initialize_rules()
    initialize_chains()
    initialize_pipelines()
    initialize_commands()
    initialize_events()
Esempio n. 24
0
 def populate(self):
     self._styles.clear()
     # Avoid circular imports.
     from mailman.config import config
     # Install all the styles described by the configuration files.
     for section in config.style_configs:
         class_path = section['class']
         style = call_name(class_path)
         assert section.name.startswith('style'), (
             'Bad style section name: %s' % section.name)
         style.name = section.name[6:]
         style.priority = int(section.priority)
         self.register(style)
Esempio n. 25
0
def shell(ctx, interactive, run, listspec, run_args):
    global m, r
    banner = DEFAULT_BANNER
    # Interactive is the default unless --run was given.
    interactive = (run is None) if interactive is None else interactive
    # List name cannot be a regular expression if --run is not given.
    if listspec and listspec.startswith('^') and not run:
        ctx.fail(_('Regular expression requires --run'))
    # Handle --run.
    list_manager = getUtility(IListManager)
    if run:
        # When the module and the callable have the same name, a shorthand
        # without the dot is allowed.
        dotted_name = (run if '.' in run else '{0}.{0}'.format(run))
        if listspec is None:
            r = call_name(dotted_name, *run_args)
        elif listspec.startswith('^'):
            r = {}
            cre = re.compile(listspec, re.IGNORECASE)
            for mlist in list_manager.mailing_lists:
                if cre.match(mlist.fqdn_listname) or cre.match(mlist.list_id):
                    results = call_name(dotted_name, mlist, *run_args)
                    r[mlist.list_id] = results
        else:
            m = list_manager.get(listspec)
            if m is None:
                ctx.fail(_('No such list: $listspec'))
            r = call_name(dotted_name, m, *run_args)
    else:
        # Not --run.
        if listspec is not None:
            m = list_manager.get(listspec)
            if m is None:
                ctx.fail(_('No such list: $listspec'))
            banner = _("The variable 'm' is the $listspec mailing list")
    # All other processing is finished; maybe go into interactive mode.
    if interactive:
        do_interactive(ctx, banner)
Esempio n. 26
0
def initialize_2(debug=False, propagate_logs=None, testing=False):
    """Second initialization step.

    * Database
    * Logging
    * Pre-hook
    * Rules
    * Chains
    * Pipelines
    * Commands

    :param debug: Should the database layer be put in debug mode?
    :type debug: boolean
    :param propagate_logs: Should the log output propagate to stderr?
    :type propagate_logs: boolean or None
    """
    # Create the queue and log directories if they don't already exist.
    mailman.core.logging.initialize(propagate_logs)
    # Run the pre-hook if there is one.
    config = mailman.config.config
    if config.mailman.pre_hook:
        call_name(config.mailman.pre_hook)
    # Instantiate the database class, ensure that it's of the right type, and
    # initialize it.  Then stash the object on our configuration object.
    utility_name = ('testing' if testing else 'production')
    config.db = getUtility(IDatabaseFactory, utility_name).create()
    # Initialize the rules and chains.  Do the imports here so as to avoid
    # circular imports.
    from mailman.app.commands import initialize as initialize_commands
    from mailman.core.chains import initialize as initialize_chains
    from mailman.core.pipelines import initialize as initialize_pipelines
    from mailman.core.rules import initialize as initialize_rules
    # Order here is somewhat important.
    initialize_rules()
    initialize_chains()
    initialize_pipelines()
    initialize_commands()
Esempio n. 27
0
 def create():
     """See `IDatabaseFactory`."""
     database_class = config.database['class']
     database = call_name(database_class)
     verifyObject(IDatabase, database)
     database.initialize()
     # Remove existing tables (PostgreSQL will keep them across runs)
     metadata = MetaData(bind=database.engine)
     metadata.reflect()
     metadata.drop_all()
     database.commit()
     # Now create the current model without Alembic upgrades.
     Model.metadata.create_all(database.engine)
     database.commit()
     # Make _reset() a bound method of the database instance.
     database._reset = types.MethodType(_reset, database)
     return database
Esempio n. 28
0
 def create():
     """See `IDatabaseFactory`."""
     database_class = config.database['class']
     database = call_name(database_class)
     verifyObject(IDatabase, database)
     database.initialize()
     # Remove existing tables (PostgreSQL will keep them across runs)
     metadata = MetaData(bind=database.engine)
     metadata.reflect()
     metadata.drop_all()
     database.commit()
     # Now create the current model without Alembic upgrades.
     Model.metadata.create_all(database.engine)
     database.commit()
     # Make _reset() a bound method of the database instance.
     database._reset = types.MethodType(_reset, database)
     return database
Esempio n. 29
0
def initialize():
    """Initialize all enabled plugins."""
    for name, plugin_config in config.plugin_configs:
        class_path = plugin_config['class'].strip()
        if not as_boolean(plugin_config['enabled']) or len(class_path) == 0:
            log.info(
                'Plugin not enabled, or empty class path: {}'.format(name))
            continue
        if name in config.plugins:
            log.error('Duplicate plugin name: {}'.format(name))
            continue
        plugin = call_name(class_path)
        try:
            verifyObject(IPlugin, plugin)
        except DoesNotImplement:
            log.error('Plugin class does not implement IPlugin: {}'.format(
                class_path))
            continue
        plugin.name = name
        config.plugins[name] = plugin
Esempio n. 30
0
 def process(self, args):
     """See `ICLISubCommand`."""
     # Call the MTA-specific regeneration method.
     call_name(config.mta.incoming).regenerate(args.directory)
Esempio n. 31
0
 def process(self, args):
     """See `ICLISubCommand`."""
     global m, r
     banner = DEFAULT_BANNER
     # Detailed help wanted?
     if args.details:
         self._details()
         return
     # Interactive is the default unless --run was given.
     if args.interactive is None:
         interactive = (args.run is None)
     else:
         interactive = args.interactive
     # List name cannot be a regular expression if --run is not given.
     if args.listname and args.listname.startswith('^') and not args.run:
         self.parser.error(_('Regular expression requires --run'))
         return
     # Handle --run.
     list_manager = getUtility(IListManager)
     if args.run:
         # When the module and the callable have the same name, a shorthand
         # without the dot is allowed.
         dotted_name = (args.run
                        if '.' in args.run else '{0}.{0}'.format(args.run))
         if args.listname is None:
             self.parser.error(_('--run requires a mailing list name'))
             return
         elif args.listname.startswith('^'):
             r = {}
             cre = re.compile(args.listname, re.IGNORECASE)
             for mailing_list in list_manager.mailing_lists:
                 if cre.match(mailing_list.fqdn_listname):
                     results = call_name(dotted_name, mailing_list)
                     r[mailing_list.fqdn_listname] = results
         else:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             r = call_name(dotted_name, m)
     else:
         # Not --run.
         if args.listname is not None:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             banner = _(
                 "The variable 'm' is the $fqdn_listname mailing list")
     # All other processing is finished; maybe go into interactive mode.
     if interactive:
         overrides = dict(m=m,
                          commit=config.db.commit,
                          abort=config.db.abort,
                          config=config,
                          getUtility=getUtility)
         # Bootstrap some useful names into the namespace, mostly to make
         # the component architecture and interfaces easily available.
         for module_name in sys.modules:
             if not module_name.startswith('mailman.interfaces.'):
                 continue
             module = sys.modules[module_name]
             for name in module.__all__:
                 overrides[name] = getattr(module, name)
         banner = config.shell.banner + '\n' + (banner if isinstance(
             banner, str) else '')
         try:
             use_ipython = as_boolean(config.shell.use_ipython)
         except ValueError:
             if config.shell.use_ipython == 'debug':
                 use_ipython = True
                 debug = True
             else:
                 raise
         else:
             debug = False
         if use_ipython:
             self._start_ipython(overrides, banner, debug)
         else:
             self._start_python(overrides, banner)
Esempio n. 32
0
def create_list(fqdn_listname, owners=None, style_name=None):
    """Create the named list and apply styles.

    The mailing may not exist yet, but the domain specified in `fqdn_listname`
    must exist.

    :param fqdn_listname: The fully qualified name for the new mailing list.
    :type fqdn_listname: string
    :param owners: The mailing list owners.
    :type owners: list of string email addresses
    :param style_name: The name of the style to apply to the newly created
        list.  If not given, the default is taken from the configuration file.
    :type style_name: string
    :return: The new mailing list.
    :rtype: `IMailingList`
    :raises BadDomainSpecificationError: when the hostname part of
        `fqdn_listname` does not exist.
    :raises ListAlreadyExistsError: when the mailing list already exists.
    :raises InvalidEmailAddressError: when the fqdn email address is invalid.
    :raises InvalidListNameError: when the fqdn email address is valid but the
        listname contains disallowed characters.
    """
    if owners is None:
        owners = []
    # This raises InvalidEmailAddressError if the address is not a valid
    # posting address.  Let these percolate up.
    getUtility(IEmailValidator).validate(fqdn_listname)
    listname, domain = fqdn_listname.split('@', 1)
    # We need to be fussier than just validating the posting address.  Various
    # legal local-part characters will cause problems in list names.
    # First we check our maximally allowed set.
    if len(_listname_chars.sub('', listname)) > 0:
        raise InvalidListNameError(listname)
    # Then if another set is configured, check that.
    if config.mailman.listname_chars:
        try:
            cre = re.compile(config.mailman.listname_chars, re.IGNORECASE)
        except re.error as error:
            log.error(
                'Bad config.mailman.listname_chars setting: %s: %s',
                config.mailman.listname_chars,
                getattr(error, 'msg', str(error))
                )
        else:
            if len(cre.sub('', listname)) > 0:
                raise InvalidListNameError(listname)
    if domain not in getUtility(IDomainManager):
        raise BadDomainSpecificationError(domain)
    mlist = getUtility(IListManager).create(fqdn_listname)
    style = getUtility(IStyleManager).get(
        config.styles.default if style_name is None else style_name)
    if style is not None:
        style.apply(mlist)
    # Coordinate with the MTA, as defined in the configuration file.
    call_name(config.mta.incoming).create(mlist)
    # Create any owners that don't yet exist, and subscribe all addresses as
    # owners of the mailing list.
    user_manager = getUtility(IUserManager)
    for owner_address in owners:
        address = user_manager.get_address(owner_address)
        if address is None:
            user = user_manager.create_user(owner_address)
            address = list(user.addresses)[0]
        mlist.subscribe(address, MemberRole.owner)
    return mlist
Esempio n. 33
0
 def process(self, args):
     """See `ICLISubCommand`."""
     global m, r
     banner = DEFAULT_BANNER
     # Detailed help wanted?
     if args.details:
         self._details()
         return
     # Interactive is the default unless --run was given.
     if args.interactive is None:
         interactive = (args.run is None)
     else:
         interactive = args.interactive
     # List name cannot be a regular expression if --run is not given.
     if args.listname and args.listname.startswith('^') and not args.run:
         self.parser.error(_('Regular expression requires --run'))
         return
     # Handle --run.
     list_manager = getUtility(IListManager)
     if args.run:
         # When the module and the callable have the same name, a shorthand
         # without the dot is allowed.
         dotted_name = (args.run if '.' in args.run
                        else '{0}.{0}'.format(args.run))
         if args.listname is None:
             self.parser.error(_('--run requires a mailing list name'))
             return
         elif args.listname.startswith('^'):
             r = {}
             cre = re.compile(args.listname, re.IGNORECASE)
             for mailing_list in list_manager.mailing_lists:
                 if cre.match(mailing_list.fqdn_listname):
                     results = call_name(dotted_name, mailing_list)
                     r[mailing_list.fqdn_listname] = results
         else:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             r = call_name(dotted_name, m)
     else:
         # Not --run.
         if args.listname is not None:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             banner = _(
                 "The variable 'm' is the $fqdn_listname mailing list")
     # All other processing is finished; maybe go into interactive mode.
     if interactive:
         overrides = dict(
             m=m,
             commit=config.db.commit,
             abort=config.db.abort,
             config=config,
             getUtility=getUtility
             )
         # Bootstrap some useful names into the namespace, mostly to make
         # the component architecture and interfaces easily available.
         for module_name in sys.modules:
             if not module_name.startswith('mailman.interfaces.'):
                 continue
             module = sys.modules[module_name]
             for name in module.__all__:
                 overrides[name] = getattr(module, name)
         banner = config.shell.banner + '\n' + (
             banner if isinstance(banner, str) else '')
         try:
             use_ipython = as_boolean(config.shell.use_ipython)
         except ValueError:
             if config.shell.use_ipython == 'debug':
                 use_ipython = True
                 debug = True
             else:
                 raise
         else:
             debug = False
         if use_ipython:
             self._start_ipython(overrides, banner, debug)
         else:
             self._start_python(overrides, banner)
Esempio n. 34
0
def aliases(directory):
    call_name(config.mta.incoming).regenerate(directory)
Esempio n. 35
0
 def process(self, args):
     """See `ICLISubCommand`."""
     global m, r
     banner = DEFAULT_BANNER
     # Detailed help wanted?
     if args.details:
         self._details()
         return
     # Interactive is the default unless --run was given.
     if args.interactive is None:
         interactive = (args.run is None)
     else:
         interactive = args.interactive
     # List name cannot be a regular expression if --run is not given.
     if args.listname and args.listname.startswith('^') and not args.run:
         self.parser.error(_('Regular expression requires --run'))
         return
     # Handle --run.
     list_manager = getUtility(IListManager)
     if args.run:
         # When the module and the callable have the same name, a shorthand
         # without the dot is allowed.
         dotted_name = (args.run if '.' in args.run
                        else '{0}.{0}'.format(args.run))
         if args.listname is None:
             self.parser.error(_('--run requires a mailing list name'))
             return
         elif args.listname.startswith('^'):
             r = {}
             cre = re.compile(args.listname, re.IGNORECASE)
             for mailing_list in list_manager.mailing_lists:
                 if cre.match(mailing_list.fqdn_listname):
                     results = call_name(dotted_name, mailing_list)
                     r[mailing_list.fqdn_listname] = results
         else:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             r = call_name(dotted_name, m)
     else:
         # Not --run.
         if args.listname is not None:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             banner = _(
                 "The variable 'm' is the $fqdn_listname mailing list")
     # All other processing is finished; maybe go into interactive mode.
     if interactive:
         overrides = dict(
             m=m,
             commit=config.db.commit,
             abort=config.db.abort,
             config=config,
             )
         banner = config.shell.banner + '\n' + banner
         if as_boolean(config.shell.use_ipython):
             self._start_ipython(overrides, banner)
         else:
             self._start_python(overrides, banner)
Esempio n. 36
0
 def process(self, args):
     """See `ICLISubCommand`."""
     global m, r
     banner = DEFAULT_BANNER
     # Detailed help wanted?
     if args.details:
         self._details()
         return
     # Interactive is the default unless --run was given.
     if args.interactive is None:
         interactive = (args.run is None)
     else:
         interactive = args.interactive
     # List name cannot be a regular expression if --run is not given.
     if args.listname and args.listname.startswith('^') and not args.run:
         self.parser.error(_('Regular expression requires --run'))
         return
     # Handle --run.
     list_manager = getUtility(IListManager)
     if args.run:
         # When the module and the callable have the same name, a shorthand
         # without the dot is allowed.
         dotted_name = (args.run
                        if '.' in args.run else '{0}.{0}'.format(args.run))
         if args.listname is None:
             self.parser.error(_('--run requires a mailing list name'))
             return
         elif args.listname.startswith('^'):
             r = {}
             cre = re.compile(args.listname, re.IGNORECASE)
             for mailing_list in list_manager.mailing_lists:
                 if cre.match(mailing_list.fqdn_listname):
                     results = call_name(dotted_name, mailing_list)
                     r[mailing_list.fqdn_listname] = results
         else:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             r = call_name(dotted_name, m)
     else:
         # Not --run.
         if args.listname is not None:
             fqdn_listname = args.listname
             m = list_manager.get(fqdn_listname)
             if m is None:
                 self.parser.error(_('No such list: $fqdn_listname'))
                 return
             banner = _(
                 "The variable 'm' is the $fqdn_listname mailing list")
     # All other processing is finished; maybe go into interactive mode.
     if interactive:
         overrides = dict(
             m=m,
             commit=config.db.commit,
             abort=config.db.abort,
             config=config,
         )
         banner = config.shell.banner + '\n' + banner
         if as_boolean(config.shell.use_ipython):
             self._start_ipython(overrides, banner)
         else:
             self._start_python(overrides, banner)
Esempio n. 37
0
 def process(self, args):
     """See `ICLISubCommand`."""
     # Call the MTA-specific regeneration method.
     call_name(config.mta.incoming).regenerate(args.directory)