1# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
2#
3# This program is free software; you can redistribute it and/or
4# modify it under the terms of the GNU General Public License
5# as published by the Free Software Foundation; either version 2
6# of the License, or (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
16# USA.
17
18
19"""Shared mailman errors and messages."""
20
21
22# exceptions for problems related to opening a list
23class MMListError(Exception): pass
24class MMUnknownListError(MMListError): pass
25class MMCorruptListDatabaseError(MMListError): pass
26class MMListNotReadyError(MMListError): pass
27class MMListAlreadyExistsError(MMListError): pass
28class BadListNameError(MMListError): pass
29
30# Membership exceptions
31class MMMemberError(Exception): pass
32class MMBadUserError(MMMemberError): pass
33class MMAlreadyAMember(MMMemberError): pass
34class MMAlreadyPending(MMMemberError): pass
35
36# "New" style membership exceptions (new w/ MM2.1)
37class MemberError(Exception): pass
38class NotAMemberError(MemberError): pass
39class AlreadyReceivingDigests(MemberError): pass
40class AlreadyReceivingRegularDeliveries(MemberError): pass
41class CantDigestError(MemberError): pass
42class MustDigestError(MemberError): pass
43class MembershipIsBanned(MemberError): pass
44
45# Exception hierarchy for various authentication failures, can be
46# raised from functions in SecurityManager.py
47class MMAuthenticationError(Exception): pass
48class MMBadPasswordError(MMAuthenticationError): pass
49class MMPasswordsMustMatch(MMAuthenticationError): pass
50class MMCookieError(MMAuthenticationError): pass
51class MMExpiredCookieError(MMCookieError): pass
52class MMInvalidCookieError(MMCookieError): pass
53
54class MMMustDigestError: pass
55class MMCantDigestError: pass
56class MMNeedApproval:
57    def __init__(self, message=None):
58        self.message = message
59    def __str__(self):
60        return self.message or ''
61class MMSubscribeNeedsConfirmation: pass
62class MMBadConfirmation:
63    def __init__(self, message=None):
64        self.message = message
65    def __str__(self):
66        return self.message or ''
67class MMAlreadyDigested: pass
68class MMAlreadyUndigested: pass
69
70MODERATED_LIST_MSG    = "Moderated list"
71IMPLICIT_DEST_MSG     = "Implicit destination"
72SUSPICIOUS_HEADER_MSG = "Suspicious header"
73FORBIDDEN_SENDER_MSG  = "Forbidden sender"
74
75
76
77# New style class based exceptions.  All the above errors should eventually be
78# converted.
79
80class MailmanError(Exception):
81    """Base class for all Mailman exceptions."""
82    pass
83
84
85class MMLoopingPost(MailmanError):
86    """Post already went through this list!"""
87    pass
88
89
90# Exception hierarchy for bad email address errors that can be raised from
91# Utils.ValidateEmail()
92class EmailAddressError(MailmanError):
93    """Base class for email address validation errors."""
94    pass
95
96class MMBadEmailError(EmailAddressError):
97    """Email address is invalid (empty string or not fully qualified)."""
98    pass
99
100class MMHostileAddress(EmailAddressError):
101    """Email address has potentially hostile characters in it."""
102    pass
103
104
105# Exceptions for admin request database
106class LostHeldMessage(MailmanError):
107    """Held message was lost."""
108    pass
109
110
111
112def _(s):
113    return s
114
115# Exceptions for the Handler subsystem
116class HandlerError(MailmanError):
117    """Base class for all handler errors."""
118
119class HoldMessage(HandlerError):
120    """Base class for all message-being-held short circuits."""
121
122    # funky spelling is necessary to break import loops
123    reason = _('For some unknown reason')
124
125    def reason_notice(self):
126        return self.reason
127
128    # funky spelling is necessary to break import loops
129    rejection = _('Your message was rejected')
130
131    def rejection_notice(self, mlist):
132        return self.rejection
133
134class DiscardMessage(HandlerError):
135    """The message can be discarded with no further action"""
136
137class SomeRecipientsFailed(HandlerError):
138    """Delivery to some or all recipients failed"""
139    def __init__(self, tempfailures, permfailures):
140        HandlerError.__init__(self)
141        self.tempfailures = tempfailures
142        self.permfailures = permfailures
143
144# multiple inheritance for backwards compatibility
145class LoopError(DiscardMessage, MMLoopingPost):
146    """We've seen this message before"""
147
148class RejectMessage(HandlerError):
149    """The message will be bounced back to the sender"""
150    def __init__(self, notice=None):
151        if notice is None:
152            notice = _('Your message was rejected')
153        if notice.endswith('\n\n'):
154            pass
155        elif notice.endswith('\n'):
156            notice += '\n'
157        else:
158            notice += '\n\n'
159        self.__notice = notice
160
161    def notice(self):
162        return self.__notice
163
164
165# Additional exceptions
166class HostileSubscriptionError(MailmanError):
167    """A cross-subscription attempt was made."""
168    # This exception gets raised when an invitee attempts to use the
169    # invitation to cross-subscribe to some other mailing list.
170