summaryrefslogtreecommitdiff
path: root/mailman/commands/join.py
blob: 1cbf394e0c0f3fddd5fb5b0dec974510b2f0cac4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

"""The email commands 'join' and 'subscribe'."""

__metaclass__ = type
__all__ = [
    'Join',
    'Subscribe',
    ]


from email.header import decode_header, make_header
from email.utils import parseaddr
from zope.interface import implements

from mailman.Utils import MakeRandomPassword
from mailman.configuration import config
from mailman.i18n import _
from mailman.interfaces import (
    ContinueProcessing, DeliveryMode, IEmailCommand)



class Join:
    """The email 'join' command."""
    implements(IEmailCommand)

    name = 'join'
    argument_description = '[digest=<yes|no>] [address=<address>]'
    description = _("""\
Join this mailing list.  You will be asked to confirm your subscription
request and you may be issued a provisional password.

By using the 'digest' option, you can specify whether you want digest delivery
or not.  If not specified, the mailing list's default will be used.  You can
also subscribe an alternative address by using the 'address' option.  For
example:

    join address=myotheraddress@example.com
""")

    def process(self, mlist, msg, msgdata, arguments, results):
        """See `IEmailCommand`."""
        # Parse the arguments.
        address, delivery_mmode = self._parse_arguments(arguments)
        if address is None:
            realname, address = parseaddr(msg['from'])
        # Address could be None or the empty string.
        if not address:
            address = msg.get_sender()
        if not address:
            print >> results, _(
                '$self.name: No valid address found to subscribe')
            return ContinueProcessing.no
        password = MakeRandomPassword()
        try:
            confirm_add_member(mlist, address, realname, password,
                               delivery_mode, mlist.preferred_language)
        except XXX:
            pass
        print >> results, self.name, address, \
              (_('digest delivery') if digest else _('regular delivery'))
        return ContinueProcessing.yes

    def _parse_arguments(self, arguments):
        """Parse command arguments.

        :param arguments: The sequences of arguments as given to the
            `process()` method.
        :return: address, delivery_mode
        """
        address = None
        delivery_mode = None
        for argument in arguments:
            parts = argument.split('=', 1)
            if parts[0].lower() == 'digest':
                if digest is not None:
                    print >> results, self.name, \
                          _('duplicate argument: $argument')
                    return ContinueProcessing.no
                if len(parts) == 0:
                    # We treat just plain 'digest' as 'digest=yes'.  We don't
                    # yet support the other types of digest delivery.
                    delivery_mode = DeliveryMode.mime_digests
                else:
                    if parts[1].lower() == 'yes':
                        delivery_mode = DeliveryMode.mime_digests
                    elif parts[1].lower() == 'no':
                        delivery_mode = DeliveryMode.regular
                    else:
                        print >> results, self.name, \
                              _('bad argument: $argument')
                        return ContinueProcessing.no
            elif parts[0].lower() == 'address':
                if address is not None:
                    print >> results, self.name, \
                          _('duplicate argument $argument')
                    return ContinueProcessing.no
                if len(parts) == 0:
                    print >> results, self.name, \
                          _('missing argument value: $argument')
                    return ContinueProcessing.no
                if len(parts) > 1:
                    print >> results, self.name, \
                          _('too many argument values: $argument')
                    return ContinueProcessing.no
                address = parts[1]
        return address, delivery_mode

def ignore():
    # Fill in empty defaults
    if digest is None:
        digest = mlist.digest_is_default
    if password is None:
        password = Utils.MakeRandomPassword()
    if address is None:
        realname, address = parseaddr(res.msg['from'])
        if not address:
            # Fall back to the sender address
            address = res.msg.get_sender()
        if not address:
            res.results.append(_('No valid address found to subscribe'))
            return STOP
        # Watch for encoded names
        try:
            h = make_header(decode_header(realname))
            # BAW: in Python 2.2, use just unicode(h)
            realname = h.__unicode__()
        except UnicodeError:
            realname = u''
        # Coerce to byte string if uh contains only ascii
        try:
            realname = realname.encode('us-ascii')
        except UnicodeError:
            pass
    # Create the UserDesc record and do a non-approved subscription
    listowner = mlist.GetOwnerEmail()
    userdesc = UserDesc(address, realname, password, digest)
    remote = res.msg.get_sender()
    try:
        mlist.AddMember(userdesc, remote)
    except Errors.MembershipIsBanned:
        res.results.append(_("""\
The email address you supplied is banned from this mailing list.
If you think this restriction is erroneous, please contact the list
owners at %(listowner)s."""))
        return STOP
    except Errors.InvalidEmailAddress:
        res.results.append(_("""\
Mailman won't accept the given email address as a valid address."""))
        return STOP
    except Errors.MMAlreadyAMember:
        res.results.append(_('You are already subscribed!'))
        return STOP
    except Errors.MMCantDigestError:
        res.results.append(
            _('No one can subscribe to the digest of this list!'))
        return STOP
    except Errors.MMMustDigestError:
        res.results.append(_('This list only supports digest subscriptions!'))
        return STOP
    except Errors.MMSubscribeNeedsConfirmation:
        # We don't need to respond /and/ send a confirmation message.
        res.respond = 0
    except Errors.MMNeedApproval:
        res.results.append(_("""\
Your subscription request has been forwarded to the list administrator
at %(listowner)s for review."""))
    else:
        # Everything is a-ok
        res.results.append(_('Subscription request succeeded.'))



class Subscribe(Join):
    """The email 'subscribe' command (an alias for 'join')."""

    name = 'subscribe'