def mail_addresses_for_upload(maintainer, changed_by, fingerprint): """mail addresses to contact for an upload @type maintainer: str @param maintainer: Maintainer field of the .changes file @type changed_by: str @param changed_by: Changed-By field of the .changes file @type fingerprint: str @param fingerprint: fingerprint of the key used to sign the upload @rtype: list of str @return: list of RFC 2047-encoded mail addresses to contact regarding this upload """ addresses = [maintainer] if changed_by != maintainer: addresses.append(changed_by) fpr_addresses = gpg_get_key_addresses(fingerprint) if len(fpr_addresses) > 0 and fix_maintainer(changed_by)[3] not in fpr_addresses and fix_maintainer(maintainer)[3] not in fpr_addresses: addresses.append(fpr_addresses[0]) encoded_addresses = [ fix_maintainer(e)[1] for e in addresses ] return encoded_addresses
def mail_addresses_for_upload(maintainer, changed_by, fingerprint): """mail addresses to contact for an upload @type maintainer: str @param maintainer: Maintainer field of the .changes file @type changed_by: str @param changed_by: Changed-By field of the .changes file @type fingerprint: str @param fingerprint: fingerprint of the key used to sign the upload @rtype: list of str @return: list of RFC 2047-encoded mail addresses to contact regarding this upload """ addresses = [maintainer] if changed_by != maintainer: addresses.append(changed_by) fpr_addresses = gpg_get_key_addresses(fingerprint) if len(fpr_addresses) > 0 and fix_maintainer( changed_by)[3] not in fpr_addresses and fix_maintainer( maintainer)[3] not in fpr_addresses: addresses.append(fpr_addresses[0]) encoded_addresses = [fix_maintainer(e)[3] for e in addresses] return encoded_addresses
def mail_addresses_for_upload(maintainer, changed_by, fingerprint): """mail addresses to contact for an upload @type maintainer: str @param maintainer: Maintainer field of the .changes file @type changed_by: str @param changed_by: Changed-By field of the .changes file @type fingerprint: str @param fingerprint: fingerprint of the key used to sign the upload @rtype: list of str @return: list of RFC 2047-encoded mail addresses to contact regarding this upload """ recipients = Cnf.value_list('Dinstall::UploadMailRecipients') if not recipients: recipients = [ 'maintainer', 'changed_by', 'signer', ] # Ensure signer is last if present try: recipients.remove('signer') recipients.append('signer') except ValueError: pass # Compute the set of addresses of the recipients addresses = set() # Name + email emails = set() # Email only, used to avoid duplicates for recipient in recipients: if recipient.startswith('mail:'): # Email hardcoded in config address = recipient[5:] elif recipient == 'maintainer': address = maintainer elif recipient == 'changed_by': address = changed_by elif recipient == 'signer': fpr_addresses = gpg_get_key_addresses(fingerprint) address = fpr_addresses[0] if fpr_addresses else None if any(x in emails for x in fpr_addresses): # The signer already gets a copy via another email address = None else: raise Exception('Unsupported entry in {0}: {1}'.format( 'Dinstall::UploadMailRecipients', recipient)) if address is not None: email = fix_maintainer(address)[3] if email not in emails: addresses.add(address) emails.add(email) encoded_addresses = [fix_maintainer(e)[1] for e in addresses] return encoded_addresses
def send_mail (message, filename="", whitelists=None): """sendmail wrapper, takes _either_ a message string or a file as arguments @type whitelists: list of (str or None) @param whitelists: path to whitelists. C{None} or an empty list whitelists everything, otherwise an address is whitelisted if it is included in any of the lists. In addition a global whitelist can be specified in Dinstall::MailWhiteList. """ maildir = Cnf.get('Dir::Mail') if maildir: path = os.path.join(maildir, datetime.datetime.now().isoformat()) path = find_next_free(path) with open(path, 'w') as fh: print >>fh, message, # Check whether we're supposed to be sending mail if Cnf.has_key("Dinstall::Options::No-Mail") and Cnf["Dinstall::Options::No-Mail"]: return # If we've been passed a string dump it into a temporary file if message: (fd, filename) = tempfile.mkstemp() os.write (fd, message) os.close (fd) if whitelists is None or None in whitelists: whitelists = [] if Cnf.get('Dinstall::MailWhiteList', ''): whitelists.append(Cnf['Dinstall::MailWhiteList']) if len(whitelists) != 0: with open_file(filename) as message_in: message_raw = modemail.message_from_file(message_in) whitelist = []; for path in whitelists: with open_file(path, 'r') as whitelist_in: 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()))) # 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 {0} since it's not whitelisted".format(item) 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, ', '.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, 0o700); 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): raise SendmailFailedError(output) # Clean up any temporary files if message: os.unlink (filename)
def send_mail (message, filename="", whitelists=None): """sendmail wrapper, takes _either_ a message string or a file as arguments @type whitelists: list of (str or None) @param whitelists: path to whitelists. C{None} or an empty list whitelists everything, otherwise an address is whitelisted if it is included in any of the lists. In addition a global whitelist can be specified in Dinstall::MailWhiteList. """ maildir = Cnf.get('Dir::Mail') if maildir: path = os.path.join(maildir, datetime.datetime.now().isoformat()) path = find_next_free(path) with open(path, 'w') as fh: print >>fh, message, # Check whether we're supposed to be sending mail if "Dinstall::Options::No-Mail" in Cnf and Cnf["Dinstall::Options::No-Mail"]: return # If we've been passed a string dump it into a temporary file if message: (fd, filename) = tempfile.mkstemp() os.write (fd, message) os.close (fd) if whitelists is None or None in whitelists: whitelists = [] if Cnf.get('Dinstall::MailWhiteList', ''): whitelists.append(Cnf['Dinstall::MailWhiteList']) if len(whitelists) != 0: with open_file(filename) as message_in: message_raw = modemail.message_from_file(message_in) whitelist = []; for path in whitelists: with open_file(path, 'r') as whitelist_in: 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()))) # 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 {0} since it's not whitelisted".format(item) 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, ', '.join(match)) # Change message fields in order if we don't have a To header if "To" not in message_raw: fields.reverse() for field in fields: if field in message_raw: 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, 0o700); 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): raise SendmailFailedError(output) # Clean up any temporary files if message: os.unlink (filename)