#!/usr/pkg/bin/python3.9
# -*- coding: iso-8859-1 -*-
"""
rmmq - Remove items (files) from sendmail(8) queue, given a queue ID.

DESCRIPTION

This command is a convenience command for removing items from a sendmail(8)
queue. When you run mailq(8) or mailqs, you get a list of sendmail queue
IDs. These queue IDs map to several files in a sendmail queue directory.
This command automatically maps the queue IDs to the files and removes them
for you.

USAGE:

rmmq [-i|--ask] [-v|--verbose] queue-ID [queue-ID] ...

OPTIONS

-i, --ask       Ask before removing each queue-ID.
-n, --no-exec   Show what would be done, but don't do it.
-v, --verbose   Display each file being removed.


COPYRIGHT AND LICENSE

Copyright  2008 Brian M. Clapper

This is free software, released under the following BSD-like license:

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. The end-user documentation included with the redistribution, if any,
   must include the following acknowlegement:

      This product includes software developed by Brian M. Clapper
      (bmc@clapper.org, http://www.clapper.org/bmc/). That software is
      copyright  2008 Brian M. Clapper.

    Alternately, this acknowlegement may appear in the software itself, if
    and wherever such third-party acknowlegements normally appear.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL BRIAN M. CLAPPER BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

$Id: rmmq 7207 2008-01-23 14:11:28Z bmc $
"""

# $Id: rmmq 7207 2008-01-23 14:11:28Z bmc $

# Info about the module
__version__   = "1.0"
__author__    = "Brian Clapper, bmc@clapper.org"
__url__       = "http://www.clapper.org/software/python/sendmail-admin/"
__copyright__ = " 2008 Brian M. Clapper"
__license__   = "BSD-style license"

# Package stuff

__all__     = ["rmmq"]


# ---------------------------------------------------------------------------
# Imports
# ---------------------------------------------------------------------------

from getopt import getopt, GetoptError
import sys
import os

# Use the built-in 'set' type if using Python 2.4 or better. Otherwise, use
# the old sets module.
try:
    set
except NameError:
    from sets import Set as set, ImmutableSet as frozenset

# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------

QUEUE_DIR = "/var/spool/mqueue"

# ---------------------------------------------------------------------------
# Classes
# ---------------------------------------------------------------------------

class Params(object):
    def __init__(self):
        self.force     = False
        self.ask       = False
        self.verbose   = False
        self.no_exec   = False
        self.queue_IDs = set()

# ---------------------------------------------------------------------------
# Main Program
# ---------------------------------------------------------------------------

def usage(msg):
    if msg:
        sys.stderr.write('%s\n' % msg)

    sys.stderr.write(\
"""Usage: %s [OPTIONS] message-ID [message-ID] ...

OPTIONS:

-i, --ask       Ask before removing each file.
-n, --no-exec   Show what would be done, but don't do it.
-v, --verbose   Verbose: show each file being removed.
""" % os.path.basename(sys.argv[0]))

    sys.exit(1)


def parse_params(argv):
    try:
        opts, args = getopt(argv[1:], "inv", ["ask", "no-exec", "verbose"])
    except GetoptError, ex:
        usage(str(ex))   # throws an exception

    result = Params()

    if len(args) > 0:
        for i in args:
            result.queue_IDs.add(i)
    else:
        usage("Missing queue ID(s)")

    for o, a in opts:
        if o in ("--ask", "-i"):
            result.ask = True
            continue

        if o in ("--no-exec", "-n"):
            result.no_exec = True
            continue

        if o in ("--verbose", "-v"):
            result.verbose = True
            continue

    return result

def remove_one(queue_ID, params):
    do_remove = True
    if params.ask and (not params.no_exec):
        sys.stdout.write("Remove message with ID %s? [y] " % queue_ID)
        answer = sys.stdin.readline()
        if answer:
            answer = answer.strip()
            if (len(answer) == 0) or answer.lower().startswith('y'):
                do_remove = True
            else:
                do_remove = False

    if do_remove:
        for prefix in ("df", "qf"):
            path = '/'.join((QUEUE_DIR, prefix + queue_ID))
            try:
                if params.no_exec:
                    print('Would remove "%s"' % path)
                elif params.verbose:
                    print('Removing "%s"' % path)
                if not params.no_exec:
                    os.unlink(path)
            except OSError, (errno, msg):
                sys.stderr.write('Unable to remove "%s": %s\n' % (path, msg))

def main():

    params = parse_params(sys.argv)
    for queue_ID in params.queue_IDs:
        remove_one(queue_ID, params)

if __name__ == "__main__":
    main()
