#!/usr/local/bin/python2.4

# Vmail MGR Users Check - Qmail SPP Plugin
# (c) 2006 Catalin Constantin - Dazoot

import pwd, sys, os, cdb

class NoSuchDomain(Exception):
	pass

class InvalidEmail(Exception):
	pass

class InvalidVmailMgrDomain(Exception):
	pass
	
class VmailMgr:
	
	def __init__(self):
		self.read_virtualdomains()
	
	def read_virtualdomains(self):
		domains={}
		
		f=file("/var/qmail/control/virtualdomains", "rt")
		line=f.readline()
		while(line):
			line=line.replace("\n","").replace("\r","").strip()
			p=line.split(":")
			domain=p[0].lower()
			local_user=p[1]
			domains[domain]=local_user
			line=f.readline()
		f.close()
		
		self.domains=domains
		return self.domains
	
	def local_check(self, email_user, email_domain):
		p=email_user.split("-")
		system_user=p[0]

		# check /var/qmail/alias .qmail files
		self.home_dir="/var/qmail/alias"
		for i in range(0, min(len(p), 5)):
			if self.is_dotqmail(p, i):
				return True
		
		# check if we have a system user
		try:
			pwd_entry=pwd.getpwnam(system_user)
		except:
			return False
		
		home_dir=pwd_entry[5]
		# check if there is a home dir for this user
		if not os.path.isdir(home_dir):
			return False
			
		# check if he has a Maildir folder
		if os.path.isdir(os.path.join(home_dir, "Maildir")):
			if email_user==system_user:
				return True
		
		# check if there is a .qmail file (no - dash)
		if os.path.isfile(os.path.join(home_dir, ".qmail")):
			if email_user==system_user:
				return True
		
		# check if there is a .qmail-default file
		if os.path.isfile(os.path.join(home_dir, ".qmail-default")):
			if email_user!=system_user:
				return True
		
		# check if there are .qmail-... files in his home_dir
		self.home_dir=home_dir
		for i in range(0, min(len(p)-1, 5)):
			if self.is_dotqmail(p[1:], i):
				return True
		
		# no match
		return False
		
	def check(self, email):
		p=email.split("@")
		if len(p)!=2:
			raise InvalidEmail("Invalid email %s" % email)
		
		email_user=p[0].lower()
		email_domain=p[1].lower()
		
		if not self.domains.has_key(email_domain):
			return self.local_check(email_user, email_domain)
			# raise NoSuchDomain("No such vmailmgr domain %s" % email_domain)
		
		system_user=self.domains[email_domain]
		
		try:
			pwd_entry=pwd.getpwnam(system_user)
		except:
			raise InvalidVmailMgrDomain("No such system user for domain %s" % email_domain)
		
		home_dir=pwd_entry[5]
		passwd_dbfile=os.path.abspath(os.path.join(home_dir, "passwd.cdb"))
		if not os.path.isfile(passwd_dbfile):
			raise InvalidVmailMgrDomain("Missing domain users database for domain %s" % email_domain)
		
		try:
			db=cdb.init(passwd_dbfile)
		except:
			raise InvalidVmailMgrDomain("Could not read cdb database for domain %s" % email_domain)
		
		# check if the user is in the CDB database
		try:
			cdb_user_data=db[email_user]
			return True
		except:
			pass

		self.home_dir=home_dir
		
		p=email_user.split("-")
		for i in range(0, min(len(p), 5)):
			if self.is_dotqmail(p, i):
				return True
		
		return False
	
	def is_dotqmail(self, parts, pos):
		#print parts
		dotqmail_name="-".join(parts[0:pos+1])
		if len(parts)==pos+1:
			f=os.path.join(self.home_dir, ".qmail-%s" % dotqmail_name)
			if os.path.isfile(f):
				return True
		else:
			f=os.path.join(self.home_dir, ".qmail-%s-default" % dotqmail_name)
			if os.path.isfile(f):
				return True
		
		return False


if __name__=="__main__":
	vmgr=VmailMgr()

	if len(sys.argv)==2:
		print vmgr.check(sys.argv[1])
		sys.exit(0)
		
	# if we have RELAYCLIENT=="" skip test
	if os.getenv("RELAYCLIENT")=="":
		sys.exit(0)
		
	# check if we passed RCPTHOSTS
	if os.getenv("SMTPRCPTHOSTSOK")!="1":
		sys.exit(0)
	
	rcpt_email=os.getenv("SMTPRCPTTO")
	if rcpt_email is None:
		sys.exit(0)
	
	try:
		ok=vmgr.check(rcpt_email)
		if not ok:
			print >>sys.stdout, "E550 No such mailbox %s" % rcpt_email
			print >>sys.stderr, "No such mailbox %s from: %s (%s)" % (rcpt_email, os.getenv("TCPREMOTEHOST"), os.getenv("TCPREMOTEIP"))
	except Exception, inst:
		print >>sys.stderr, "ERROR %s" % str(inst)

	sys.exit(0)