def exec_and_parse_bugscript(handler, bugscript): """Execute and parse the output of the package bugscript, in particular identifying the headers and pseudo-headers blocks, if present""" fh, filename = TempFile() fh.close() rc = os.system('LC_ALL=C %s %s %s' % (handler, commands.mkarg(bugscript), commands.mkarg(filename))) isheaders = False ispseudoheaders = False headers = pseudoheaders = text = '' fp = open(filename) for line in fp.readlines(): # we identify the blocks for headers and pseudo-h if line == '-- BEGIN HEADERS --\n': isheaders = True elif line == '-- END HEADERS --\n': isheaders = False elif line == '-- BEGIN PSEUDOHEADERS --\n': ispseudoheaders = True elif line == '-- END PSEUDOHEADERS --\n': ispseudoheaders = False else: if isheaders: headers += line elif ispseudoheaders: pseudoheaders += line else: text += line fp.close() cleanup_temp_file(filename) text = text.decode('utf-8', 'replace') return (rc, headers, pseudoheaders, text)
def sign_message(body, fromaddr, package='x', pgp_addr=None, sign='gpg', draftpath=None): '''Sign message with pgp key.''' ''' Return: a signed body. On failure, return None. kw need to have the following keys ''' if not pgp_addr: pgp_addr = get_email_addr(fromaddr)[1] # Make the unsigned file first (unsigned, file1) = TempFile(prefix=tempfile_prefix(package, 'unsigned'), dir=draftpath) unsigned.write(body) unsigned.close() # Now make the signed file (signed, file2) = TempFile(prefix=tempfile_prefix(package, 'signed'), dir=draftpath) signed.close() if sign == 'gpg': os.unlink(file2) if 'GPG_AGENT_INFO' not in os.environ: signcmd = "gpg --local-user '%s' --clearsign " % pgp_addr else: signcmd = "gpg --local-user '%s' --use-agent --clearsign " % pgp_addr signcmd += '--output '+commands.mkarg(file2)+ ' ' + commands.mkarg(file1) else: signcmd = "pgp -u '%s' -fast" % pgp_addr signcmd += '<'+commands.mkarg(file1)+' >'+commands.mkarg(file2) try: os.system(signcmd) x = file(file2, 'r') signedbody = x.read() x.close() if os.path.exists(file1): os.unlink(file1) if os.path.exists(file2): os.unlink(file2) if not signedbody: raise NoMessage body = signedbody except (NoMessage, IOError, OSError): fh, tmpfile2 = TempFile(prefix=tempfile_prefix(package), dir=draftpath) fh.write(body) fh.close() ewrite('gpg/pgp failed; input file in %s\n', tmpfile2) body = None return body
def sign_message(body, fromaddr, package='x', pgp_addr=None, sign='gpg', draftpath=None): '''Sign message with pgp key.''' ''' Return: a signed body. On failure, return None. kw need to have the following keys ''' if not pgp_addr: pgp_addr = get_email_addr(fromaddr)[1] # Make the unsigned file first (unsigned, file1) = TempFile(prefix=tempfile_prefix(package, 'unsigned'), dir=draftpath) unsigned.write(body) unsigned.close() # Now make the signed file (signed, file2) = TempFile(prefix=tempfile_prefix(package, 'signed'), dir=draftpath) signed.close() if sign == 'gpg': os.unlink(file2) if 'GPG_AGENT_INFO' not in os.environ: signcmd = "gpg --local-user '%s' --clearsign " % pgp_addr else: signcmd = "gpg --local-user '%s' --use-agent --clearsign " % pgp_addr signcmd += '--output ' + commands.mkarg(file2) + ' ' + commands.mkarg( file1) else: signcmd = "pgp -u '%s' -fast" % pgp_addr signcmd += '<' + commands.mkarg(file1) + ' >' + commands.mkarg(file2) try: os.system(signcmd) x = file(file2, 'r') signedbody = x.read() x.close() if os.path.exists(file1): os.unlink(file1) if os.path.exists(file2): os.unlink(file2) if not signedbody: raise NoMessage body = signedbody except (NoMessage, IOError, OSError): fh, tmpfile2 = TempFile(prefix=tempfile_prefix(package), dir=draftpath) fh.write(body) fh.close() ewrite('gpg/pgp failed; input file in %s\n', tmpfile2) body = None return body
def exec_and_parse_bugscript(handler, bugscript): """Execute and parse the output of the package bugscript, in particular identifying the headers and pseudo-headers blocks, if present""" fh, filename = TempFile() fh.close() rc = os.system( 'LC_ALL=C %s %s %s' % (handler, commands.mkarg(bugscript), commands.mkarg(filename))) isheaders = False ispseudoheaders = False isattachments = False headers = pseudoheaders = text = '' attachments = [] fp = open(filename) for line in fp.readlines(): # we identify the blocks for headers and pseudo-h if line == '-- BEGIN HEADERS --\n': isheaders = True elif line == '-- END HEADERS --\n': isheaders = False elif line == '-- BEGIN PSEUDOHEADERS --\n': ispseudoheaders = True elif line == '-- END PSEUDOHEADERS --\n': ispseudoheaders = False elif line == '-- BEGIN ATTACHMENTS --\n': isattachments = True elif line == '-- END ATTACHMENTS --\n': isattachments = False else: if isheaders: headers += line elif ispseudoheaders: pseudoheaders += line elif isattachments: attachments.append(line.strip()) else: text += line fp.close() cleanup_temp_file(filename) text = text.decode('utf-8', 'replace') return (rc, headers, pseudoheaders, text, attachments)
def launch_mbox_reader(cmd, url, http_proxy, timeout): """Runs the command specified by cmd passing the mbox file downloaded from url as a parameter. If cmd is None or fails, then fallback to mail program.""" mbox = open_url(url, http_proxy, timeout) if mbox is None: return (fd, fname) = TempFile() try: for line in mbox: fd.write(line) fd.close() if cmd is not None: try: cmd = cmd % fname except TypeError: cmd = "%s %s" % (cmd, fname) error = os.system(cmd) if not error: return #fallback os.system('mail -f ' + fname) finally: os.unlink(fname)
def send_report(body, attachments, mua, fromaddr, sendto, ccaddr, bccaddr, headers, package='x', charset="us-ascii", mailing=True, sysinfo=None, rtype='debbugs', exinfo=None, replyto=None, printonly=False, template=False, outfile=None, mta='', kudos=False, smtptls=False, smtphost='localhost', smtpuser=None, smtppasswd=None, paranoid=False, draftpath=None): '''Send a report.''' failed = using_sendmail = False msgname = '' # Disable smtphost if mua is set if mua and smtphost: smtphost = '' # No, I'm not going to do a full MX lookup on every address... get a # real MTA! if kudos and smtphost == 'reportbug.debian.org': smtphost = 'packages.debian.org' body_charset = charset if isinstance(body, unicode): # Since the body is Unicode, utf-8 seems like a sensible body encoding # to choose pretty much all the time. body = body.encode('utf-8', 'replace') body_charset = 'utf-8' tfprefix = tempfile_prefix(package) if attachments and not mua: (message, failed) = mime_attach(body, attachments, charset, body_charset) if failed: ewrite("Error: Message creation failed, not sending\n") mua = mta = smtphost = None else: message = BetterMIMEText(body, _charset=body_charset) # Standard headers message['From'] = rfc2047_encode_address(fromaddr, 'utf-8', mua) message['To'] = rfc2047_encode_address(sendto, charset, mua) for (header, value) in headers: if header in ['From', 'To', 'Cc', 'Bcc', 'X-Debbugs-CC', 'Reply-To', 'Mail-Followup-To']: message[header] = rfc2047_encode_address(value, charset, mua) else: message[header] = rfc2047_encode_header(value, charset, mua) if ccaddr: message['Cc'] = rfc2047_encode_address(ccaddr, charset, mua) if bccaddr: message['Bcc'] = rfc2047_encode_address(bccaddr, charset, mua) replyto = os.environ.get("REPLYTO", replyto) if replyto: message['Reply-To'] = rfc2047_encode_address(replyto, charset, mua) if mailing: message['Message-ID'] = email.Utils.make_msgid('reportbug') message['X-Mailer'] = VERSION message['Date'] = email.Utils.formatdate(localtime=True) elif mua and not (printonly or template): message['X-Reportbug-Version'] = VERSION_NUMBER addrs = [str(x) for x in (message.get_all('To', []) + message.get_all('Cc', []) + message.get_all('Bcc', []))] alist = email.Utils.getaddresses(addrs) cclist = [str(x) for x in message.get_all('X-Debbugs-Cc', [])] debbugs_cc = email.Utils.getaddresses(cclist) if cclist: del message['X-Debbugs-Cc'] addrlist = ', '.join(cclist) message['X-Debbugs-Cc'] = rfc2047_encode_address(addrlist, charset, mua) # Drop any Bcc headers from the message to be sent if not outfile and not mua: try: del message['Bcc'] except: pass message = message.as_string() if paranoid and not (template or printonly): pager = os.environ.get('PAGER', 'sensible-pager') os.popen(pager, 'w').write(message) if not ui.yes_no('Does your report seem satisfactory', 'Yes, send it.', 'No, don\'t send it.'): smtphost = mta = None filename = None if template or printonly: pipe = sys.stdout elif mua: pipe, filename = TempFile(prefix=tfprefix, dir=draftpath) elif outfile or not mta or not os.path.exists(mta): msgname = outfile or ('/var/tmp/%s.bug' % package) if os.path.exists(msgname): try: os.rename(msgname, msgname+'~') except OSError: ewrite('Unable to rename existing %s as %s~\n', msgname, msgname) try: pipe = open_write_safe(msgname, 'w') except OSError: fh, newmsgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message.as_string()) fh.close() ewrite('Writing to %s failed; ' 'wrote bug report to %s\n', msgname, newmsgname) msgname = newmsgname elif mta and not smtphost: try: x = os.getcwd() except OSError: os.chdir('/') malist = [commands.mkarg(a[1]) for a in alist] jalist = ' '.join(malist) faddr = rfc822.parseaddr(fromaddr)[1] ewrite("Sending message via %s...\n", mta) pipe = os.popen('%s -f %s -oi -oem %s' % ( mta, commands.mkarg(faddr), jalist), 'w') using_sendmail = True if smtphost: toaddrs = [x[1] for x in alist] smtp_message = re.sub(r'(?m)^[.]', '..', message) tryagain = True refused = None retry = 0 while tryagain: tryagain = False ewrite("Connecting to %s via SMTP...\n", smtphost) try: conn = None # if we're using reportbug.debian.org, send mail to # submit if smtphost.lower() == 'reportbug.debian.org': conn = smtplib.SMTP(smtphost,587) else: conn = smtplib.SMTP(smtphost) response = conn.ehlo() if not (200 <= response[0] <= 299): conn.helo() if smtptls: conn.starttls() response = conn.ehlo() if not (200 <= response[0] <= 299): conn.helo() if smtpuser: if not smtppasswd: smtppasswd = ui.get_password( 'Enter SMTP password for %s@%s: ' % (smtpuser, smtphost)) conn.login(smtpuser, smtppasswd) refused = conn.sendmail(fromaddr, toaddrs, smtp_message) conn.quit() except (socket.error, smtplib.SMTPException), x: # If wrong password, try again... if isinstance(x, smtplib.SMTPAuthenticationError): ewrite('SMTP error: authentication failed. Try again.\n') tryagain = True smtppasswd = None retry += 1 if retry <= 2: continue else: tryagain = False # In case of failure, ask to retry or to save & exit if ui.yes_no('SMTP send failure: %s. Do you want to retry (or else save the report and exit)?' % x, 'Yes, please retry.', 'No, save and exit.'): tryagain = True continue else: failed = True fh, msgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message) fh.close() ewrite('Wrote bug report to %s\n', msgname) # Handle when some recipients are refused. if refused: for (addr, err) in refused.iteritems(): ewrite('Unable to send report to %s: %d %s\n', addr, err[0], err[1]) fh, msgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message) fh.close() ewrite('Wrote bug report to %s\n', msgname)
fh.close() ewrite('Wrote bug report to %s\n', msgname) else: try: pipe.write(message) pipe.flush() if msgname: ewrite("Bug report written as %s\n", msgname) except IOError: failed = True pipe.close() if failed or (pipe.close() and using_sendmail): failed = True fh, msgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message) fh.close() ewrite('Original write failed, wrote bug report to %s\n', msgname) if mua: ewrite("Spawning %s...\n", mua.name) returnvalue = 0 succeeded = False while not succeeded: returnvalue = mua.send(filename) if returnvalue != 0: ewrite("Mutt users should be aware it is mandatory to edit the draft before sending.\n") mtitle = 'Report has not been sent yet; what do you want to do now?' mopts = 'Eq' moptsdesc = {'e' : 'Edit the message.',
def send_report(body, attachments, mua, fromaddr, sendto, ccaddr, bccaddr, headers, package='x', charset="us-ascii", mailing=True, sysinfo=None, rtype='debbugs', exinfo=None, replyto=None, printonly=False, template=False, outfile=None, mta='', kudos=False, smtptls=False, smtphost='localhost', smtpuser=None, smtppasswd=None, paranoid=False, draftpath=None, envelopefrom=None): '''Send a report.''' failed = using_sendmail = False msgname = '' # Disable smtphost if mua is set if mua and smtphost: smtphost = '' # No, I'm not going to do a full MX lookup on every address... get a # real MTA! if kudos and smtphost == 'reportbug.debian.org': smtphost = 'packages.debian.org' body_charset = charset if isinstance(body, unicode): # Since the body is Unicode, utf-8 seems like a sensible body encoding # to choose pretty much all the time. body = body.encode('utf-8', 'replace') body_charset = 'utf-8' tfprefix = tempfile_prefix(package) if attachments and not mua: (message, failed) = mime_attach(body, attachments, charset, body_charset) if failed: ewrite("Error: Message creation failed, not sending\n") mua = mta = smtphost = None else: message = BetterMIMEText(body, _charset=body_charset) # Standard headers message['From'] = rfc2047_encode_address(fromaddr, 'utf-8', mua) message['To'] = rfc2047_encode_address(sendto, charset, mua) for (header, value) in headers: if header in [ 'From', 'To', 'Cc', 'Bcc', 'X-Debbugs-CC', 'Reply-To', 'Mail-Followup-To' ]: message[header] = rfc2047_encode_address(value, charset, mua) else: message[header] = rfc2047_encode_header(value, charset, mua) if ccaddr: message['Cc'] = rfc2047_encode_address(ccaddr, charset, mua) if bccaddr: message['Bcc'] = rfc2047_encode_address(bccaddr, charset, mua) replyto = os.environ.get("REPLYTO", replyto) if replyto: message['Reply-To'] = rfc2047_encode_address(replyto, charset, mua) if mailing: message['Message-ID'] = email.Utils.make_msgid('reportbug') message['X-Mailer'] = VERSION message['Date'] = email.Utils.formatdate(localtime=True) elif mua and not (printonly or template): message['X-Reportbug-Version'] = VERSION_NUMBER addrs = [ str(x) for x in (message.get_all('To', []) + message.get_all('Cc', []) + message.get_all('Bcc', [])) ] alist = email.Utils.getaddresses(addrs) cclist = [str(x) for x in message.get_all('X-Debbugs-Cc', [])] debbugs_cc = email.Utils.getaddresses(cclist) if cclist: del message['X-Debbugs-Cc'] addrlist = ', '.join(cclist) message['X-Debbugs-Cc'] = rfc2047_encode_address( addrlist, charset, mua) # Drop any Bcc headers from the message to be sent if not outfile and not mua: try: del message['Bcc'] except: pass message = message.as_string() if paranoid and not (template or printonly): pager = os.environ.get('PAGER', 'sensible-pager') os.popen(pager, 'w').write(message) if not ui.yes_no('Does your report seem satisfactory', 'Yes, send it.', 'No, don\'t send it.'): smtphost = mta = None filename = None if template or printonly: pipe = sys.stdout elif mua: pipe, filename = TempFile(prefix=tfprefix, dir=draftpath) elif outfile or not ((mta and os.path.exists(mta)) or smtphost): msgname = outfile or ('/var/tmp/%s.bug' % package) if os.path.exists(msgname): try: os.rename(msgname, msgname + '~') except OSError: ewrite('Unable to rename existing %s as %s~\n', msgname, msgname) try: pipe = open_write_safe(msgname, 'w') except OSError: # we can't write to the selected file, use a temp file instead fh, newmsgname = TempFile(prefix=tfprefix, dir=draftpath) ewrite('Writing to %s failed; ' 'using instead %s\n', msgname, newmsgname) msgname = newmsgname # we just need a place where to write() and a file handler # is here just for that pipe = fh elif mta and not smtphost: try: x = os.getcwd() except OSError: os.chdir('/') malist = [commands.mkarg(a[1]) for a in alist] jalist = ' '.join(malist) faddr = rfc822.parseaddr(fromaddr)[1] if envelopefrom: envfrom = rfc822.parseaddr(envelopefrom)[1] else: envfrom = faddr ewrite("Sending message via %s...\n", mta) pipe = os.popen( '%s -f %s -oi -oem %s' % (mta, commands.mkarg(envfrom), jalist), 'w') using_sendmail = True if smtphost: toaddrs = [x[1] for x in alist] smtp_message = re.sub(r'(?m)^[.]', '..', message) tryagain = True refused = None retry = 0 while tryagain: tryagain = False ewrite("Connecting to %s via SMTP...\n", smtphost) try: conn = None # if we're using reportbug.debian.org, send mail to # submit if smtphost.lower() == 'reportbug.debian.org': conn = smtplib.SMTP(smtphost, 587) else: conn = smtplib.SMTP(smtphost) response = conn.ehlo() if not (200 <= response[0] <= 299): conn.helo() if smtptls: conn.starttls() response = conn.ehlo() if not (200 <= response[0] <= 299): conn.helo() if smtpuser: if not smtppasswd: smtppasswd = ui.get_password( 'Enter SMTP password for %s@%s: ' % (smtpuser, smtphost)) conn.login(smtpuser, smtppasswd) refused = conn.sendmail(fromaddr, toaddrs, smtp_message) conn.quit() except (socket.error, smtplib.SMTPException), x: # If wrong password, try again... if isinstance(x, smtplib.SMTPAuthenticationError): ewrite('SMTP error: authentication failed. Try again.\n') tryagain = True smtppasswd = None retry += 1 if retry <= 2: continue else: tryagain = False # In case of failure, ask to retry or to save & exit if ui.yes_no( 'SMTP send failure: %s. Do you want to retry (or else save the report and exit)?' % x, 'Yes, please retry.', 'No, save and exit.'): tryagain = True continue else: failed = True fh, msgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message) fh.close() ewrite('Wrote bug report to %s\n', msgname) # Handle when some recipients are refused. if refused: for (addr, err) in refused.iteritems(): ewrite('Unable to send report to %s: %d %s\n', addr, err[0], err[1]) fh, msgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message) fh.close() ewrite('Wrote bug report to %s\n', msgname)
fh.close() ewrite('Wrote bug report to %s\n', msgname) else: try: pipe.write(message) pipe.flush() if msgname: ewrite("Bug report written as %s\n", msgname) except IOError: failed = True pipe.close() if failed or (pipe.close() and using_sendmail): failed = True fh, msgname = TempFile(prefix=tfprefix, dir=draftpath) fh.write(message) fh.close() ui.long_message( 'Error: send/write operation failed, bug report ' 'saved to %s\n', msgname) if mua: ewrite("Spawning %s...\n", mua.name) returnvalue = 0 succeeded = False while not succeeded: returnvalue = mua.send(filename) if returnvalue != 0: ewrite( "Mutt users should be aware it is mandatory to edit the draft before sending.\n"