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