"""Read mail from a POP3 account and write a Unix Mailbox file"""

import string, re
import socket
import poplib
import rfc822
import time
from nettools import *

lower = string.lower
strip = string.strip
find = string.find

LF = '\n'
CRLF = '\r\n'

# Exception class
class POPMboxError(Exception): pass

# the mail gateway
class POPMbox:
	"""A POP3 --> mailbox gateway.

Retrieves mail messages from a POP3 account and passes them on
to a Unix mailbox file."""

	version = 'POPMbox 1.0'
	# 1.0/19990303/bb: initial release

	def __init__(self):
		self.localhost = localhost()	# this host's FQDN

		self.mbox = ''			# Mailbox file name to write
		self.fp = None			# Mailbox file object

		self.pop_host = ''		# POP3 server to get messages from
		self.pop_user = ''		# POP3 user name
		self.pop_pass = ''		# POP3 password
		self.pop_dele = 0		# delete mail after reading?
		self.pop = None			# poplib.POP3 object

	def banner(self):
		return '%s starting on %s' % (self.version, curtime())

	def config_mbox(self, mbox):
		self.mbox = mbox

	def config_pop(self, phost, puser, ppass, dele = 1):
		self.pop_host = phost
		self.pop_user = puser
		self.pop_pass = ppass
		self.pop_dele = dele


	def gateway(self, msg):
		"""take the message msg, which is a list of strings,
		and append it to self.fp"""

		EOF = '\x1A'

		# append to the file
		try:
			self.fp.write('From - ' + time.ctime(time.time()) + LF)
			for line in msg:
				if line[:2] == '..':
					line = line[1:]		# drop duplicate leading periods
				elif lower(line[:5]) == 'from ':
					line = '>' + line	# but protect unprotected "from " lines
				line = string.replace(line, EOF, '')	# delete ^Z characters (DOS EOF)
				line = string.expandtabs(line, 8)	# expand TABs
				self.fp.write(line + LF)
			self.fp.write(LF)
			return 1
		except IOError, e:
			print '  ! ', e
			return 0

	def forward_all(self):
		"""forward all waiting messages"""

		try:
			id = hdr = None
			msgs, bytes = self.pop.stat()

			if msgs < 1:
				return

			print '%s: %d (%d)' % (self.pop_user, msgs, bytes)

			msglist = self.pop.list()[1]
			for s in msglist:
				id = string.split(s)[0]		# message id on POP server
				hdr = self.pop.top(id, 0)[1]	# get header
				mail = self.pop.retr(id)[1]	# get message
				if self.gateway(mail) and self.pop_dele:
					self.pop.dele(id)
				id = hdr = None

		except poplib.error_proto, msg:
			print '  !!! forward_all:', msg, id and '(msg id %s)' % id or ''
			if hdr:
				print fmtlist(hdr, lambda h: '  ! ' + h)
		except socket.error, msg:
			print '  !!! forward_all:', sockerror(msg), id and '(msg id %s)' % id or ''
			if hdr:
				print fmtlist(hdr, lambda h: '  ! ' + h)


	def connect_pop(self):
		try:
			self.pop = poplib.POP3(self.pop_host)
			return 1
		except socket.error, msg:
			print '  !!! connect_pop(%s):' % self.pop_host, sockerror(msg)
			self.pop = None
			return 0
		except poplib.error_proto, msg:
			print '  !!! connect_pop(%s):' % self.pop_host, msg
			self.pop = None
			return 0

	def login_pop(self):
		try:
			self.pop.user(self.pop_user)
			self.pop.pass_(self.pop_pass)
			return 1
		except socket.error, msg:
			print '  !!! login_pop(%s):' % self.pop_host, sockerror(msg)
			return 0
		except poplib.error_proto, msg:
			print '  !!! login_pop(%s):' % self.pop_host, msg
			return 0

	def disconnect_pop(self):
		if self.pop:
			try:
				self.pop.quit()
			except:
				pass
		self.pop = None


	def check(self):
		"""check the POP3 mailbox and forward all waiting messages"""

		try:
			self.fp = open(self.mbox, 'a')
		except IOError, msg:
			print msg[1]
			return

		if self.connect_pop():
			if self.login_pop():
				self.forward_all()
			self.disconnect_pop()

		self.fp.close()
		self.fp = None


# end class POPMbox


def check(gw, pop):
	"""check one pop account"""

	# go do it
	gw.config_mbox(pop[3])
	gw.config_pop(pop[0], pop[1], pop[2], pop[4])
	gw.check()


def check_multi(pop_accounts):

	gw = POPMbox()

	print gw.banner()

	for pop in pop_accounts:
		check(gw, pop)

	print '-' * 20


def main():
	"""A mail gateway for dware.

Retrieves mails from the dware project management POP3 accounts and passes them
on to a Unix mailbox file.

WARNING: This function contains clear-text passwords!"""

	import sys, os
	sys.stderr = sys.stdout		# tracebacks on stdout!

	mboxdir = r'\\DWAS21\DO\Daten\PM\Mail_in\POP2Mbox' '\\'
	mbox = mboxdir + 'dware.mbx'
	dele = 1

	accounts = [
		# a list of (pop_host, pop_user, pop_pass, mbox, delete) tuples
		('mail.intern.dware.ch', 'dwamhc', 'mhc', mbox, dele),
# 2000-10-17/dwabb: NPO-Account auf Wunsch von dwaaw rausgenommen
#		('mail.intern.dware.ch', 'dwanpo', 'npo', mbox, dele),
		('mail.intern.dware.ch', 'dwainfo', 'info', mbox, dele),
	]

	check_multi(accounts)


if __name__ == '__main__':
	main()
