@@ -29,48 +29,49 @@ news
Now based on pygrack & gitweb
- Improved RSS/ATOM feeds. Discoverable by browsers using proper headers, and
reformated based on user suggestions. Additional rss/atom feeds for user
journal
- various i18n improvements
- #478 permissions overview for admin in user edit view
fixes
+++++
- improved translations
- fixes issue #455 Creating an archive generates an exception on Windows
- fixes #448 Download ZIP archive keeps file in /tmp open and results
in out of disk space
- fixes issue #454 Search results under Windows include proceeding
backslash
- fixed issue #450. Rhodecode no longer will crash when bad revision is
present in journal data.
- fix for issue #417, git execution was broken on windows for certain
commands.
- fixed #413. Don't disable .git directory for bare repos on deleting
- fixed issue #459. Changed the way of obtaining logger in reindex task.
- fixed #453 added ID field in whoosh SCHEMA that solves the issue of
reindexing modified files
- fixes #481 rhodecode emails are sent without Date header
1.3.6 (**2012-05-17**)
----------------------
news
++++
- chinese traditional translation
- changed setup-app into setup-rhodecode and added arguments for auto-setup
mode that doesn't need user interaction
- fixed no scm found warning
- fixed __future__ import error on rcextensions
- made simplejson required lib for speedup on JSON encoding
- fixes #449 bad regex could get more than revisions from parsing history
- don't clear DB session when CELERY_EAGER is turned ON
1.3.5 (**2012-05-10**)
from rhodecode.lib.rcmail.response import MailResponse
from rhodecode.lib.rcmail.exceptions import BadHeaders
from rhodecode.lib.rcmail.exceptions import InvalidMessage
class Attachment(object):
"""
Encapsulates file attachment information.
:param filename: filename of attachment
:param content_type: file mimetype
:param data: the raw file data, either as string or file obj
:param disposition: content-disposition (if any)
def __init__(self,
filename=None,
content_type=None,
data=None,
disposition=None):
self.filename = filename
self.content_type = content_type
self.disposition = disposition or 'attachment'
self._data = data
@property
def data(self):
if isinstance(self._data, basestring):
@@ -113,55 +114,55 @@ class Message(object):
return response
def is_bad_headers(self):
Checks for bad headers i.e. newlines in subject, sender or recipients.
headers = [self.subject, self.sender]
headers += list(self.send_to)
headers += self.extra_headers.values()
for val in headers:
for c in '\r\n':
if c in val:
return True
return False
def validate(self):
Checks if message is valid and raises appropriate exception.
if not self.recipients:
raise InvalidMessage, "No recipients have been added"
raise InvalidMessage("No recipients have been added")
if not self.body and not self.html:
raise InvalidMessage, "No body has been set"
raise InvalidMessage("No body has been set")
if not self.sender:
raise InvalidMessage, "No sender address has been set"
raise InvalidMessage("No sender address has been set")
if self.is_bad_headers():
raise BadHeaders
def add_recipient(self, recipient):
Adds another recipient to the message.
:param recipient: email address of recipient.
self.recipients.append(recipient)
def add_cc(self, recipient):
Adds an email address to the CC list.
self.cc.append(recipient)
def add_bcc(self, recipient):
@@ -343,107 +343,111 @@ def to_message(mail, separator="; "):
"%r (Python ERROR: %s" %
(ctype, params, exc.message))
for k in mail.keys():
if k in ADDRESS_HEADERS_WHITELIST:
out[k.encode('ascii')] = header_to_mime_encoding(
mail[k],
not_email=False,
separator=separator
)
else:
not_email=True
out.extract_payload(mail)
# go through the children
for part in mail.parts:
out.attach(to_message(part))
return out
class MIMEPart(MIMEBase):
A reimplementation of nearly everything in email.mime to be more useful
for actually attaching things. Rather than one class for every type of
thing you'd encode, there's just this one, and it figures out how to
encode what you ask it.
def __init__(self, type, **params):
self.maintype, self.subtype = type.split('/')
MIMEBase.__init__(self, self.maintype, self.subtype, **params)
def add_text(self, content):
# this is text, so encode it in canonical form
try:
encoded = content.encode('ascii')
charset = 'ascii'
except UnicodeError:
encoded = content.encode('utf-8')
charset = 'utf-8'
self.set_payload(encoded, charset=charset)
def extract_payload(self, mail):
if mail.body == None: return # only None, '' is still ok
if mail.body == None:
return # only None, '' is still ok
ctype, ctype_params = mail.content_encoding['Content-Type']
cdisp, cdisp_params = mail.content_encoding['Content-Disposition']
assert ctype, ("Extract payload requires that mail.content_encoding "
"have a valid Content-Type.")
if ctype.startswith("text/"):
self.add_text(mail.body)
if cdisp:
# replicate the content-disposition settings
self.add_header('Content-Disposition', cdisp, **cdisp_params)
self.set_payload(mail.body)
encoders.encode_base64(self)
def __repr__(self):
return "<MIMEPart '%s/%s': %r, %r, multipart=%r>" % (
self.subtype,
self.maintype,
self['Content-Type'],
self['Content-Disposition'],
self.is_multipart())
def header_to_mime_encoding(value, not_email=False, separator=", "):
if not value: return ""
if not value:
return ""
encoder = Charset(DEFAULT_ENCODING)
if type(value) == list:
return separator.join(properly_encode_header(
v, encoder, not_email) for v in value)
return properly_encode_header(value, encoder, not_email)
def properly_encode_header(value, encoder, not_email):
The only thing special (weird) about this function is that it tries
to do a fast check to see if the header value has an email address in
it. Since random headers could have an email address, and email addresses
have weird special formatting rules, we have to check for it.
Normally this works fine, but in Librelist, we need to "obfuscate" email
addresses by changing the '@' to '-AT-'. This is where
VALUE_IS_EMAIL_ADDRESS exists. It's a simple lambda returning True/False
to check if a header value has an email address. If you need to make this
check different, then change this.
return value.encode("ascii")
except UnicodeEncodeError:
if not_email is False and VALUE_IS_EMAIL_ADDRESS(value):
# this could have an email address, make sure we don't screw it up
name, address = parseaddr(value)
return '"%s" <%s>' % (
encoder.header_encode(name.encode("utf-8")), address)
return encoder.header_encode(value.encode("utf-8"))
# -*- coding: utf-8 -*-
rhodecode.lib.rcmail.smtp_mailer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Simple smtp mailer used in RhodeCode
:created_on: Sep 13, 2010
:copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
:license: GPLv3, see COPYING for more details.
# 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 3 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, see <http://www.gnu.org/licenses/>.
import time
import logging
import smtplib
from socket import sslerror
from email.utils import formatdate
from rhodecode.lib.rcmail.message import Message
class SmtpMailer(object):
"""SMTP mailer class
mailer = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth
mail_port, ssl, tls)
mailer.send(recipients, subject, body, attachment_files)
:param recipients might be a list of string or single string
:param attachment_files is a dict of {filename:location}
it tries to guess the mimetype and attach the file
def __init__(self, mail_from, user, passwd, mail_server, smtp_auth=None,
mail_port=None, ssl=False, tls=False, debug=False):
self.mail_from = mail_from
self.mail_server = mail_server
self.mail_port = mail_port
self.user = user
self.passwd = passwd
self.ssl = ssl
self.tls = tls
self.debug = debug
self.auth = smtp_auth
def send(self, recipients=[], subject='', body='', html='',
attachment_files=None):
if isinstance(recipients, basestring):
recipients = [recipients]
headers = {
'Date': formatdate(time.time())
}
msg = Message(subject, recipients, body, html, self.mail_from,
recipients_separator=", ")
recipients_separator=", ", extra_headers=headers)
raw_msg = msg.to_message()
if self.ssl:
smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port)
smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
if self.tls:
smtp_serv.ehlo()
smtp_serv.starttls()
if self.debug:
smtp_serv.set_debuglevel(1)
if self.auth:
smtp_serv.esmtp_features["auth"] = self.auth
# if server requires authorization you must provide login and password
# but only if we have them
if self.user and self.passwd:
smtp_serv.login(self.user, self.passwd)
smtp_serv.sendmail(msg.sender, msg.send_to, raw_msg.as_string())
Status change: