/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/smtp_connection.py

  • Committer: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""A convenience class around smtplib."""
18
18
 
19
 
from email import Utils
 
19
from email.utils import getaddresses, parseaddr
 
20
 
20
21
import errno
21
22
import smtplib
22
23
import socket
23
24
 
24
 
from bzrlib import (
 
25
from . import (
25
26
    config,
26
27
    osutils,
27
28
    )
28
 
from bzrlib.errors import (
29
 
    NoDestinationAddress,
30
 
    SMTPError,
31
 
    DefaultSMTPConnectionRefused,
32
 
    SMTPConnectionRefused,
 
29
from .errors import (
 
30
    BzrError,
 
31
    InternalBzrError,
33
32
    )
34
33
 
35
34
 
 
35
smtp_password = config.Option('smtp_password', default=None,
 
36
                              help='''\
 
37
Password to use for authentication to SMTP server.
 
38
''')
 
39
smtp_server = config.Option('smtp_server', default=None,
 
40
                            help='''\
 
41
Hostname of the SMTP server to use for sending email.
 
42
''')
 
43
smtp_username = config.Option('smtp_username', default=None,
 
44
                              help='''\
 
45
Username to use for authentication to SMTP server.
 
46
''')
 
47
 
 
48
 
 
49
class SMTPError(BzrError):
 
50
 
 
51
    _fmt = "SMTP error: %(error)s"
 
52
 
 
53
    def __init__(self, error):
 
54
        self.error = error
 
55
 
 
56
 
 
57
class SMTPConnectionRefused(SMTPError):
 
58
 
 
59
    _fmt = "SMTP connection to %(host)s refused"
 
60
 
 
61
    def __init__(self, error, host):
 
62
        self.error = error
 
63
        self.host = host
 
64
 
 
65
 
 
66
class DefaultSMTPConnectionRefused(SMTPConnectionRefused):
 
67
 
 
68
    _fmt = "Please specify smtp_server.  No server at default %(host)s."
 
69
 
 
70
 
 
71
class NoDestinationAddress(InternalBzrError):
 
72
 
 
73
    _fmt = "Message does not have a destination address."
 
74
 
 
75
 
36
76
class SMTPConnection(object):
37
77
    """Connect to an SMTP server and send an email.
38
78
 
39
 
    This is a gateway between bzrlib.config.Config and smtplib.SMTP. It
 
79
    This is a gateway between breezy.config.Config and smtplib.SMTP. It
40
80
    understands the basic bzr SMTP configuration information: smtp_server,
41
81
    smtp_username, and smtp_password.
42
82
    """
48
88
        if self._smtp_factory is None:
49
89
            self._smtp_factory = smtplib.SMTP
50
90
        self._config = config
51
 
        self._config_smtp_server = config.get_user_option('smtp_server')
 
91
        self._config_smtp_server = config.get('smtp_server')
52
92
        self._smtp_server = self._config_smtp_server
53
93
        if self._smtp_server is None:
54
94
            self._smtp_server = self._default_smtp_server
55
95
 
56
 
        self._smtp_username = config.get_user_option('smtp_username')
57
 
        self._smtp_password = config.get_user_option('smtp_password')
 
96
        self._smtp_username = config.get('smtp_username')
 
97
        self._smtp_password = config.get('smtp_password')
58
98
 
59
99
        self._connection = None
60
100
 
65
105
 
66
106
        self._create_connection()
67
107
        # FIXME: _authenticate() should only be called when the server has
68
 
        # refused unauthenticated access, so it can safely try to authenticate 
 
108
        # refused unauthenticated access, so it can safely try to authenticate
69
109
        # with the default username. JRV20090407
70
110
        self._authenticate()
71
111
 
74
114
        self._connection = self._smtp_factory()
75
115
        try:
76
116
            self._connection.connect(self._smtp_server)
77
 
        except socket.error, e:
 
117
        except socket.error as e:
78
118
            if e.args[0] == errno.ECONNREFUSED:
79
119
                if self._config_smtp_server is None:
80
120
                    raise DefaultSMTPConnectionRefused(socket.error,
96
136
        if self._connection.has_extn("starttls"):
97
137
            code, resp = self._connection.starttls()
98
138
            if not (200 <= code <= 299):
99
 
                raise SMTPError("server refused STARTTLS: %d %s" % (code, resp))
 
139
                raise SMTPError("server refused STARTTLS: %d %s" %
 
140
                                (code, resp))
100
141
            # Say EHLO again, to check for newly revealed features
101
142
            code, resp = self._connection.ehlo()
102
143
            if not (200 <= code <= 299):
107
148
        auth = config.AuthenticationConfig()
108
149
        if self._smtp_username is None:
109
150
            # FIXME: Since _authenticate gets called even when no authentication
110
 
            # is necessary, it's not possible to use the default username 
 
151
            # is necessary, it's not possible to use the default username
111
152
            # here yet.
112
153
            self._smtp_username = auth.get_user('smtp', self._smtp_server)
113
154
            if self._smtp_username is None:
131
172
        """Get the origin and destination addresses of a message.
132
173
 
133
174
        :param message: A message object supporting get() to access its
134
 
            headers, like email.Message or bzrlib.email_message.EmailMessage.
 
175
            headers, like email.message.Message or
 
176
            breezy.email_message.EmailMessage.
135
177
        :return: A pair (from_email, to_emails), where from_email is the email
136
178
            address in the From header, and to_emails a list of all the
137
179
            addresses in the To, Cc, and Bcc headers.
138
180
        """
139
 
        from_email = Utils.parseaddr(message.get('From', None))[1]
 
181
        from_email = parseaddr(message.get('From', None))[1]
140
182
        to_full_addresses = []
141
183
        for header in ['To', 'Cc', 'Bcc']:
142
184
            value = message.get(header, None)
143
185
            if value:
144
186
                to_full_addresses.append(value)
145
 
        to_emails = [ pair[1] for pair in
146
 
                Utils.getaddresses(to_full_addresses) ]
 
187
        to_emails = [pair[1] for pair in
 
188
                     getaddresses(to_full_addresses)]
147
189
 
148
190
        return from_email, to_emails
149
191
 
153
195
        The message will be sent to all addresses in the To, Cc and Bcc
154
196
        headers.
155
197
 
156
 
        :param message: An email.Message or email.MIMEMultipart object.
 
198
        :param message: An email.message.Message or
 
199
            email.mime.multipart.MIMEMultipart object.
157
200
        :return: None
158
201
        """
159
202
        from_email, to_emails = self.get_message_addresses(message)
165
208
            self._connect()
166
209
            self._connection.sendmail(from_email, to_emails,
167
210
                                      message.as_string())
168
 
        except smtplib.SMTPRecipientsRefused, e:
 
211
        except smtplib.SMTPRecipientsRefused as e:
169
212
            raise SMTPError('server refused recipient: %d %s' %
170
 
                    e.recipients.values()[0])
171
 
        except smtplib.SMTPResponseException, e:
 
213
                            next(iter(e.recipients.values())))
 
214
        except smtplib.SMTPResponseException as e:
172
215
            raise SMTPError('%d %s' % (e.smtp_code, e.smtp_error))
173
 
        except smtplib.SMTPException, e:
 
216
        except smtplib.SMTPException as e:
174
217
            raise SMTPError(str(e))