1# Copyright (C) 2007-2020 by the Free Software Foundation, Inc.
2#
3# This file is part of GNU Mailman.
4#
5# GNU Mailman is free software: you can redistribute it and/or modify it under
6# the terms of the GNU General Public License as published by the Free
7# Software Foundation, either version 3 of the License, or (at your option)
8# any later version.
9#
10# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13# more details.
14#
15# You should have received a copy of the GNU General Public License along with
16# GNU Mailman.  If not, see <https://www.gnu.org/licenses/>.
17
18"""Interface for a mailing list."""
19
20from enum import Enum
21from mailman.interfaces.address import InvalidEmailAddressError
22from mailman.interfaces.member import MemberRole
23from public import public
24from zope.interface import Attribute, Interface
25
26
27@public
28class InvalidListNameError(InvalidEmailAddressError):
29    """List name is invalid."""
30
31    def __init__(self, listname):
32        super().__init__('{}@'.format(listname))
33        self.listname = listname
34
35
36@public
37class DMARCMitigateAction(Enum):
38    # Mitigations to apply to messages From: domains publishing an applicable
39    # DMARC policy, or unconditionally depending on settings.
40    #
41    # No DMARC mitigations.
42    no_mitigation = 0
43    # Messages From: domains with DMARC policy will have From: replaced by the
44    # list posting address and the original From: added to Reply-To: or Cc:.
45    munge_from = 1
46    # Messages From: domains with DMARC policy will be wrapped in an outer
47    # message From: the list posting address.
48    wrap_message = 2
49    # Messages From: domains with DMARC policy will be rejected.
50    reject = 3
51    # Messages From: domains with DMARC policy will be discarded.
52    discard = 4
53
54
55@public
56class Personalization(Enum):
57    none = 0
58    # Everyone gets a unique copy of the message, and there are a few more
59    # substitution variables, but no headers are modified.
60    individual = 1
61    # All of the 'individual' personalization plus recipient header
62    # modification.
63    full = 2
64
65
66@public
67class ReplyToMunging(Enum):
68    # The Reply-To header is passed through untouched
69    no_munging = 0
70    # The mailing list's posting address is appended to the Reply-To header
71    point_to_list = 1
72    # An explicit Reply-To header is added
73    explicit_header = 2
74    # An explicit Reply-To header is added and
75    # the list address is removed from CC
76    explicit_header_only = 3
77
78
79@public
80class SubscriptionPolicy(Enum):
81    """All subscription/unsubscription policies for a mailing list."""
82    # Neither confirmation, nor moderator approval is required.
83    open = 0
84    # The user must confirm the subscription.
85    confirm = 1
86    # The moderator must approve the subscription.
87    moderate = 2
88    # The user must first confirm their subscription, and then if that is
89    # successful, the moderator must also approve it.
90    confirm_then_moderate = 3
91
92
93@public
94class IMailingList(Interface):
95    """A mailing list."""
96
97    # List identity
98
99    created_at = Attribute(
100        """The date and time that the mailing list was created.""")
101
102    list_name = Attribute("""\
103        The read-only short name of the mailing list.  Note that where a
104        Mailman installation supports multiple domains, this short name may
105        not be unique.  Use the fqdn_listname attribute for a guaranteed
106        unique id for the mailing list.  This short name is always the local
107        part of the posting email address.  For example, if messages are
108        posted to mylist@example.com, then the list_name is 'mylist'.
109        """)
110
111    mail_host = Attribute("""\
112        The read-only domain name 'hosting' this mailing list.  This is always
113        the domain name part of the posting email address, and it may bear no
114        relationship to the web url used to access this mailing list.  For
115        example, if messages are posted to mylist@example.com, then the
116        mail_host is 'example.com'.
117        """)
118
119    list_id = Attribute("""\
120        The identity of the mailing list.  This value will never change.  It
121        is defined in RFC 2369.
122        """)
123
124    fqdn_listname = Attribute("""\
125        The read-only fully qualified name of the mailing list.  This is the
126        guaranteed unique id for the mailing list, and it is always the
127        address to which messages are posted, e.g. mylist@example.com.  It is
128        always comprised of the list_name + '@' + mail_host.
129        """)
130
131    domain = Attribute(
132        """The `IDomain` that this mailing list is defined in.""")
133
134    display_name = Attribute("""\
135        The short human-readable descriptive name for the mailing list.  This
136        is used in locations such as the message footers and as the default
137        value for the Subject prefix.
138        """)
139
140    description = Attribute("""\
141        A terse phrase identifying this mailing list.
142
143        This description is used when the mailing list is listed with other
144        mailing lists, or in headers, and so forth.  It should be as succinct
145        as you can get it, while still identifying what the list is.""")
146
147    info = Attribute("""\
148        A longer description of this mailing list.  This can be any arbitrary
149        text, up to a database-specific maximum length.
150        """)
151
152    preferred_language = Attribute("""\
153        The default language for communications on this mailing list.
154
155        When the list sends out notifications, it will be in this language,
156        unless the recipient is a known user and that user has a preferred
157        language.
158        """)
159
160    subject_prefix = Attribute("""\
161        The text to insert at the front of the Subject field.
162
163        When messages posted to this mailing list are sent to the list
164        subscribers, the Subject header may be rewritten to include an
165        identifying prefix.  Typically this prefix will appear in square
166        brackets and the default value inside the brackets is taken as the
167        list's display name.  However, any value can be used, including the
168        empty string to prevent Subject header rewriting.
169        """)
170
171    allow_list_posts = Attribute(
172        """Flag specifying posts to the list are generally allowed.
173
174        This controls the value of the RFC 2369 List-Post header.  This is
175        usually set to True, except for announce-only lists.  When False, the
176        List-Post is set to NO as per the RFC.
177        """)
178
179    include_rfc2369_headers = Attribute(
180        """Flag specifying whether to include any RFC 2369 header, including
181        the RFC 2919 List-ID header.""")
182
183    anonymous_list = Attribute(
184        """Flag controlling whether messages to this list are anonymized.
185
186        Anonymizing messages is not perfect, however setting this flag removes
187        the sender of the message (in the From, Sender, and Reply-To fields)
188        and replaces these with the list's posting address.
189        """)
190
191    advertised = Attribute(
192        """Advertise this mailing list when people ask for an overview of the
193        available mailing lists.""")
194
195    # Contact addresses
196
197    posting_address = Attribute(
198        """The address to which messages are posted for copying to the full
199        list membership, where 'full' of course means those members for which
200        delivery is currently enabled.
201        """)
202
203    no_reply_address = Attribute(
204        """The address to which all messages will be immediately discarded,
205        without prejudice or record.  This address is specific to the ddomain,
206        even though it's available on the IMailingListAddresses interface.
207        Generally, humans should never respond directly to this address.
208        """)
209
210    owner_address = Attribute(
211        """The address which reaches the owners and moderators of the mailing
212        list.  There is no address which reaches just the owners or just the
213        moderators of a mailing list.
214        """)
215
216    request_address = Attribute(
217        """The address which reaches the email robot for this mailing list.
218        This robot can process various email commands such as changing
219        delivery options, getting information or help about the mailing list,
220        or processing subscrptions and unsubscriptions (although for the
221        latter two, it's better to use the join_address and leave_address.
222        """)
223
224    bounces_address = Attribute(
225        """The address which reaches the automated bounce processor for this
226        mailing list.  Generally, humans should never respond directly to this
227        address.
228        """)
229
230    join_address = Attribute(
231        """The address to which subscription requests should be sent.""")
232
233    leave_address = Attribute(
234        """The address to which unsubscription requests should be sent.""")
235
236    subscribe_address = Attribute(
237        """Deprecated address to which subscription requests may be sent.
238        This address is provided for backward compatibility only.  See
239        `join_address` for the preferred alias.
240        """)
241
242    unsubscribe_address = Attribute(
243        """Deprecated address to which unsubscription requests may be sent.
244        This address is provided for backward compatibility only.  See
245        `leave_address` for the preferred alias.
246        """)
247
248    def confirm_address(cookie=''):
249        """The address used for various forms of email confirmation."""
250
251    # DMARC attributes.
252
253    dmarc_mitigate_action = Attribute(
254        """The mitigation to apply to messages from a DMARC matching domain.
255
256        This is a  DMARCMitigateAction to be applied to messages From: a domain
257        publishing DMARC p=reject or quarantine, and possibly unconditionally
258        depending on the setting of dmarc_mitigate_unconditionally.
259        """)
260
261    dmarc_mitigate_unconditionally = Attribute(
262        """Should DMARC mitigations apply unconditionally?
263
264        A flag indicating whether to apply dmarc_mitigate_action to all
265        messages, but only if dmarc_mitigate_action is other than reject or
266        discard.
267        """)
268
269    dmarc_moderation_notice = Attribute(
270        """Text to include in any DMARC rejected message.
271
272        Rejection notices are sent when DMARCMitigateAction of reject applies.
273        """)
274
275    dmarc_wrapped_message_text = Attribute(
276        """Additional MIME text to include in DMARC wrapped messages.
277
278        This text is added as a separate text/plain MIME part preceding the
279        original message part in the wrapped message when DMARCMitigateAction
280        of wrap_message applies.
281        """)
282
283    # Rosters and subscriptions.
284
285    owners = Attribute(
286        """The IUser owners of this mailing list.
287
288        This does not include the IUsers who are moderators but not owners of
289        the mailing list.""")
290
291    moderators = Attribute(
292        """The IUser moderators of this mailing list.
293
294        This does not include the IUsers who are owners but not moderators of
295        the mailing list.""")
296
297    administrators = Attribute(
298        """The IUser administrators of this mailing list.
299
300        This includes the IUsers who are both owners and moderators of the
301        mailing list.""")
302
303    nonmembers = Attribute(
304        """A roster of all the nonmembers of the mailing list.""")
305
306    members = Attribute(
307        """A roster of all the members of the mailing list, regardless of
308        whether they are to receive regular messages or digests, or whether
309        they have their delivery disabled or not.""")
310
311    regular_members = Attribute(
312        """An roster of all the IMembers who are to receive regular postings
313        (i.e. non-digests) from the mailing list, regardless of whether they
314        have their delivery disabled or not.""")
315
316    digest_members = Attribute(
317        """A roster of all the IMembers who are to receive digests of postings
318        to this mailing list, regardless of whether they have their deliver
319        disabled or not, or of the type of digest they are to receive.""")
320
321    subscription_policy = Attribute(
322        """The policy for subscribing new members to the list.""")
323
324    unsubscription_policy = Attribute(
325        """The policy for unsubscribing members from the list.""")
326
327    subscribers = Attribute(
328        """An iterator over all IMembers subscribed to this list, with any
329        role.
330        """)
331
332    def get_roster(role):
333        """Return the appropriate roster for the given role.
334
335        :param role: The requested roster's role.
336        :type role: MemberRole
337        :return: The requested roster.
338        :rtype: Roster
339        """
340
341    def is_subscribed(subscriber, role=MemberRole.member):
342        """Is the given address or user subscribed to the mailing list?
343
344        :param subscriber: The address or user to check.
345        :type subscriber: `IUser` or `IAddress`
346        :param role: The role being checked (e.g. a member, owner, or
347            moderator of a mailing list).
348        :type role: `MemberRole`
349        :return: A flag indicating whether the subscriber is already
350            subscribed to the mailing list or not.
351        """
352
353    def subscribe(subscriber, role=MemberRole.member):
354        """Subscribe the given address or user to the mailing list.
355
356        :param subscriber: The address or user to subscribe to the mailing
357            list.  The user's preferred address receives deliveries, if she
358            has one, otherwise no address for the user appears in the rosters.
359        :type subscriber: `IUser` or `IAddress`
360        :param role: The role being subscribed to (e.g. a member, owner, or
361            moderator of a mailing list).
362        :type role: `MemberRole`
363        :return: The member object representing the subscription.
364        :rtype: `IMember`
365        :raises AlreadySubscribedError: If the address or user is already
366            subscribed to the mailing list with the given role.  Note however
367            that it is possible to subscribe an address to a mailing list with
368            a particular role, and also subscribe a user with a matching
369            preferred address that is explicitly subscribed with the same role.
370        :raises InvalidEmailAddressError: If the address being subscribed is
371            the list's posting address.
372        """
373
374    # Delivery.
375
376    archive_policy = Attribute(
377        """The policy for archiving messages to this mailing list.
378
379        The value is an `ArchivePolicy` enum.  Use this to archive the mailing
380        list publicly, privately, or not at all.
381        """)
382
383    last_post_at = Attribute(
384        """The date and time a message was last posted to the mailing list.""")
385
386    post_id = Attribute(
387        """A monotonically increasing integer sequentially assigned to each
388        list posting.""")
389
390    personalize = Attribute(
391        """The type of personalization that is applied to postings.""")
392
393    reply_goes_to_list = Attribute(
394        """Reply-To: header munging policy.""")
395
396    member_roster_visibility = Attribute(
397        """The policy for who can view the member roster of this mailing list.
398
399        The value is an `RosterVisibility` enum.  Use this to change who can
400        view the member list. Options are public, members, or moderators.""")
401
402    # Digests.
403
404    digests_enabled = Attribute(
405        """Whether or not digests are enabled for this mailing list.""")
406
407    digest_size_threshold = Attribute(
408        """The maximum (approximate) size in kilobytes of the digest currently
409        being collected.""")
410
411    digest_send_periodic = Attribute(
412        """Should a digest be sent by the `mailman send_digest` command even
413        when the size threshold hasn't yet been met?""")
414
415    digest_volume_frequency = Attribute(
416        """How often should a new digest volume be started?""")
417
418    digest_last_sent_at = Attribute(
419        """The date and time a digest of this mailing list was last sent.""")
420
421    volume = Attribute(
422        """A monotonically increasing integer sequentially assigned to each
423        new digest volume.  The volume number may be bumped either
424        automatically (i.e. on a defined schedule) or manually.  When the
425        volume number is bumped, the digest number is always reset to 1.""")
426
427    next_digest_number = Attribute(
428        """A sequence number for a specific digest in a given volume.  When
429        the digest volume number is bumped, the digest number is reset to
430        1.""")
431
432    def send_one_last_digest_to(address, delivery_mode):
433        """Make sure to send one last digest to an address.
434
435        This is used when a person transitions from digest delivery to regular
436        delivery and wants to make sure they don't miss anything.  By
437        indicating that they'd like to receive one last digest, they will
438        ensure continuity in receiving mailing lists posts.
439
440        :param address: The address of the person receiving one last digest.
441        :type address: `IAddress`
442        :param delivery_mode: The type of digest to receive.
443        :type delivery_mode: `DeliveryMode`
444        """
445
446    last_digest_recipients = Attribute(
447        """An iterator over the addresses that should receive one last digest.
448
449        Items are 2-tuples of (`IAddress`, `DeliveryMode`).  The one last
450        digest recipients are cleared.
451        """)
452
453    # Autoresponses.
454
455    autoresponse_grace_period = Attribute(
456        """Time period (in days) between automatic responses.
457
458        When this mailing list is set to send an auto-response for messages
459        sent to mailing list posts, the mailing list owners, or the `-request`
460        address, such reponses will not be sent to the same user more than
461        once during the grace period.  Set to zero (or a negative value) for
462        no grace period (i.e. auto-respond to every message).
463        """)
464
465    autorespond_owner = Attribute(
466        """How should the mailing list automatically respond to messages sent
467        to the -owner or -moderator address?
468
469        Options are:
470        * No response sent
471        * Send a response and discard the original messge
472        * Send a response and continue processing the original message
473        """)
474
475    autoresponse_owner_text = Attribute(
476        """The text sent in an autoresponse to the owner or moderator.""")
477
478    autorespond_postings = Attribute(
479        """How should the mailing list automatically respond to messages sent
480        to the list's posting address?
481
482        Options are:
483        * No response sent
484        * Send a response and discard the original messge
485        * Send a response and continue processing the original message
486        """)
487
488    autoresponse_postings_text = Attribute(
489        """The text sent in an autoresponse to the list's posting address.""")
490
491    autorespond_requests = Attribute(
492        """How should the mailing list automatically respond to messages sent
493        to the list's `-request` address?
494
495        Options are:
496        * No response sent
497        * Send a response and discard the original messge
498        * Send a response and continue processing the original message
499        """)
500
501    autoresponse_request_text = Attribute(
502        """The text sent in an autoresponse to the list's `-request`
503        address.""")
504
505    # Processing.
506
507    posting_chain = Attribute(
508        """This mailing list's posting moderation chain.
509
510        When messages are posted to a mailing list, it first goes through a
511        moderation chain to determine whether the message will be accepted.
512        This attribute names a chain for postings, which must exist.
513        """)
514
515    posting_pipeline = Attribute(
516        """This mailing list's posting pipeline.
517
518        Every mailing list has a processing pipeline that messages flow
519        through once they've been accepted for posting to the mailing list.
520        This attribute names a pipeline for postings, which must exist.
521        """)
522
523    owner_chain = Attribute(
524        """This mailing list's owner moderation chain.
525
526        When messages are posted to the owners of a mailing list, it first
527        goes through a moderation chain to determine whether the message will
528        be accepted.  This attribute names a chain for postings, which must
529        exist.
530        """)
531
532    owner_pipeline = Attribute(
533        """This mailing list's owner posting pipeline.
534
535        Every mailing list has a processing pipeline that messages flow
536        through once they've been accepted for posting to the owners of a
537        mailing list.  This attribute names a pipeline for postings, which
538        must exist.
539        """)
540
541    data_path = Attribute(
542        """The file system path to list-specific data.
543
544        An example of list-specific data is the temporary digest mbox file
545        that gets created to accumlate messages for the digest.
546        """)
547
548    require_explicit_destination = Attribute(
549        """Flag controlling requiring explisit destination.
550
551        If require_explicit_destination is True, a post must have the list's
552        posting address or an acceptable alias in To: or Cc: or be held for
553        moderator approval.
554        """)
555
556    acceptable_aliases = Attribute(
557        """List of addresses and regexps acceptable as explicit destination.
558
559        This is a list of addresses and regexps matching addresses that are
560        acceptable in To: or Cc: when require_explicit_destination is True.
561        """)
562
563    administrivia = Attribute(
564        """Flag controlling `administrivia` checks.
565
566        Administrivia tests check whether postings to the mailing list are
567        really meant for the -request address.  Examples include messages with
568        `help`, `subscribe`, `unsubscribe`, and other commands.  When such
569        messages are incorrectly posted to the general mailing list, they are
570        just noise, and when this flag is set will be intercepted and in
571        general held for moderator approval.
572        """)
573
574    filter_content = Attribute(
575        """Flag specifying whether to filter a message's content.
576
577        Filtering is performed on MIME type and file name extension.
578        """)
579
580    filter_action = Attribute(
581        """Action to take when the top-level content-type is filtered.
582
583        The value is a `FilterAction` enum.
584        """)
585
586    convert_html_to_plaintext = Attribute(
587        """Flag specifying whether text/html parts should be converted.
588
589        When True, after filtering, if there are any text/html parts left in
590        the original message, they are converted to text/plain.
591        """)
592
593    collapse_alternatives = Attribute(
594        """Flag specifying whether multipart/alternatives should be collapsed.
595
596        After all MIME content filtering is complete, collapsing alternatives
597        replaces the outer multipart/alternative parts with the first
598        subpart.
599        """)
600
601    filter_types = Attribute(
602        """Sequence of MIME types that should be filtered out.
603
604        These can be either main types or main/sub types.  Set this attribute
605        to a sequence to change it, or to None to empty it.
606        """)
607
608    pass_types = Attribute(
609        """Sequence of MIME types to explicitly pass.
610
611        These can be either main types or main/sub types.  Set this attribute
612        to a sequence to change it, or to None to empty it.  Pass types are
613        consulted after filter types, and only if `pass_types` is non-empty.
614        """)
615
616    filter_extensions = Attribute(
617        """Sequence of file extensions that should be filtered out.
618
619        Set this attribute to a sequence to change it, or to None to empty it.
620        """)
621
622    pass_extensions = Attribute(
623        """Sequence of file extensions to explicitly pass.
624
625        Set this attribute to a sequence to change it, or to None to empty it.
626        Pass extensions are consulted after filter extensions, and only if
627        `pass_extensions` is non-empty.
628        """)
629
630    # Moderation.
631
632    default_member_action = Attribute(
633        """The default action to take for postings from members.
634
635        When an address is subscribed to the mailing list, this attribute sets
636        the initial moderation action (as an `Action`).  When the action is
637        `Action.defer` (the default), then normal posting decisions are made.
638        When the action is `Action.accept`, the postings are accepted without
639        any other checks.
640        """)
641
642    default_nonmember_action = Attribute(
643        """The default action to take for postings from nonmembers.
644
645        When a nonmember address posts to the mailing list, this attribute
646        sets the initial moderation action (as an `Action`).  When the action
647        is `Action.defer` (the default), then normal posting decisions are
648        made.  When the action is `Action.accept`, the postings are accepted
649        without any other checks.
650        """)
651
652    # Bounces.
653    bounce_info_stale_after = Attribute(
654        """Number of days after which bounce info is considered stale.
655
656        The number of days after which a member's bounce information is
657        considered stale. If no new bounces have been received in the interim,
658        the bounce score is reset to zero. This value must be an integer.
659        """)
660
661    bounce_notify_owner_on_disable = Attribute(
662        """This option controls whether or not the list owner
663        is notified when a member's subscription is automatically
664        disabled due to their bounce threshold being reached.
665        """)
666
667    bounce_notify_owner_on_removal = Attribute(
668        """This option controls whether or not the list owner
669        is notified when a member is removed from the list after
670        their disabled notifications have been exhausted.
671        """)
672
673    bounce_score_threshold = Attribute(
674        """Bounce score threshold for a mailing-list.
675
676        Threshold value for a Member's bounce_score after which we will either
677        disable membership or unsubscribe the member from the mailing list.
678        """)
679
680    bounce_you_are_disabled_warnings = Attribute(
681        """The number of notices a disabled member will
682        receive before their address is removed from the
683        mailing list's roster. Set this to 0 to immediately
684        remove an address from the list once their bounce
685        score exceeds the threshold. This value must be an integer.
686        """)
687
688    bounce_you_are_disabled_warnings_interval = Attribute(
689        """The number of days between each disabled notification.""")
690
691    forward_unrecognized_bounces_to = Attribute(
692        """What to do when a bounce contains no recognizable addresses.
693
694        This is an enumeration which specifies what to do with such bounce
695        messages.  They can be discarded, forward to the list owner, or
696        forwarded to the site owner.
697        """)
698
699    process_bounces = Attribute(
700        """Whether or not the mailing list processes bounces.""")
701
702    # Notifications.
703
704    admin_immed_notify = Attribute(
705        """Flag controlling immediate notification of requests.
706
707        List moderators normally get daily notices about pending
708        administrative requests.  This flag controls whether moderators also
709        receive immediate notification of such pending requests.
710        """)
711
712    admin_notify_mchanges = Attribute(
713        """Flag controlling notification of joins and leaves.
714
715        List moderators can receive notifications for every member that joins
716        or leaves their mailing lists.  This flag controls those
717        notifications.
718        """)
719
720    send_welcome_message = Attribute(
721        """Flag indicating whether a welcome message should be sent.""")
722
723    send_goodbye_message = Attribute(
724        """Flag indicating whether a goodbye message should be sent.""")
725
726    # Usenet gateway.
727
728    gateway_to_mail = Attribute(
729        """Flag indicating that posts to the linked newsgroup should be gated
730        to the list.""")
731
732    gateway_to_news = Attribute(
733        """Flag indicating that posts to the list should be gated to the
734        linked newsgroup.""")
735
736    linked_newsgroup = Attribute(
737        """The name of the linked newsgroup.""")
738
739    newsgroup_moderation = Attribute(
740        """The moderation policy for the linked newsgroup, if there is one.""")
741
742    nntp_prefix_subject_too = Attribute(
743        """Flag indicating whether the list's subject_prefix should be included
744        in posts gated to usenet.""")
745
746    usenet_watermark = Attribute(
747        """The NNTP server's message number of the last post gated to the
748        list.""")
749
750
751@public
752class IAcceptableAlias(Interface):
753    """An acceptable alias for implicit destinations."""
754
755    mailing_list = Attribute('The associated mailing list.')
756
757    address = Attribute('The address or pattern to match against recipients.')
758
759
760@public
761class IAcceptableAliasSet(Interface):
762    """The set of acceptable aliases for a mailing list."""
763
764    def clear():
765        """Clear the set of acceptable posting aliases."""
766
767    def add(alias):
768        """Add the given address as an acceptable aliases for posting.
769
770        :param alias: The email address to accept as a recipient for implicit
771            destination posting purposes.  The alias is coerced to lower
772            case.  If `alias` begins with a '^' character, it is interpreted
773            as a regular expression, otherwise it must be an email address.
774        :type alias: string
775        :raises ValueError: when the alias neither starts with '^' nor has an
776            '@' sign in it.
777        """
778
779    def remove(alias):
780        """Remove the given address as an acceptable aliases for posting.
781
782        :param alias: The email address to no longer accept as a recipient for
783            implicit destination posting purposes.
784        :type alias: string
785        """
786
787    aliases = Attribute(
788        """An iterator over all the acceptable aliases.""")
789
790
791@public
792class IListArchiver(Interface):
793    """An archiver for a mailing list.
794
795    The named archiver must be enabled site-wide in order for a mailing list
796    to be able to enable it.
797    """
798
799    mailing_list = Attribute('The associated mailing list.')
800
801    name = Attribute('The name of the archiver.')
802
803    is_enabled = Attribute('Is this archiver enabled for this mailing list?')
804
805    system_archiver = Attribute(
806        'The associated system-wide IArchiver instance.')
807
808
809@public
810class IListArchiverSet(Interface):
811    """The set of archivers (enabled or disabled) for a mailing list."""
812
813    archivers = Attribute(
814        """An iterator over all the archivers for this mailing list.""")
815
816    def get(archiver_name):
817        """Return the `IListArchiver` with the given name, if it exists.
818
819        :param archiver_name: The name of the archiver.
820        :type archiver_name: unicode.
821        :return: the matching `IListArchiver` or None if the named archiver
822            does not exist.
823        """
824
825
826@public
827class IHeaderMatch(Interface):
828    """A mailing list-specific message header matching rule."""
829
830    mailing_list = Attribute(
831        """The mailing list for the header match.""")
832
833    header = Attribute(
834        """The email header that will be checked.""")
835
836    pattern = Attribute(
837        """The regular expression to match.""")
838
839    position = Attribute(
840        """The ordinal position of this header match.
841
842        Set this to change the position of this header match.
843        """)
844
845    chain = Attribute(
846        """The chain to jump to on a match.
847
848        If it is None, the `[antispam]jump_chain` action in the configuration
849        file is used.
850        """)
851
852    tag = Attribute(
853        """An arbitrary value to identify a set of IHeaderMatches.
854
855        This tag can be used to filter a set of IHeaderMatches, so that they
856        can set and removed together, without having to query the whole list
857        and iterate over them.
858        """)
859
860
861@public
862class IHeaderMatchList(Interface):
863    """The list of header matching rules for a mailing list."""
864
865    def clear():
866        """Clear the list of header matching rules."""
867
868    def append(header, pattern, chain=None, tag=None):
869        """Append the given rule to this mailing list's header match list.
870
871        :param header: The email header to filter on.  It will be converted to
872            lower case for consistency.
873        :type header: string
874        :param pattern: The regular expression to use.
875        :type pattern: string
876        :param chain: The chain to jump to, or None to use the site-wide
877            antispam jump chain via the configuration.  Defaults to None.
878        :type chain: string or None
879        :param tag: An arbitrary value to identify a set of IHeaderMatches.
880        :type tag: string or None
881        :raises ValueError: if the header/pattern pair already exists for this
882            mailing list.
883        """
884
885    def insert(index, header, pattern, chain=None, tag=None):
886        """Insert a header match rule.
887
888        Inserts the given rule at the given index position in this
889        mailing list's header match list.
890
891        :param index: The index to insert the rule at.
892        :type index: integer
893        :param header: The email header to filter on.  It will be converted to
894            lower case for consistency.
895        :type header: string
896        :param pattern: The regular expression to use.
897        :type pattern: string
898        :param chain: The chain to jump to, or None to use the site-wide
899            antispam jump chain via the configuration.  Defaults to None.
900        :type chain: string or None
901        :param tag: An arbitrary value to identify a set of IHeaderMatches.
902        :type tag: string or None
903        :raises ValueError: if the header/pattern pair already exists for this
904            mailing list.
905        """
906
907    def remove(header, pattern):
908        """Remove the given rule from this mailing list's header match list.
909
910        :param header: The email header part of the rule to be removed.
911        :type header: string
912        :param pattern: The regular expression part of the rule to be removed.
913        :type pattern: string
914        :raises ValueError: if the header does not exist in the list of
915            header matches.
916        """
917
918    def __getitem__(index):
919        """Return the header match at the given index for this mailing list.
920
921        :param index: The index of the header match to return.
922        :type index: integer
923        :return: The header match at this index.
924        :rtype: `IHeaderMatch`
925        :raises IndexError: if there is no header match at this index for
926            this mailing list.
927        """
928
929    def __delitem__(index):
930        """Remove the rule at the given index.
931
932        :param index: The index of the header match to remove.
933        :type index: integer
934        :raises IndexError: if there is no header match at this index for
935            this mailing list.
936        """
937
938    def __len__():
939        """Return the number of header matches for this mailing list.
940
941        :rtype: integer
942        """
943
944    def __iter__():
945        """An iterator over all the IHeaderMatches defined in this list.
946
947        :return: iterator over `IHeaderMatch`.
948        """
949