#!/usr/bin/env python
#
# A simple script to purge a given folder from an IMAP account.
# Useful for clearing out folders with thousands of messages
# deposited by anti-spam solutions, etc.  Plus a good example
# of how to use the Python IMAP client library.

import re, string, sys
import imaplib, getpass

__author__ = "Nick Guy"
__license__ = "GPLv2"

# Build option parser
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-n", "--hostname", dest="hostname", help="Hostname of the IMAP server in question.", metavar="HOSTNAME")
parser.add_option("-u", "--username", dest="username", help="Username to authenticate with.  If left blank, you will be prompted to enter one on standard input.", metavar="USERNAME")
parser.add_option("-p", "--password", dest="password", help="Password you wish to authenticate with.  If left blank, you will be prompted to enter one on standard input.", metavar="PASS")
parser.add_option("-f", "--folder", dest="folder", help="The folder you want to clear out.  If left blank, a list will be shown and you will be asked to enter the name on standard intput.", metavar="FOLDER")
parser.add_option("-s", "--secure", action="store_true", help="Enable SSL support (and TLS in the future).  This is always a good idea to try first.", default=False)
parser.add_option("-v", "--verbose", action="store_true", help="Enable verbose output, mostly useful for testing.", default=False)
parser.add_option("-r", "--readonly", action="store_true", help="Operate in Read Only mode. (useful for debugging primarily..)", default=False)
(options,args) = parser.parse_args()

# Process options, making sensible defaults and reading missing values
# from stdin.
if options.hostname == None:
	print ("Please specify a hostname: "),
	hostname = sys.stdin.readline().strip()
	# do error correction here.
else:
	hostname = options.hostname

if options.username == None:
	print ("Please specify a username: "),
	username = sys.stdin.readline().strip()
	# Do error checking here.
else:
	username = options.username

if options.password == None:
	# Getpass module is an ncurses feature that will allow a user
	# to type in a password without echoing the characters back to
	# the screen.
	password = getpass.getpass("Please specify a password: ")
else:
	# At some point in the future, learn to overwrite what the option parser found
	# on the sys.argv[] array so that passwords don't show up in `ps`
	password = options.password

# This is where it gets complicated...  We need to now connect to the server to get
# the user's folder list..
if options.secure == True:
	mailbox = imaplib.IMAP4_SSL(hostname)
	# you'll probably want to deal with all of the necessary SSL warnings here at some point.. :\
	# Not to mention integrating the TLS library when you can.
else:
	mailbox = imaplib.IMAP4(hostname)

# Connect to the IMAP Server...
try:
	mailbox.login(username,password)
except:
	print "Unable to authenticatte to IMAP Server: " + hostname + " using username: " + username
	mailbox.logout()
	sys.exit(5)

if options.folder == None:
	print "Select a folder from the list below..."
	typ, folders = mailbox.list()
	if typ == 'OK':
		for folder in folders:
			# note that what mailbox.list() returns can vary from server to server.
			# So we have to use a regex instead of a standard split().
			folder_name = re.split("\s\".\" ", folder)
			# Select each mailbox to get the message count, but do 
			# so read-only so you don't accidentally delete something.
			folder_name = folder_name[1].strip("\"")
			typ, message_nums = mailbox.select(folder_name, True)
			print folder_name + " (" + message_nums[0] + " messages)"
	else:
		print "Unable to list folders."
		if options.verbose == True:
			print "output from mail server..."
			print "IMAP command response type: " + typ
			print "IMAP command response messages: "
			print folders
		mailbox.logout()
		sys.exit(2)
	print ("Folder name: "),
	folder = sys.stdin.readline().strip() # The extra \n from readline() causes issues with imap4.select()

else:
	folder = options.folder

if options.verbose == True:
	 print "Attempting to acces folder: \"" + folder + "\""

if options.readonly == True:
	 typ, num_messages = mailbox.select(folder, True)
else:
	 typ, num_messages = mailbox.select(folder)

if typ == 'OK':
	# proceed to deletion, DELETE WITH CAUTION!
	if options.verbose == True:
		print "About to expunge " + num_messages[0] + " messages...  "

	# Search for all messages in that box, mark them deleted, then expunge.
	typ, data = mailbox.search(None, 'ALL')
	if typ != 'OK':
		print "Unable to enumerate messages."
		mailbox.logout()
		sys.exit(6)
	else:
		for num in data[0].split():
			if options.verbose == True:
				print "Marking message #" + num + " as deleted."
			mailbox.store(num, '+FLAGS', '\\Deleted')
		typ, message = mailbox.expunge()
		if options.verbose == True:
			print "Server response code: " + typ
			print "Server response message: ",
			print message
		if typ == 'OK':
			print  "Expunged " + num_messages[0] + " messages in " + folder + "."
			mailbox.close()
			mailbox.logout()
			sys.exit(0)
		else:
			print "Unable to expunge folder: " + folder
			if options.verbose == True:
				print "Server response code: " + typ
			mailbox.logout()
			sys.exit(3)
else:
	print "Unable to select folder to expunge."
	if options.verbose == True:
		print "Server response: ",
		print num_messages
	mailbox.logout()
	sys.exit(4)