def run_delete(args): patchfns.chdir_to_base_dir() if args.patch: patch = patchfns.find_patch(args.patch) if not patch: return cmd_result.ERROR else: patch = patchfns.top_patch() if args.opt_next: patch =patchfns.patch_after(patch) if not patch: output.error('No next patch\n') return cmd_result.ERROR if not patch: patchfns.find_top_patch() return cmd_result.ERROR if patchfns.is_applied(patch): if patch != patchfns.top_patch(): output.error('Patch %s is currently applied\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if patchfns.pyquilt_command('pop -qf') != cmd_result.OK: return cmd_result.ERROR if patchfns.remove_from_series(patch): output.write('Removed patch %s\n' % patchfns.print_patch(patch)) else: output.error('Failed to remove patch %s\n' % patchfns.print_patch(patch)) return cmd_result.ERROR patch_file = patchfns.patch_file_name(patch) if args.opt_remove and os.path.exists(patch_file): if args.opt_backup: try: os.rename(patch_file, patch_file + '~') except IOError: output.error('Failed to backup patch file %s\n' % patch_file) return cmd_result.ERROR else: try: os.remove(patch_file) except IOError: output.error('Failed to remove patch file %s\n' % patch_file) return cmd_result.ERROR return cmd_result.OK
def run_mail(args): patchfns.chdir_to_base_dir() if not shell.which('formail'): output.write("You have to install 'formail' to use 'quilt mail'") return cmd_result.ERROR if not args.opt_signature or args.opt_signature == '-': args.opt_signature = None else: try: args.opt_signature = open(args.opt_signature).read() except IOError as edata: output.perror(edata) if args.first_patch: args.first_patch = patchfns.find_first_patch() if args.first_patch == '-' else patchfns.find_patch(args.first_patch) if not args.first_patch: return cmd_result.ERROR if not args.last_patch: args.last_patch = args.first_patch else: args.last_patch = patchfns.find_last_patch() if args.last_patch == '-' else patchfns.find_patch(args.last_patch) if not args.last_patch: return cmd_result.ERROR if not args.opt_sender: hostname = socket.gethostname() args.opt_sender = '%s@%s' % (get_login_name(), hostname) if not re.match('^\S+@\S+\.\S+$', args.opt_sender): output.error('Could not determine the envelope sender address. Please use --sender.\n') return cmd_result.ERROR _dummy, args.opt_sender_address = email.utils.parseaddr(args.opt_sender) if not args.opt_charset: lc_all = os.getenv('LC_ALL', patchfns.ORIGINAL_LANG) if lc_all and lc_all.endswith('UTF-8'): args.opt_charset = 'UTF-8' else: args.opt_charset = 'ISO-8859-15' patches = patchfns.cat_series() if args.first_patch: first_index = patches.index(args.first_patch) last_index = patches.index(args.last_patch) if last_index < first_index: output.error('Patch %s not applied before patch %s\n' % (patchfns.print_patch(args.first_patch), patchfns.print_patch(args.first_patch))) return cmd_result.ERROR patches = patches[first_index:last_index + 1] total = len(patches) tmpdir = patchfns.gen_tempfile(asdir=True) atexit.register(lambda: not os.path.exists(tmpdir) or shutil.rmtree(tmpdir, ignore_errors=True)) subject_map = {} patch_msgs = [] for patch in patches: contents = fsutils.get_file_contents(patchfns.patch_file_name(patch)) mailmsg = message_from_patch(contents, args.opt_charset) if mailmsg is False: subject = None else: patch_msgs.append(mailmsg) subject = mailmsg['Replace-Subject'] if mailmsg is False or not subject: output.error('Unable to extract a subject header from %s\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if subject in subject_map: subject_map[subject].append(patch) else: subject_map[subject] = [patch] if len(subject_map) != len(patches): duplicates = [] for key in sorted(subject_map): plist = subject_map[key] if len(plist) > 1: duplicates += plist output.error('Patches %s have duplicate subject headers.\n' % ', '.join([patchfns.print_patch(dup) for dup in duplicates])) return cmd_result.ERROR if args.opt_reply_to: if not os.path.exists(args.opt_reply_to): output.error('File %s does not exist\n' % args.opt_reply_to) return cmd_result.ERROR args.opt_reply_to = email.message_from_string(open(args.opt_reply_to).read()) if not args.opt_subject: repto_subject = args.opt_reply_to['Subject'] args.opt_subject = 'Re: %s' % re.sub('^([ \t]*[rR][eE]:[ \t]*)', '', repto_subject) intro = 'Message-Id: <%s>\n' % msgid(args) intro += 'User-Agent: pyquilt\n' last_ts = time.localtime() intro += time.strftime('Date: %a, %d %b %Y %H:%M:%S %z\n', last_ts) intro += 'From: %s\n' % (args.opt_from if args.opt_from else args.opt_sender) intro += 'To: %s\n' % (', '.join(args.opt_to) if args.opt_to else '') intro += 'Cc: %s\n' % (', '.join(args.opt_cc) if args.opt_cc else '') intro += 'Bcc: %s\n' % (', '.join(args.opt_bcc) if args.opt_bcc else '') if args.opt_reply_to: intro += in_reply_to_header(args.opt_reply_to) intro += references_header(args.opt_reply_to) intro += 'Subject-Prefix: [%s @num@/@total@]\n' % args.opt_prefix intro += 'Subject: %s\n\n' % (args.opt_subject if args.opt_subject else '') intro += ('%s\n\n' % args.opt_message) if args.opt_message else '' intro += ('-- \n%s\n' % args.opt_signature) if args.opt_signature else '' intro_message = email.message_from_string(intro) intro_message.set_charset(args.opt_charset) if not args.opt_message: introfile = patchfns.gen_tempfile() open(introfile, 'w').write(intro_message.as_string()) result = shell.run_cmd('%s %s' % (os.getenv('EDITOR'), introfile)) output.write(result.stdout) output.error(result.stderr) intro_message = email.message_from_string(open(introfile).read(), charset=args.opt_charset) os.remove(introfile) if result.eflags != 0: return cmd_result.ERROR subject = join_lines(intro_message['Subject']) if not subject: if not args.opt_message: savefile = patchfns.gen_tempfile() open(savefile, 'w').write(intro_message.as_string()) output.error('Introduction has no subject header (saved as %s)\n' % savefile) else: output.error('Introduction has no subject header\n') return cmd_result.ERROR if args.opt_mbox: fsutils.touch(args.opt_mbox) subject_prefix = email.utils.quote(join_lines(intro_message['Subject-Prefix'])) subject_prefix += ' ' if subject_prefix else '' subject_prefix = re.sub('@total@', str(total), subject_prefix) del intro_message['Subject-Prefix'] pnum_fmt = '{0:0%s}' % len(str(total)) pfx = re.sub('@num@', pnum_fmt.format(0), subject_prefix) intro_message.replace_header('Subject', pfx + intro_message['Subject']) remove_empty_headers(intro_message) for key in ['To', 'Cc', 'Bcc']: # Consolidate up the various recipient fields values = intro_message.get_all(key) if values: del intro_message[key] intro_message[key] = ', '.join(values) process_mail(intro_message, args) pnum = 0 for msg in patch_msgs: msg.add_header('Content-Disposition', 'inline', filename=patches[pnum]) for key in intro_message.keys(): if key.lower() not in ['message-id', 'references', 'in-reply-to', 'subject']: for value in intro_message.get_all(key): msg[key] = value msg['References'] = get_reference_to(intro_message) msg.set_charset(args.opt_charset) for aclass in ['To', 'Cc', 'Bcc']: rclass = 'Recipient-' + aclass if msg.has_key(rclass): msg[aclass] = ',\n '.join(msg.get_all(rclass)) del msg[rclass] pnum += 1 ppfx = re.sub('@num@', pnum_fmt.format(pnum), subject_prefix) msg['Message-Id'] = msgid(args) msg['Subject'] = '%s%s' % (ppfx, msg['Replace-Subject']) if ppfx else msg['Replace-Subject'] del msg['Replace-Subject'] remove_empty_headers(msg) process_mail(msg, args) return cmd_result.OK