comparison mercurial/mail.py @ 26587:56b2bcea2529

error: get Abort from 'error' instead of 'util' The home of 'Abort' is 'error' not 'util' however, a lot of code seems to be confused about that and gives all the credit to 'util' instead of the hardworking 'error'. In a spirit of equity, we break the cycle of injustice and give back to 'error' the respect it deserves. And screw that 'util' poser. For great justice.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Thu, 08 Oct 2015 12:55:45 -0700
parents ce26928cbe41
children ab1af5e7d734
comparison
equal deleted inserted replaced
26586:d51c658d3f04 26587:56b2bcea2529
16 import time 16 import time
17 17
18 from .i18n import _ 18 from .i18n import _
19 from . import ( 19 from . import (
20 encoding, 20 encoding,
21 error,
21 sslutil, 22 sslutil,
22 util, 23 util,
23 ) 24 )
24 25
25 _oldheaderinit = email.Header.Header.__init__ 26 _oldheaderinit = email.Header.Header.__init__
91 **self._sslkwargs) 92 **self._sslkwargs)
92 self.file = smtplib.SSLFakeFile(new_socket) 93 self.file = smtplib.SSLFakeFile(new_socket)
93 return new_socket 94 return new_socket
94 else: 95 else:
95 def SMTPS(sslkwargs, keyfile=None, certfile=None, **kwargs): 96 def SMTPS(sslkwargs, keyfile=None, certfile=None, **kwargs):
96 raise util.Abort(_('SMTPS requires Python 2.6 or later')) 97 raise error.Abort(_('SMTPS requires Python 2.6 or later'))
97 98
98 def _smtp(ui): 99 def _smtp(ui):
99 '''build an smtp connection and return a function to send mail''' 100 '''build an smtp connection and return a function to send mail'''
100 local_hostname = ui.config('smtp', 'local_hostname') 101 local_hostname = ui.config('smtp', 'local_hostname')
101 tls = ui.config('smtp', 'tls', 'none') 102 tls = ui.config('smtp', 'tls', 'none')
102 # backward compatible: when tls = true, we use starttls. 103 # backward compatible: when tls = true, we use starttls.
103 starttls = tls == 'starttls' or util.parsebool(tls) 104 starttls = tls == 'starttls' or util.parsebool(tls)
104 smtps = tls == 'smtps' 105 smtps = tls == 'smtps'
105 if (starttls or smtps) and not util.safehasattr(socket, 'ssl'): 106 if (starttls or smtps) and not util.safehasattr(socket, 'ssl'):
106 raise util.Abort(_("can't use TLS: Python SSL support not installed")) 107 raise error.Abort(_("can't use TLS: Python SSL support not installed"))
107 mailhost = ui.config('smtp', 'host') 108 mailhost = ui.config('smtp', 'host')
108 if not mailhost: 109 if not mailhost:
109 raise util.Abort(_('smtp.host not configured - cannot send mail')) 110 raise error.Abort(_('smtp.host not configured - cannot send mail'))
110 verifycert = ui.config('smtp', 'verifycert', 'strict') 111 verifycert = ui.config('smtp', 'verifycert', 'strict')
111 if verifycert not in ['strict', 'loose']: 112 if verifycert not in ['strict', 'loose']:
112 if util.parsebool(verifycert) is not False: 113 if util.parsebool(verifycert) is not False:
113 raise util.Abort(_('invalid smtp.verifycert configuration: %s') 114 raise error.Abort(_('invalid smtp.verifycert configuration: %s')
114 % (verifycert)) 115 % (verifycert))
115 verifycert = False 116 verifycert = False
116 if (starttls or smtps) and verifycert: 117 if (starttls or smtps) and verifycert:
117 sslkwargs = sslutil.sslkwargs(ui, mailhost) 118 sslkwargs = sslutil.sslkwargs(ui, mailhost)
118 else: 119 else:
149 ui.note(_('(authenticating to mail server as %s)\n') % 150 ui.note(_('(authenticating to mail server as %s)\n') %
150 (username)) 151 (username))
151 try: 152 try:
152 s.login(username, password) 153 s.login(username, password)
153 except smtplib.SMTPException as inst: 154 except smtplib.SMTPException as inst:
154 raise util.Abort(inst) 155 raise error.Abort(inst)
155 156
156 def send(sender, recipients, msg): 157 def send(sender, recipients, msg):
157 try: 158 try:
158 return s.sendmail(sender, recipients, msg) 159 return s.sendmail(sender, recipients, msg)
159 except smtplib.SMTPRecipientsRefused as inst: 160 except smtplib.SMTPRecipientsRefused as inst:
160 recipients = [r[1] for r in inst.recipients.values()] 161 recipients = [r[1] for r in inst.recipients.values()]
161 raise util.Abort('\n' + '\n'.join(recipients)) 162 raise error.Abort('\n' + '\n'.join(recipients))
162 except smtplib.SMTPException as inst: 163 except smtplib.SMTPException as inst:
163 raise util.Abort(inst) 164 raise error.Abort(inst)
164 165
165 return send 166 return send
166 167
167 def _sendmail(ui, sender, recipients, msg): 168 def _sendmail(ui, sender, recipients, msg):
168 '''send mail using sendmail.''' 169 '''send mail using sendmail.'''
172 ui.note(_('sending mail: %s\n') % cmdline) 173 ui.note(_('sending mail: %s\n') % cmdline)
173 fp = util.popen(cmdline, 'w') 174 fp = util.popen(cmdline, 'w')
174 fp.write(msg) 175 fp.write(msg)
175 ret = fp.close() 176 ret = fp.close()
176 if ret: 177 if ret:
177 raise util.Abort('%s %s' % ( 178 raise error.Abort('%s %s' % (
178 os.path.basename(program.split(None, 1)[0]), 179 os.path.basename(program.split(None, 1)[0]),
179 util.explainexit(ret)[0])) 180 util.explainexit(ret)[0]))
180 181
181 def _mbox(mbox, sender, recipients, msg): 182 def _mbox(mbox, sender, recipients, msg):
182 '''write mails to mbox''' 183 '''write mails to mbox'''
206 def validateconfig(ui): 207 def validateconfig(ui):
207 '''determine if we have enough config data to try sending email.''' 208 '''determine if we have enough config data to try sending email.'''
208 method = ui.config('email', 'method', 'smtp') 209 method = ui.config('email', 'method', 'smtp')
209 if method == 'smtp': 210 if method == 'smtp':
210 if not ui.config('smtp', 'host'): 211 if not ui.config('smtp', 'host'):
211 raise util.Abort(_('smtp specified as email transport, ' 212 raise error.Abort(_('smtp specified as email transport, '
212 'but no smtp host configured')) 213 'but no smtp host configured'))
213 else: 214 else:
214 if not util.findexe(method): 215 if not util.findexe(method):
215 raise util.Abort(_('%r specified as email transport, ' 216 raise error.Abort(_('%r specified as email transport, '
216 'but not in PATH') % method) 217 'but not in PATH') % method)
217 218
218 def mimetextpatch(s, subtype='plain', display=False): 219 def mimetextpatch(s, subtype='plain', display=False):
219 '''Return MIME message suitable for a patch. 220 '''Return MIME message suitable for a patch.
220 Charset will be detected as utf-8 or (possibly fake) us-ascii. 221 Charset will be detected as utf-8 or (possibly fake) us-ascii.
300 acc, dom = addr.split('@') 301 acc, dom = addr.split('@')
301 acc = acc.encode('ascii') 302 acc = acc.encode('ascii')
302 dom = dom.decode(encoding.encoding).encode('idna') 303 dom = dom.decode(encoding.encoding).encode('idna')
303 addr = '%s@%s' % (acc, dom) 304 addr = '%s@%s' % (acc, dom)
304 except UnicodeDecodeError: 305 except UnicodeDecodeError:
305 raise util.Abort(_('invalid email address: %s') % addr) 306 raise error.Abort(_('invalid email address: %s') % addr)
306 except ValueError: 307 except ValueError:
307 try: 308 try:
308 # too strict? 309 # too strict?
309 addr = addr.encode('ascii') 310 addr = addr.encode('ascii')
310 except UnicodeDecodeError: 311 except UnicodeDecodeError:
311 raise util.Abort(_('invalid local address: %s') % addr) 312 raise error.Abort(_('invalid local address: %s') % addr)
312 return email.Utils.formataddr((name, addr)) 313 return email.Utils.formataddr((name, addr))
313 314
314 def addressencode(ui, address, charsets=None, display=False): 315 def addressencode(ui, address, charsets=None, display=False):
315 '''Turns address into RFC-2047 compliant header.''' 316 '''Turns address into RFC-2047 compliant header.'''
316 if display or not address: 317 if display or not address: