import apt_pkg
import database
import time
+import re
+import string
+import email as modemail
from dak_exceptions import *
+from textutils import fix_maintainer
from regexes import re_html_escaping, html_escaping, re_single_line_field, \
re_multi_line_field, re_srchasver, re_verwithext, \
- re_parse_maintainer, re_taint_free, re_gpg_uid
+ re_parse_maintainer, re_taint_free, re_gpg_uid, re_re_mark, \
+ re_whitespace_comment
################################################################################
changes_in = open_file(filename)
content = changes_in.read()
changes_in.close()
+ try:
+ unicode(content, 'utf-8')
+ except UnicodeError:
+ raise ChangesUnicodeError, "Changes file not proper utf-8"
return parse_deb822(content, signing_rules)
################################################################################
file_handle = open_file(f)
except CantOpenError:
rejmsg.append("Could not open file %s for checksumming" % (f))
+ continue
files[f][hash_key(hashname)] = hashfunc(file_handle)
################################################################################
-def force_to_utf8(s):
- """
- Forces a string to UTF-8. If the string isn't already UTF-8,
- it's assumed to be ISO-8859-1.
- """
- try:
- unicode(s, 'utf-8')
- return s
- except UnicodeError:
- latin1_s = unicode(s,'iso8859-1')
- return latin1_s.encode('utf-8')
-
-def rfc2047_encode(s):
- """
- Encodes a (header) string per RFC2047 if necessary. If the
- string is neither ASCII nor UTF-8, it's assumed to be ISO-8859-1.
- """
- try:
- codecs.lookup('ascii')[1](s)
- return s
- except UnicodeError:
- pass
- try:
- codecs.lookup('utf-8')[1](s)
- h = email.Header.Header(s, 'utf-8', 998)
- return str(h)
- except UnicodeError:
- h = email.Header.Header(s, 'iso-8859-1', 998)
- return str(h)
-
-################################################################################
-
-# <Culus> 'The standard sucks, but my tool is supposed to interoperate
-# with it. I know - I'll fix the suckage and make things
-# incompatible!'
-
-def fix_maintainer (maintainer):
- """
- Parses a Maintainer or Changed-By field and returns:
- 1. an RFC822 compatible version,
- 2. an RFC2047 compatible version,
- 3. the name
- 4. the email
-
- The name is forced to UTF-8 for both 1. and 3.. If the name field
- contains '.' or ',' (as allowed by Debian policy), 1. and 2. are
- switched to 'email (name)' format.
-
- """
- maintainer = maintainer.strip()
- if not maintainer:
- return ('', '', '', '')
-
- if maintainer.find("<") == -1:
- email = maintainer
- name = ""
- elif (maintainer[0] == "<" and maintainer[-1:] == ">"):
- email = maintainer[1:-1]
- name = ""
- else:
- m = re_parse_maintainer.match(maintainer)
- if not m:
- raise ParseMaintError, "Doesn't parse as a valid Maintainer field."
- name = m.group(1)
- email = m.group(2)
-
- # Get an RFC2047 compliant version of the name
- rfc2047_name = rfc2047_encode(name)
-
- # Force the name to be UTF-8
- name = force_to_utf8(name)
-
- if name.find(',') != -1 or name.find('.') != -1:
- rfc822_maint = "%s (%s)" % (email, name)
- rfc2047_maint = "%s (%s)" % (email, rfc2047_name)
- else:
- rfc822_maint = "%s <%s>" % (name, email)
- rfc2047_maint = "%s <%s>" % (rfc2047_name, email)
-
- if email.find("@") == -1 and email.find("buildd_") != 0:
- raise ParseMaintError, "No @ found in email address part."
-
- return (rfc822_maint, rfc2047_maint, name, email)
-
-################################################################################
-
def send_mail (message, filename=""):
"""sendmail wrapper, takes _either_ a message string or a file as arguments"""
os.write (fd, message)
os.close (fd)
+ if Cnf.has_key("Dinstall::MailWhiteList") and \
+ Cnf["Dinstall::MailWhiteList"] != "":
+ message_in = open_file(filename)
+ message_raw = modemail.message_from_file(message_in)
+ message_in.close();
+
+ whitelist = [];
+ whitelist_in = open_file(Cnf["Dinstall::MailWhiteList"])
+ try:
+ for line in whitelist_in:
+ if not re_whitespace_comment.match(line):
+ if re_re_mark.match(line):
+ whitelist.append(re.compile(re_re_mark.sub("", line.strip(), 1)))
+ else:
+ whitelist.append(re.compile(re.escape(line.strip())))
+ finally:
+ whitelist_in.close()
+
+ # Fields to check.
+ fields = ["To", "Bcc", "Cc"]
+ for field in fields:
+ # Check each field
+ value = message_raw.get(field, None)
+ if value != None:
+ match = [];
+ for item in value.split(","):
+ (rfc822_maint, rfc2047_maint, name, email) = fix_maintainer(item.strip())
+ mail_whitelisted = 0
+ for wr in whitelist:
+ if wr.match(email):
+ mail_whitelisted = 1
+ break
+ if not mail_whitelisted:
+ print "Skipping %s since it's not in %s" % (item, Cnf["Dinstall::MailWhiteList"])
+ continue
+ match.append(item)
+
+ # Doesn't have any mail in whitelist so remove the header
+ if len(match) == 0:
+ del message_raw[field]
+ else:
+ message_raw.replace_header(field, string.join(match, ", "))
+
+ # Change message fields in order if we don't have a To header
+ if not message_raw.has_key("To"):
+ fields.reverse()
+ for field in fields:
+ if message_raw.has_key(field):
+ message_raw[fields[-1]] = message_raw[field]
+ del message_raw[field]
+ break
+ else:
+ # Clean up any temporary files
+ # and return, as we removed all recipients.
+ if message:
+ os.unlink (filename);
+ return;
+
+ fd = os.open(filename, os.O_RDWR|os.O_EXCL, 0700);
+ os.write (fd, message_raw.as_string(True));
+ os.close (fd);
+
# Invoke sendmail
(result, output) = commands.getstatusoutput("%s < %s" % (Cnf["Dinstall::SendmailCommand"], filename))
if (result != 0):
def which_conf_file ():
res = socket.gethostbyaddr(socket.gethostname())
+ # In case we allow local config files per user, try if one exists
+ if Cnf.FindB("Config::" + res[0] + "::AllowLocalConfig"):
+ homedir = os.getenv("HOME")
+ confpath = os.path.join(homedir, "/etc/dak.conf")
+ if os.path.exists(confpath):
+ apt_pkg.ReadConfigFileISC(Cnf,default_config)
+
+ # We are still in here, so there is no local config file or we do
+ # not allow local files. Do the normal stuff.
if Cnf.get("Config::" + res[0] + "::DakConfig"):
return Cnf["Config::" + res[0] + "::DakConfig"]
else:
def which_apt_conf_file ():
res = socket.gethostbyaddr(socket.gethostname())
+ # In case we allow local config files per user, try if one exists
+ if Cnf.FindB("Config::" + res[0] + "::AllowLocalConfig"):
+ homedir = os.getenv("HOME")
+ confpath = os.path.join(homedir, "/etc/dak.conf")
+ if os.path.exists(confpath):
+ apt_pkg.ReadConfigFileISC(Cnf,default_config)
+
if Cnf.get("Config::" + res[0] + "::AptConfig"):
return Cnf["Config::" + res[0] + "::AptConfig"]
else:
if len(args) >= 1:
timestamp = args[0]
if timestamp.count("T") == 0:
- expiredate = time.strftime("%Y-%m-%d", time.gmtime(timestamp))
+ try:
+ expiredate = time.strftime("%Y-%m-%d", time.gmtime(float(timestamp)))
+ except ValueError:
+ expiredate = "unknown (%s)" % (timestamp)
else:
expiredate = timestamp
reject("The key used to sign %s has expired on %s" % (sig_filename, expiredate))
################################################################################
+def temp_dirname(parent=None, prefix="dak", suffix=""):
+ """
+ Return a secure and unique directory by pre-creating it.
+ If 'parent' is non-null, it will be the directory the directory is pre-created in.
+ If 'prefix' is non-null, the filename will be prefixed with it, default is dak.
+ If 'suffix' is non-null, the filename will end with it.
+
+ Returns a pathname to the new directory
+ """
+
+ return tempfile.mkdtemp(suffix, prefix, parent)
+
+################################################################################
+
def is_email_alias(email):
""" checks if the user part of the email is listed in the alias file """
global alias_cache
################################################################################
+def get_changes_files(dir):
+ """
+ Takes a directory and lists all .changes files in it (as well as chdir'ing
+ to the directory; this is due to broken behaviour on the part of p-u/p-a
+ when you're not in the right place)
+
+ Returns a list of filenames
+ """
+ try:
+ # Much of the rest of p-u/p-a depends on being in the right place
+ os.chdir(dir)
+ changes_files = [x for x in os.listdir(dir) if x.endswith('.changes')]
+ except OSError, e:
+ fubar("Failed to read list from directory %s (%s)" % (dir, e))
+
+ return changes_files
+
+################################################################################
+
apt_pkg.init()
Cnf = apt_pkg.newConfiguration()
if which_conf_file() != default_config:
apt_pkg.ReadConfigFileISC(Cnf,which_conf_file())
-################################################################################
+###############################################################################