pax_global_header00006660000000000000000000000064115110735260014513gustar00rootroot0000000000000052 comment=07563c6eb65208a2c1c24e3b018a08ff552fbe0d pmailq-0.5/000077500000000000000000000000001151107352600126425ustar00rootroot00000000000000pmailq-0.5/AUTHORS000066400000000000000000000002021151107352600137040ustar00rootroot00000000000000pmailq - Postfix MAIL Queue manager =================================== Main developer : Emmanuel Bouthenot pmailq-0.5/CHANGELOG000066400000000000000000000011261151107352600140540ustar00rootroot00000000000000pmailq - Postfix MAIL Queue manager =================================== ChangeLog Version 0.5 (2011-01-05): * Some rewording in manpage. Version 0.4 (2010-12-29): * Replace the usage of the deprecated popen2.Popen3() with subprocess.Popen(). * Fix some errors and do some cleanup in manpage. Version 0.3 (2010-01-31): * Fix dead lock while processing a large amount of datas in mail queue Version 0.2 (2008-01-08): * Add Changelog * Fix typos in manpage * Fix exit code on errors (http://bugs.debian.org/457299) Version 0.1 (2007-11-27): * First release pmailq-0.5/COPYING000066400000000000000000000007741151107352600137050ustar00rootroot00000000000000 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar 14 rue de Plaisance, 75014 Paris, France Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. pmailq-0.5/Makefile000066400000000000000000000004141151107352600143010ustar00rootroot00000000000000 MANPAGE_SECTION = 8 all: man man: pmailq.${MANPAGE_SECTION} pmailq.${MANPAGE_SECTION}: pmailq.pod pod2man --center "" --date "" --release "" --section=${MANPAGE_SECTION} pmailq.pod > pmailq.${MANPAGE_SECTION} clean: rm -f pmailq.${MANPAGE_SECTION} .PHOMY: man pmailq-0.5/README000066400000000000000000000004171151107352600135240ustar00rootroot00000000000000pmailq - Postfix MAIL Queue manager =================================== see manpage for more informations Features -------- (see manpage) Copyright --------- (see AUTHORS file) Licence ------- pmailq is distributed under WTFPL (see COPYING file for complete license) pmailq-0.5/pmailq000077500000000000000000000214111151107352600140520ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # This program is free software. It comes without any warranty, to # the extent permitted by applicable law. You can redistribute it # and/or modify it under the terms of the Do What The Fuck You Want # To Public License, Version 2, as published by Sam Hocevar. See # http://sam.zoy.org/wtfpl/COPYING for more details. _NAME = 'pmailq' _HELP = "[OPTIONS] [ list | parse | del ]" _DESC = "%s postfix mail queue manager" % _NAME _VERSION = '0.3' _AUTHOR = 'Emmanuel Bouthenot ' MAILQ = "postqueue -p" DELQ = "postsuper -d" from optparse import OptionParser, OptionGroup # needs python >= 2.3 import sys, os, subprocess, fcntl, select, fnmatch class Proc: def run(self, command): proc = subprocess.Popen(command, bufsize=1, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) proc.stdin.close() outfile = proc.stdout outfd = outfile.fileno() errfile = proc.stderr errfd = errfile.fileno() # avoid deadlocks self.set_no_block(outfd) self.set_no_block(errfd) outdata = errdata = '' outeof = erreof = False while True: # wait for activity ready = select.select([outfd, errfd], [], []) if outfd in ready[0]: outchunk = outfile.read() if outchunk == '': outeof = True outdata = outdata + outchunk if errfd in ready[0]: errchunk = errfile.read() if errchunk == '': erreof = True errdata = errdata + errchunk if outeof and erreof: break # give a little time for buffers to fill select.select([],[],[],.1) err = proc.wait() return err, outdata, errdata def set_no_block(self, fd): fl = fcntl.fcntl(fd, fcntl.F_GETFL) try: fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY) except AttributeError: fcntl.fcntl(fd, fcntl.F_SETFL, fl | fcntl.FNDELAY) class Mailqueue: def __init__(self): self.mailqueue = [] self.filters = { 'email' : None, 'msg' : None, 'lowsize' : 0, 'upsize' : 0, 'active' : False, 'hold' : False } self.parse() def add_filter(self, key, value): self.filters[key] = value def parse(self): p_ret, p_stdout, p_stderr = Proc().run(MAILQ) # mail system down ? if p_ret != 0: sys.stderr.write ("ERR : %s\n" % ", ".join(p_stderr.strip().split("\n"))) sys.exit (-1) buffer = p_stdout.strip().split('\n'); # checking empty mail queue if len(buffer)>0 and buffer[0].strip() == "Mail queue is empty": sys.stderr.write ("INFO : %s\n" % buffer[0].strip()) return None # skip first and last line buffer = "\n".join(buffer[1:-1]).strip() for block in buffer.split("\n\n"): lines = block.split("\n") headers = lines[0].split(' ') # squeeze repeated spaces while '' in headers: headers.remove('') queue = [] dest = [] info = "" for expl in lines[1:]: expl = expl.strip() if expl.startswith("(") and expl.endswith(")"): if info == "": info = expl[1:len(expl)-1] if dest != []: queue.append({ "info" : info , "dest" : dest }) dest = [] info = expl[1:len(expl)-1] else: dest.append(expl.lower()) if dest != []: queue.append({ "info" : info , "dest" : dest }) self.mailqueue.append({ "id" : headers[0].rstrip("*!"), "active" : headers[0].endswith("*"), "hold" : headers[0].endswith("!"), "size" : headers[1], "date" : " ".join(headers[2:5]), "queue" : queue }) def check(self, size, active, hold, dest, infos): if self.filters['email'] != None: match = False for e in dest: if fnmatch.fnmatch(e.lower(), self.filters['email'].lower()): match = True if not match: return False if self.filters['msg'] != None: match = False for i in infos: if fnmatch.fnmatch(i.lower(), self.filters['msg'].lower()): match = True if not match: return False if self.filters['active'] and not active: return False if self.filters['hold'] and not hold: return False if self.filters['lowsize'] != 0 and int(size) > self.filters['lowsize']: return False if self.filters['upsize'] != 0 and int(size) < self.filters['upsize']: return False return True def cmd_list(self): for m in self.mailqueue: out = "%s\n" % m['id'] out += " -date: %s\n" % m['date'] out += " -size: %s\n" % m['size'] out += " -active: %s\n" % str(m['active']) out += " -hold: %s\n" % str(m['hold']) out += " -to:\n" to = [] i = [] for n in m['queue']: i.append(n['info']) to += n['dest'] out += " + %s : [%s]\n" % (",".join(n['dest']), n['info']) if self.check(m['size'], m['active'], m['hold'], to, i): print out def cmd_parse(self): for m in self.mailqueue: e = [] i = [] for n in m['queue']: i.append(n['info']) for o in n['dest']: e.append(o) if self.check(m['size'], m['active'], m['hold'], e, i): print "%s|%s|%s|%d|%d|%s" % (m['id'], m['date'], m['size'], int(m['active']), int(m['hold']), ",".join(n['dest'])) def cmd_del(self): for m in self.mailqueue: e = [] i=[] for n in m['queue']: i.append(n['info']) for o in n['dest']: e.append(o) if self.check(m['size'], m['active'], m['hold'], e, i): proc = popen2.Popen3("%s %s" % (DELQ, m['id']), True) p_ret = proc.wait() if p_ret != 0: print "deleting %s [FAILED] (%s)" % (m['id'], "".join(proc.childerr.readlines()).strip()) else: print "deleting %s [OK]" % m['id'] def main(): usage = "%prog " + _HELP desc = _DESC parser = OptionParser(usage=usage, description=desc, version=("%s %s" % (_NAME, _VERSION))) opts = OptionGroup(parser, "filters") opts.add_option("-e", "--email", dest="email", type="string", metavar="PATTERN", help="select entries in queue with email matching PATTERN") parser.set_defaults(email=None) opts.add_option("-m", "--msg", dest="msg", type="string", metavar="PATTERN", help="select entries in queue with error message matching PATTERN") parser.set_defaults(msg=None) opts.add_option("-l", "--size-lower", dest="lowsize", type="int", metavar="SIZE", help="select entries in queue with size lower than SIZE bytes") parser.set_defaults(lowsize=0) opts.add_option("-u", "--size-upper", dest="upsize", type="int", metavar="SIZE", help="select entries in queue with size upper than SIZE bytes") parser.set_defaults(upsize=0) opts.add_option("-a", "--active", dest="active", default=False, action="store_true", help="select 'active' entries in queue (default: no)") opts.add_option("-o", "--hold", dest="hold", default=False, action="store_true", help="select 'on hold' entries in queue (default: no)") parser.add_option_group(opts) (options, args) = parser.parse_args() m = Mailqueue() m.add_filter("email", options.email) m.add_filter("msg", options.msg) m.add_filter("lowsize", options.lowsize) m.add_filter("upsize", options.upsize) m.add_filter("active", options.active) m.add_filter("hold", options.hold) if args == []: m.cmd_list() elif args[0] == "list": m.cmd_list() elif args[0] == "parse": m.cmd_parse() elif args[0] == "del": m.cmd_del() else: print "%s %s" % (_NAME, _HELP) if __name__ == "__main__": main() pmailq-0.5/pmailq.pod000066400000000000000000000054601151107352600146360ustar00rootroot00000000000000=head1 NAME pmailq - Postfix MAIL Queue manager =head1 SYNOPSIS pmailq [I