pmailq 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # This program is free software. It comes without any warranty, to
  4. # the extent permitted by applicable law. You can redistribute it
  5. # and/or modify it under the terms of the Do What The Fuck You Want
  6. # To Public License, Version 2, as published by Sam Hocevar. See
  7. # http://sam.zoy.org/wtfpl/COPYING for more details.
  8. _NAME = 'pmailq'
  9. _HELP = "[OPTIONS] [ list | parse | del ]"
  10. _DESC = "%s postfix mail queue manager" % _NAME
  11. _VERSION = '0.1'
  12. _AUTHOR = 'Emmanuel Bouthenot <kolter@openics.org>'
  13. MAILQ = "postqueue -p"
  14. DELQ = "postsuper -d"
  15. from optparse import OptionParser, OptionGroup # needs python >= 2.3
  16. import sys, popen2, fnmatch
  17. class mailqueue:
  18. def __init__(self):
  19. self.mailqueue = []
  20. self.filters = {
  21. 'email' : None,
  22. 'msg' : None,
  23. 'lowsize' : 0,
  24. 'upsize' : 0,
  25. 'active' : False,
  26. 'hold' : False
  27. }
  28. self.parse()
  29. def add_filter(self, key, value):
  30. self.filters[key] = value
  31. def parse(self):
  32. proc = popen2.Popen3(MAILQ, True)
  33. p_ret = proc.wait()
  34. if p_ret != 0:
  35. print "ERROR (%d) !!!:" % p_ret
  36. print "".join(proc.childerr.readline())
  37. return None
  38. # checking empty mail queue
  39. buffer = proc.fromchild.readlines()
  40. if len(buffer)>0 and buffer[0].strip() == "Mail queue is empty":
  41. print buffer[0].strip()
  42. return None
  43. # skip first and last line
  44. buffer = "".join(buffer[1:-1]).strip()
  45. for block in buffer.split("\n\n"):
  46. lines = block.split("\n")
  47. headers = lines[0].split(' ')
  48. # squeeze repeated spaces
  49. while '' in headers:
  50. headers.remove('')
  51. queue = []
  52. dest = []
  53. info = ""
  54. for expl in lines[1:]:
  55. expl = expl.strip()
  56. if expl.startswith("(") and expl.endswith(")"):
  57. if info == "":
  58. info = expl[1:len(expl)-1]
  59. if dest != []:
  60. queue.append({ "info" : info , "dest" : dest })
  61. dest = []
  62. info = expl[1:len(expl)-1]
  63. else:
  64. dest.append(expl.lower())
  65. if dest != []:
  66. queue.append({ "info" : info , "dest" : dest })
  67. self.mailqueue.append({
  68. "id" : headers[0].rstrip("*!"),
  69. "active" : headers[0].endswith("*"),
  70. "hold" : headers[0].endswith("!"),
  71. "size" : headers[1],
  72. "date" : " ".join(headers[2:5]),
  73. "queue" : queue
  74. })
  75. def check(self, size, active, hold, dest, infos):
  76. if self.filters['email'] != None:
  77. match = False
  78. for e in dest:
  79. if fnmatch.fnmatch(e.lower(), self.filters['email'].lower()):
  80. match = True
  81. if not match:
  82. return False
  83. if self.filters['msg'] != None:
  84. match = False
  85. for i in infos:
  86. if fnmatch.fnmatch(i.lower(), self.filters['msg'].lower()):
  87. match = True
  88. if not match:
  89. return False
  90. if self.filters['active'] and not active:
  91. return False
  92. if self.filters['hold'] and not hold:
  93. return False
  94. if self.filters['lowsize'] != 0 and int(size) > self.filters['lowsize']:
  95. return False
  96. if self.filters['upsize'] != 0 and int(size) < self.filters['upsize']:
  97. return False
  98. return True
  99. def cmd_list(self):
  100. for m in self.mailqueue:
  101. out = "%s\n" % m['id']
  102. out += " -date: %s\n" % m['date']
  103. out += " -size: %s\n" % m['size']
  104. out += " -active: %s\n" % str(m['active'])
  105. out += " -hold: %s\n" % str(m['hold'])
  106. out += " -to:\n"
  107. to = []
  108. i = []
  109. for n in m['queue']:
  110. i.append(n['info'])
  111. to += n['dest']
  112. out += " + %s : [%s]\n" % (",".join(n['dest']), n['info'])
  113. if self.check(m['size'], m['active'], m['hold'], to, i):
  114. print out
  115. def cmd_parse(self):
  116. for m in self.mailqueue:
  117. e = []
  118. i = []
  119. for n in m['queue']:
  120. i.append(n['info'])
  121. for o in n['dest']:
  122. e.append(o)
  123. if self.check(m['size'], m['active'], m['hold'], e, i):
  124. print "%s|%s|%s|%d|%d|%s" % (m['id'], m['date'], m['size'], int(m['active']), int(m['hold']), ",".join(n['dest']))
  125. def cmd_del(self):
  126. for m in self.mailqueue:
  127. e = []
  128. i=[]
  129. for n in m['queue']:
  130. i.append(n['info'])
  131. for o in n['dest']:
  132. e.append(o)
  133. if self.check(m['size'], m['active'], m['hold'], e, i):
  134. proc = popen2.Popen3("%s %s" % (DELQ, m['id']), True)
  135. p_ret = proc.wait()
  136. if p_ret != 0:
  137. print "deleting %s [FAILED] (%s)" % (m['id'], "".join(proc.childerr.readlines()).strip())
  138. else:
  139. print "deleting %s [OK]" % m['id']
  140. def main():
  141. usage = "%prog " + _HELP
  142. desc = _DESC
  143. parser = OptionParser(usage=usage, description=desc, version=("%s %s" % (_NAME, _VERSION)))
  144. opts = OptionGroup(parser, "filters")
  145. opts.add_option("-e", "--email", dest="email", type="string", metavar="PATTERN", help="select entries in queue with email matching PATTERN")
  146. parser.set_defaults(email=None)
  147. opts.add_option("-m", "--msg", dest="msg", type="string", metavar="PATTERN", help="select entries in queue with error message matching PATTERN")
  148. parser.set_defaults(msg=None)
  149. opts.add_option("-l", "--size-lower", dest="lowsize", type="int", metavar="SIZE", help="select entries in queue with size lower than SIZE bytes")
  150. parser.set_defaults(lowsize=0)
  151. opts.add_option("-u", "--size-upper", dest="upsize", type="int", metavar="SIZE", help="select entries in queue with size upper than SIZE bytes")
  152. parser.set_defaults(upsize=0)
  153. opts.add_option("-a", "--active", dest="active", default=False, action="store_true", help="select 'active' entries in queue (default: no)")
  154. opts.add_option("-o", "--hold", dest="hold", default=False, action="store_true", help="select 'on hold' entries in queue (default: no)")
  155. parser.add_option_group(opts)
  156. (options, args) = parser.parse_args()
  157. m = mailqueue()
  158. m.add_filter("email", options.email)
  159. m.add_filter("msg", options.msg)
  160. m.add_filter("lowsize", options.lowsize)
  161. m.add_filter("upsize", options.upsize)
  162. m.add_filter("active", options.active)
  163. m.add_filter("hold", options.hold)
  164. if args == []:
  165. m.cmd_list()
  166. elif args[0] == "list":
  167. m.cmd_list()
  168. elif args[0] == "parse":
  169. m.cmd_parse()
  170. elif args[0] == "del":
  171. m.cmd_del()
  172. else:
  173. print "%s %s" % (_NAME, _HELP)
  174. if __name__ == "__main__":
  175. main()