"""nettools.py: Beat's Python library"""

import string
import socket
import time
from types import *

def __id(x):
	return x

def fmtdict(d, f=__id):
	r = ''
	for k in d.keys():
		r = r + '\n%s: %s' % (k, f(d[k]))
	return r[1:]

def fmtlist(l, f=__id):
	r = ''
	for i in l:
		r = r + '\n' + f(i)
	return r[1:]


def joinaddr(p):
	r = ''
	if type(p) == TupleType:	# we have a tuple (name, email)
		if p[0]:				# name
			n = p[0]
			if n[0] == n[-1] == "'":	# strip quotes
				n = n[1:-1]
			if string.lower(n[:15]) == '=?iso-8859-1?q?' and n[-2:] == '?=':
				n = unqp(n[15:-2])
			r = '"' + n + '"'
		if p[1]:
			if r: r = r + ' '
			r = r + '<' + p[1] + '>'	# email
	else:
		r = '<' + p + '>'			# email only
	return r


LOCALHOST = 'localhost'
LOCALHOST_IP = '127.0.0.1'

def hostname(ip):
	"""return a fully qualified domain name for IP address 'ip'"""
	try:
		lh = socket.gethostbyaddr(ip)
	except socket.error:
		if ip == LOCALHOST_IP:
			return LOCALHOST
		else:
			return 'unknown'
	if '.' in lh[0]: return lh[0]
	for n in lh[1]:
		if '.' in n: return n
	return lh[0]

def verbose_hostname(ip):
	return hostname(ip) + ' [' + ip + ']'

def localaddr():
	try:
		return socket.gethostbyname(socket.gethostname())
	except socket.error:
		return LOCALHOST_IP

def localhost():
	return hostname(localaddr())

def verbose_localhost():
	return verbose_hostname(localaddr())


def domainpart(addr):
	"""return the domain part of an email address"""
	at = string.rfind(addr, '@')
	if at > 0:
		return addr[at + 1:]
	return ''

def namepart(addr):
	"""return the name part of an email address"""
	at = string.rfind(addr, '@')
	if at > 0:
		return addr[:at]
	return addr


_sockerror_map = {
	10050: 'Network down',
	10053: 'Connection aborted',
	10054: 'Connection reset by peer',
	10055: 'No buffer space available',
	10058: 'Socket is already shut down',
	10060: 'Connection timed out',
	10061: 'Connection refused',
	10065: 'No route to host',
}

def sockerror(e):
	"""return an error string for socket.error e"""
	if type(e) in (TupleType, InstanceType):
		try:
			return _sockerror_map[e[0]]
		except KeyError:
			return 'Socket error: %s' % e[0]
	return str(e)


_fmtzLOC = "%+03d%02d"		# default TZ designator format
_fmtzUTC = "UTC"		# default UTC designator format 1
_fmtzvar = "^z"			# TZ placeholder in fmttime arg below

def fmttime(t, utc, fmttime, fmtzLOC=_fmtzLOC, fmtzUTC=_fmtzUTC):
	if type(t) == FloatType:	# time.time() result
		if utc:
			t = time.gmtime(t)[:8] + time.localtime(t)[8:]	# keep DST flag!
		else:
			t = time.localtime(t)
	if utc == 1:
		z = fmtzUTC
	elif utc == 2:
		z = fmtzLOC % (0, 0)
	elif time.daylight and t[8] == 1:
		z = fmtzLOC % divmod(-time.altzone, 3600)
	else:
		z = fmtzLOC % divmod(-time.timezone, 3600)
	return string.replace(time.strftime(fmttime, t), _fmtzvar, z)

def rfctime(t=time.time(), utc=0):
	"""format the time argument according to RFC822"""
	return fmttime(t, utc, "%a, %d %b %Y %H:%M:%S " + _fmtzvar)

def isotime(t=time.time(), utc=0):
	"""format the time argument according to ISO8601"""
	return fmttime(t, utc, "%Y-%m-%dT%H:%M:%S" + _fmtzvar, fmtzUTC='Z')

def curtime():
	"""return the current local time in human readable format"""
	return time.ctime(time.time())

def timestamp():
	"""return the current local time in timestamp format, e.g. YYYYMMDD-HHMMSS"""
	return time.strftime("%Y%m%d-%H%M%S", time.localtime(time.time()))


_esc1 = '='
_esc2 = '_'
_hex = '0123456789ABCDEF'

def unqp(s):
	"""undo a quoted-printable content-transfer-encoding"""
	r = ''
	n = len(s)
	i = 0
	while i < n:
		c = s[i]
		if c == _esc1 and i + 2 < n:
			d1 = string.find(_hex, s[i + 1])
			d2 = string.find(_hex, s[i + 2])
			if d1 >= 0 and d2 >= 0:
				c = chr(16 * d1 + d2)
				i = i + 2
		elif c == _esc2:
			c = ' '
		r = r + c
		i = i + 1
	return r

def qp(s):
	"""do a quoted-printable content-transfer-encoding"""
	r = ''
	ok = string.letters + string.digits
	for c in s:
		if c in ok:
			pass
		elif ord(c) == 0x20:	# not c == ' ', according to RFC 1522!
			c = _esc2
		else:
			c = _esc1 + _hex[a / 16] + _hex[a % 16]
		r = r + c
	return r


def isPyWin():
	"""determine if we're running under PythonWin or not"""
	try:
		pywin			# this succeeds if the module pywin is loaded
		return 1
	except NameError:		# module pywin not loaded
		return 0
