예제 #1
0
def check_bmoutbox(intcond):
	global interrupted
	## get all messages
	#all_messages = json.loads(api['conn'].getAllInboxMessages())['inboxMessages']	
	logging.info("Entering BM outbox checker loop")
	intcond.acquire()
	while not interrupted:
		all_messages = get_outbox()

		logging.info("Trashing old outbox messages")
		## if no messages
		if not all_messages:
			try:
				intcond.wait(BMConfig().get("bmgateway", "bmgateway", "outbox_process_interval"))
			except KeyboardInterrupt:
				break
			continue

		## loop through messages to find unread
		for a_message in all_messages:
			if a_message['status'] == 'ackreceived':
				userdata = lib.user.GWUser(bm = a_message['toAddress'])
				if userdata:
					userdata.setlastackreceived(a_message['lastActionTime'])
				BMMessage.deleteStatic(a_message['msgid'], folder = "outbox")

		logging.info("Vacuuming DB")
		result = BMAPI().conn().deleteAndVacuum()

		intcond.wait(BMConfig().get("bmgateway", "bmgateway", "outbox_process_interval"))
	intcond.release()
	logging.info("Leaving BM outbox checker loop")
def check_bmoutbox(intcond):
	global interrupted
	## get all messages
	#all_messages = json.loads(api['conn'].getAllInboxMessages())['inboxMessages']	
	logging.info("Entering BM outbox checker loop")
	intcond.acquire()
	while not interrupted:
		all_messages = get_outbox()

		logging.info("Trashing old outbox messages")
		## if no messages
		if not all_messages:
			try:
				intcond.wait(BMConfig().get("bmgateway", "bmgateway", "outbox_process_interval"))
			except KeyboardInterrupt:
				break
			continue

		## loop through messages to find unread
		for a_message in all_messages:
			if a_message['status'] == 'ackreceived':
				BMMessage.deleteStatic(a_message['msgid'], folder = "outbox")

		logging.info("Vacuuming DB")
		result = BMAPI().conn().deleteAndVacuum()

		intcond.wait(BMConfig().get("bmgateway", "bmgateway", "outbox_process_interval"))
	intcond.release()
	logging.info("Leaving BM outbox checker loop")
예제 #3
0
def check_bminbox(intcond):
	global interrupted
	## get all messages
	#all_messages = json.loads(api['conn'].getAllInboxMessages())['inboxMessages']	
	
	logging.info("Entering BM inbox checker loop")
	intcond.acquire()
	while not interrupted:
		all_messages = get_inbox()
	
		## if no messages
		if not all_messages:
			try:
				intcond.wait(BMConfig().get("bmgateway", "bmgateway", "process_interval"))
			except KeyboardInterrupt:
				break
			continue
	
		## loop through messages to find unread
		for a_message in all_messages:
	
			## if already read, delete and break
			if a_message['read'] == 1:
				BMMessage.deleteStatic(a_message['msgid'])
				continue

			## check if already processed, maybe from another instance
			if lib.bminbox.check_message_processed(a_message['msgid']):
				logging.info('Message %s has already been processed deleting...', a_message['msgid'])
#				BMMessage.deleteStatic(a_message['msgid'])
#				continue

			## if the message is unread, load it by ID to trigger the read flag
			message = json.loads(BMAPI().conn().getInboxMessageByID(a_message['msgid'], False))['inboxMessage'][0]
	
			## if a blank message was returned
			if not message:
				logging.error('API returned blank message when requesting a message by msgID')
				delete_bitmessage_inbox(bm_id)
				BMMessage.deleteStatic(a_message['msgid'])
				continue
	
			## find message ID
			bm_id = message['msgid']
	
			## check if receive address is a DEregistration request
			if field_in_list(message, BMAPI().address_list,
				'toAddress', 'deregistration_address_label'):
	
				## check if address is registered
				userdata = lib.user.GWUser(bm = message['fromAddress'])
	
				## if the sender is actually registered and wants to deregister
				if userdata.check():
					## process deregistration
					logging.info('Processed deregistration request for user ' + userdata.email)
					delete_address(message['fromAddress'])
	
					## send deregistration confirmation email
					SendBMTemplate(
						sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "deregistration_address_label")),
						recipient = message['fromAddress'],
						template = "deregistration-confirmed",
						addmaps = {
							'email': userdata.email
						})
	
				## bogus deregistration request
				else:
					logging.warn('Purged malicious deregistration bitmessage from ' + message['fromAddress'])
	
			elif field_in_list(message, BMAPI().address_list, 'toAddress', 'bug_report_address_label'):
				userdata = lib.user.GwUser(bm = message['fromAddress'])
				# if not, create a fake one
				# relay to ticket
	
			## check if receive address is a registration request
			elif field_in_list(message, BMAPI().address_list,
				'toAddress', 'registration_address_label'):

				userdata = lib.user.GWUser(bm = message['fromAddress'])

				if userdata.check(): # status, config, etc
					command = base64.b64decode(message['subject']).lower()
					if command == "config":
						logging.info('Config request from %s', message['fromAddress'])
						body = base64.b64decode(message['message'])
						data = {}
						for line in body.splitlines():
							line = re.sub("#.*", "", line)
							option = re.search("(\S+)\s*:\s*(\S+)", line)
							if option is None:
								continue
							if option.group(1).lower() == "pgp":
								data['pgp'] = lib.user.GWUserData.pgp(option.group(2))
							elif option.group(1).lower() == "attachments":
								data['attachments'] = lib.user.GWUserData.zero_one(option.group(2))
							#elif option.group(1).lower() == "flags":
								#data['flags'] = lib.user.GWUserData.numeric(option.group(2))
							elif option.group(1).lower() == "archive":
								data['archive'] = lib.user.GWUserData.zero_one(option.group(2))
							elif option.group(1).lower() == "masterpubkey_btc":
								data['masterpubkey_btc'] = lib.user.GWUserData.public_seed(option.group(2))
								# reset offset unless set explicitly
								if data['masterpubkey_btc'] is not None and not 'offset_btc' in data:
									data['offset_btc'] = "0"
							elif option.group(1).lower() == "offset_btc":
								data['offset_btc'] = lib.user.GWUserData.numeric(option.group(2))
							elif option.group(1).lower() == "feeamount":
								data['feeamount'] = lib.user.GWUserData.numeric(option.group(2), 8)
							elif option.group(1).lower() == "feecurrency":
								data['feecurrency'] = lib.user.GWUserData.currency(option.group(2))
							else:
								pass
						if userdata.update(data):
							SendBMTemplate(
								sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
								recipient = message['fromAddress'],
								template = "configchange",
								addmaps = {
								})
						else:
							SendBMTemplate(
								sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
								recipient = message['fromAddress'],
								template = "confignochange",
								addmaps = {
								})
							pass
					elif command == "status" or command == "" or not command:
						logging.info('Status request from %s', message['fromAddress'])
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "status",
							addmaps = {
								'email': userdata.email,
								'domain': userdata.domain,
								'active': "Yes" if userdata.active else "No",
								'cansend': "Yes" if userdata.cansend else "No",
								'cancharge': "Yes" if userdata.cancharge else "No",
								'caninvoice': "Yes" if userdata.caninvoice else "No",
								'pgp': "server" if userdata.pgp else "local",
								'attachments': "Yes" if userdata.attachments else "No",
								'expires': userdata.exp.strftime("%B %-d %Y"),
								'masterpubkey_btc': userdata.masterpubkey_btc if userdata.masterpubkey_btc else "N/A",
								'offset_btc': str(userdata.offset_btc) if userdata.masterpubkey_btc else "N/A",
								'feeamount': str(userdata.feeamount) if userdata.masterpubkey_btc else "N/A",
								'feecurrency': str(userdata.feecurrency) if userdata.masterpubkey_btc else "N/A",
								'archive': "Yes" if userdata.archive else "No",
								'flags': hex(userdata.flags),
								'aliases': ', '.join(userdata.aliases) if userdata.aliases else "None"
							})
					else:
						logging.info('Invalid command from %s', message['fromAddress'])
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "command-invalid",
							addmaps = {
								'command': command,
								'email': userdata.email
							})
					
				else: # attempt to register new user
					## find requested username
					proposed_registration_user = base64.b64decode(message['subject']).lower()

					#full_registration_user = registration_user + '@' + BMConfig().get("bmgateway", "bmgateway", "domain_name")
					valid_one = re.match('^[\w]{4,20}$', proposed_registration_user) is not None
					valid_two =  re.match('^[\w]{4,20}@' + BMConfig().get("bmgateway", "bmgateway", "domain_name") + '$', proposed_registration_user) is not None
	
					# strip domain if they sent it during registration
					if valid_one:
						full_registration_user = proposed_registration_user.lower() + '@' + BMConfig().get("bmgateway", "bmgateway", "domain_name")
						registration_user = proposed_registration_user.lower()
					elif valid_two:
						full_registration_user = proposed_registration_user.lower()
						registration_user = proposed_registration_user.split('@')[0].lower()
					else:
						logging.info('Invalid email address in registration request for %s', proposed_registration_user)
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-invalid",
							addmaps = {
								'email': proposed_registration_user
							})
						BMMessage.deleteStatic(bm_id)
						continue
	
					## if username is valid check if it's available

					## check if address is already registered to a username or is banned
					if is_banned_username(registration_user):
						logging.info('Banned email address in registration request for %s', registration_user)
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-duplicate",
							addmaps = {
								'email': full_registration_user
							})
						BMMessage.deleteStatic(bm_id)
						continue
					elif lib.user.GWUser(email = full_registration_user).check():
						logging.info('Duplicate email address in registration request for %s', registration_user)
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-duplicate",
							addmaps = {
								'email': full_registration_user
							})
						BMMessage.deleteStatic(bm_id)
						continue
	
					logging.info('Received registration request for email address %s ', full_registration_user)
					lib.user.GWUser(empty = True).add(bm = message['fromAddress'], email = full_registration_user)
					SendBMTemplate(
						sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-confirmed",
							addmaps = {
								'email': full_registration_user
							})
			## if sent to the generic recipient or sender address
			elif field_in_list(message, BMAPI().address_list,
				'toAddress', 'relay_address_label'):
	
				## if user is not registered, purge
				userdata = lib.user.GWUser(bm = message['fromAddress'])
				if not userdata.check():
					if BMConfig().get("bmgateway", "bmgateway", "allow_unregistered_senders"):
						bm_sender = message['fromAddress'] + '@' + BMConfig().get("bmgateway", "bmgateway", "domain_name")
					else:
						logging.warn('Purged bitmessage from non-registered user ' + message['fromAddress'])
						BMMessage.deleteStatic(bm_id)
						continue
	
				## if user is registered, find their username @ domain
				else:
					bm_sender = userdata.email

				## find outbound email address
				bm_receiver = re.findall(r'[\w\.\+-]+@[\w\.-]+\.[\w]+', base64.b64decode(message['subject']))
				if len(bm_receiver) > 0:
					bm_receiver = bm_receiver[0]
				
				## if there is no receiver mapping or the generic address didnt get a valid outbound email, deny it
				if not bm_receiver:
					# FIXME explain to sender what is whrong
					logging.warn('Received and purged bitmessage with unknown recipient (likely generic address and bad subject)')
					if BMConfig().get("bmgateway", "bmgateway", "respond_to_missing"):
						SendBMTemplate(
							sender = message['toAddress'],
							recipient = message['fromAddress'],
							template = "relay-missing-recipient",
							addmaps = {
								'email': userdata.email,
							})
					BMMessage.deleteStatic(bm_id)
					continue
	
				# expired or cannot send
				if (userdata.expired() or userdata.cansend == 0) and not \
					(bm_receiver == BMConfig().get("bmgateway", "bmgateway", "bug_report_address_email")): # can still contact bugreport
					btcaddress, amount = lib.payment.payment_exists_domain (BMConfig().get("bmgateway", "bmgateway", "domain_name"), userdata.bm)
				        # create new one
       					if btcaddress == False:
                				btcaddress, amount = lib.payment.create_invoice_domain (BMConfig().get("bmgateway", "bmgateway", "domain_name"), userdata.bm)

					SendBMTemplate(
						sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
						recipient = message['fromAddress'],
						template = "accountexpired",
						addmaps = {
							'btcuri': lib.payment.create_payment_uri(btcaddress, 'BTC', amount,
								BMConfig().get("bmgateway", "bmgateway", "companyname"), 'User ' + userdata.bm + " / " + userdata.email + ' subscription'),
				                        'service': 'Subscription for ' + userdata.email + ' from ' + datetime.date.today().strftime("%B %-d %Y") +
								' until ' + userdata.exp.strftime("%B %-d %Y"),
							'email': userdata.email
						})
					logging.warn("User " + message['fromAddress'] + " notified of payment requirement")
					BMMessage.deleteStatic(bm_id)
					continue
	
				bm_subject = base64.b64decode(message['subject'])
	 
				## handle removal of embedded MAILCHUCK-FROM:: tag for replies
				bm_subject = bm_subject.replace('MAILCHUCK-FROM::' + bm_receiver + ' | ', '');
	
				## remove email address from subject
				if field_in_list(message, BMAPI().address_list, 'toAddress', 'relay_address_label'):
					bm_subject = bm_subject.replace(bm_receiver, '')	
	
				## get message contents
				bm_body = base64.b64decode(message['message'])	

				## pad with a newline, otherwise it may look ugly
				if bm_body[-1:] != '\n':
					bm_body += '\n'
	
				## send message and delete bitmessage, bitches
				if (float(userdata.lastrelay) + BMConfig().get("bmgateway", "bmgateway", "throttle") > time.time()):
					SendBMTemplate(
						sender = message['toAddress'],
						recipient = message['fromAddress'],
						template = "relay-throttle",
						addmaps = {
							'email': userdata.email,
							'throttledelta':  str(int((float(userdata.lastrelay) +
								BMConfig().get("bmgateway", "bmgateway", "throttle") - time.time() + 60)/60))
						})
					logging.warn('Throttled %s', message['fromAddress'])
					BMMessage.deleteStatic(bm_id)
					continue
				else:
					retval = send_email(bm_receiver, bm_sender, bm_subject, bm_body, bm_id, userdata = userdata)
					if retval is None:
						logging.info('Relayed from %s to %s', message['fromAddress'], bm_receiver)
					else:
						if retval[0] >= 400 and retval[0] < 500:
							# do not delete, repeatable
							continue
						else:
							SendBMTemplate(
								sender = message['toAddress'],
								recipient = message['fromAddress'],
								template = "smtperror",
								addmaps = {
									'emailrcpt': bm_receiver,
									'errcode': retval[0],
									'errmessage': retval[1]
								}
							)
							

			## remove message
			BMMessage.deleteStatic(bm_id)
			lib.bminbox.set_message_processed(bm_id)
		intcond.wait(BMConfig().get("bmgateway", "bmgateway", "process_interval"))
	intcond.release()
	logging.info("Leaving BM inbox checker loop")
예제 #4
0
def send_email(recipient, sender, subject, body, bm_id, userdata = None):
	## open connection
	server = smtplib.SMTP('localhost')
	server.set_debuglevel(0)

	## build message
	msg = MIMEMultipart()
	msg['From'] = sender
	msg['To'] = recipient
	msg['Subject'] = subject

	## Signature
	if BMConfig().get("bmgateway", "bmgateway", "signature") is not None:
		body += "-- \n" + \
			BMConfig().get("bmgateway", "bmgateway", "signature") + \
			"\n"

	enc_body = None
	sender_key = None
	recipient_key = None
	sign = BMConfig().get("bmgateway", "pgp", "sign")
	encrypt = BMConfig().get("bmgateway", "pgp", "encrypt")

	if userdata:
		if userdata.expired():
			sign = False
			encrypt = False
		else:
			# only override if not expired and pgp allowed globally
			if sign:
				sign = (userdata.pgp == 1)
			if encrypt:
				encrypt = (userdata.pgp == 1)

	#TODO find out if already encrypted/signed

	## generate a signing key if we dont have one
	if sign:
		if not lib.gpg.check_key(sender, whatreturn="key", operation="sign"):
			lib.gpg.create_primary_key(sender)
		sender_key = lib.gpg.check_key(sender, whatreturn="key", operation="sign")
		if not sender_key:
			logging.error('Could not find or upload user\'s keyid: %s', sender)

	## search for recipient PGP key
	if encrypt:
#		if lib.gpg.find_key(recipient):
		recipient_key = lib.gpg.check_key(recipient, whatreturn="key", operation="encrypt")
		if not recipient_key:
			logging.info('Could not find recipient\'s keyid, not encrypting: %s', recipient)
		# make sure sender has an encryption key
		if not lib.gpg.check_key(sender, whatreturn="key", operation="encrypt"):
			if not lib.gpg.check_key(sender, whatreturn="key", operation="sign"):
				lib.gpg.create_primary_key(sender)
			lib.gpg.create_subkey(sender)

	if sender_key and recipient_key:
		enc_body = lib.gpg.encrypt_text(body, recipient_key, sender_key)
		logging.info('Encrypted and signed outbound mail from %s to %s', sender, recipient)
	elif recipient_key:
		enc_body = lib.gpg.encrypt_text(body, recipient_key)
		logging.info('Encrypted outbound mail from %s to %s', sender, recipient)
	elif sender_key and not recipient == BMConfig().get("bmgateway", "bmgateway", "bug_report_address_email"):
		logging.info('Signed outbound mail from %s to %s', sender, recipient)
		enc_body = lib.gpg.sign_text(body, sender_key)

	## only encrypt if the operation was successful
	if enc_body:
		body = enc_body

	text = body

	## encode as needed
	body = MIMEText(body, 'plain')

	## attach body with correct encoding
	msg.attach(body)
	text = msg.as_string()

	## send message
	try:
		status = server.sendmail(sender, recipient, text, [], ["NOTIFY=SUCCESS,FAILURE,DELAY", "ORCPT=rfc822;" + recipient])
   		logging.info('Sent email from %s to %s', sender, recipient) 
		BMMessage.deleteStatic(bm_id, folder = "inbox")
	## send failed
	
	except smtplib.SMTPException as e:
   		logging.error('Could not send email from %s to %s: %s', sender, recipient, e)
		server.quit()
		for rcpt in e.recipients:
			return e.recipients[rcpt]

	server.quit()
	return
def check_bminbox(intcond):
	global interrupted
	## get all messages
	#all_messages = json.loads(api['conn'].getAllInboxMessages())['inboxMessages']	
	
	logging.info("Entering BM inbox checker loop")
	intcond.acquire()
	while not interrupted:
		all_messages = get_inbox()
	
		## if no messages
		if not all_messages:
			try:
				intcond.wait(BMConfig().get("bmgateway", "bmgateway", "process_interval"))
			except KeyboardInterrupt:
				break
			continue
	
		## loop through messages to find unread
		for a_message in all_messages:
	
			## if already read, delete and break
			if a_message['read'] == 1:
				BMMessage.deleteStatic(a_message['msgid'])
				continue
	
			## if the message is unread, load it by ID to trigger the read flag
			message = json.loads(BMAPI().conn().getInboxMessageByID(a_message['msgid'], False))['inboxMessage'][0]
	
			## if a blank message was returned
			if not message:
				logging.error('API returned blank message when requesting a message by msgID')
				delete_bitmessage_inbox(bm_id)
				BMMessage.deleteStatic(a_message['msgid'])
				continue
	
			## find message ID
			bm_id = message['msgid']
	
			## check if receive address is a DEregistration request
			if field_in_list(message, BMAPI().address_list,
				'toAddress', 'deregistration_address_label'):
	
				## check if address is registered
				userdata = lib.user.GWUser(bm = message['fromAddress'])
	
				## if the sender is actually registered and wants to deregister
				if userdata.check():
					## process deregistration
					logging.info('Processed deregistration request for user ' + userdata.email)
					delete_address(message['fromAddress'])
	
					## send deregistration confirmation email
					SendBMTemplate(
						sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "deregistration_address_label")),
						recipient = message['fromAddress'],
						template = "deregistration-confirmed",
						addmaps = {
							'email': userdata.email
						})
	
				## bogus deregistration request
				else:
					logging.warn('Purged malicious deregistration bitmessage from ' + message['fromAddress'])
	
	
			## check if receive address is a registration request
			elif field_in_list(message, BMAPI().address_list,
				'toAddress', 'registration_address_label'):

				userdata = lib.user.GWUser(bm = message['fromAddress'])

				if userdata.check(): # status, config, etc
					command = base64.b64decode(message['subject']).lower()
					if command == "blabla":
						logging.info('Blabla request from %s', message['fromAddress'])
					elif command == "status" or command == "" or not command:
						logging.info('Status request from %s', message['fromAddress'])
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "status",
							addmaps = {
								'email': userdata.email,
								'domain': userdata.domain,
								'active': "Yes" if userdata.active else "No",
								'cansend': "Yes" if userdata.cansend else "No",
								'cancharge': "Yes" if userdata.cancharge else "No",
								'caninvoice': "Yes" if userdata.caninvoice else "No",
								'pgp': "Yes" if userdata.pgp else "No",
								'attachments': "Yes" if userdata.attachments else "No",
								'expires': userdata.exp.strftime("%B %-d %Y"),
								'masterpubkey_btc': userdata.masterpubkey_btc if userdata.masterpubkey_btc else "N/A",
								'offset_btc': str(userdata.offset_btc) if userdata.masterpubkey_btc else "N/A",
								'feeamount': str(userdata.feeamount) if userdata.masterpubkey_btc else "N/A",
								'feecurrency': str(userdata.feecurrency) if userdata.masterpubkey_btc else "N/A",
								'archive': "Yes" if userdata.archive else "No",
								'flags': userdata.flags
							})
					else:
						logging.info('Invalid command from %s', message['fromAddress'])
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "command-invalid",
							addmaps = {
								'email': proposed_registration_user
							})
					
				else: # attempt to register new user
					## find requested username
					proposed_registration_user = base64.b64decode(message['subject']).lower()

					#full_registration_user = registration_user + '@' + BMConfig().get("bmgateway", "bmgateway", "domain_name")
					valid_one = re.match('^[\w]{4,20}$', proposed_registration_user) is not None
					valid_two =  re.match('^[\w]{4,20}@' + BMConfig().get("bmgateway", "bmgateway", "domain_name") + '$', proposed_registration_user) is not None
	
					# strip domain if they sent it during registration
					if valid_one:
						full_registration_user = proposed_registration_user.lower() + '@' + BMConfig().get("bmgateway", "bmgateway", "domain_name")
						registration_user = proposed_registration_user.lower()
					elif valid_two:
						full_registration_user = proposed_registration_user.lower()
						registration_user = proposed_registration_user.split('@')[0].lower()
					else:
						logging.info('Invalid email address in registration request for %s', proposed_registration_user)
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-invalid",
							addmaps = {
								'email': proposed_registration_user
							})
						BMMessage.deleteStatic(bm_id)
						continue
	
					## if username is valid check if it's available

					## check if address is already registered to a username or is banned
					if is_banned_username(registration_user):
						logging.info('Banned email address in registration request for %s', registration_user)
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-duplicate",
							addmaps = {
								'email': full_registration_user
							})
						BMMessage.deleteStatic(bm_id)
						continue
					elif lib.user.GWUser(email = full_registration_user).check():
						logging.info('Duplicate email address in registration request for %s', registration_user)
						SendBMTemplate(
							sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-duplicate",
							addmaps = {
								'email': full_registration_user
							})
						BMMessage.deleteStatic(bm_id)
						continue
	
					logging.info('Received registration request for email address %s ', full_registration_user)
					lib.user.GWUser(empty = True).add(bm = message['fromAddress'], email = full_registration_user)
					SendBMTemplate(
						sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
							recipient = message['fromAddress'],
							template = "registration-confirmed",
							addmaps = {
								'email': full_registration_user
							})
			## if sent to the generic recipient or sender address
			elif field_in_list(message, BMAPI().address_list,
				'toAddress', 'relay_address_label'):
	
				## if user is not registered, purge
				userdata = lib.user.GWUser(bm = message['fromAddress'])
				if not userdata.check():
					if BMConfig().get("bmgateway", "bmgateway", "allow_unregistered_senders"):
						bm_sender = message['fromAddress'] + '@' + BMConfig().get("bmgateway", "bmgateway", "domain_name")
					else:
						logging.warn('Purged bitmessage from non-registered user ' + message['fromAddress'])
						BMMessage.deleteStatic(bm_id)
						continue
	
				## if user is registered, find their username @ domain
				else:
					bm_sender = userdata.email

				## find outbound email address
				bm_receiver = re.findall(r'[\w\.\+-]+@[\w\.-]+\.[\w]+', base64.b64decode(message['subject']))
				if len(bm_receiver) > 0:
					bm_receiver = bm_receiver[0]
				
				## if there is no receiver mapping or the generic address didnt get a valid outbound email, deny it
				if not bm_receiver:
					# FIXME explain to sender what is whrong
					logging.warn('Received and purged bitmessage with unknown recipient (likely generic address and bad subject)')
					if BMConfig().get("bmgateway", "bmgateway", "respond_to_missing"):
						SendBMTemplate(
							sender = message['toAddress'],
							recipient = message['fromAddress'],
							template = "relay-missing-recipient",
							addmaps = {
								'email': userdata.email,
							})
					BMMessage.deleteStatic(bm_id)
					continue
	
				# expired or cannot send
				if (userdata.expired() or userdata.cansend == 0) and not \
					(bm_receiver == BMConfig().get("bmgateway", "bmgateway", "bug_report_address_email")): # can still contact bugreport
					btcaddress, amount = lib.payment.payment_exists_domain (BMConfig().get("bmgateway", "bmgateway", "domain_name"), userdata.bm)
				        # create new one
       					if btcaddress == False:
                				btcaddress, amount = lib.payment.create_invoice_domain (BMConfig().get("bmgateway", "bmgateway", "domain_name"), userdata.bm)

					SendBMTemplate(
						sender = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "registration_address_label")),
						recipient = message['fromAddress'],
						template = "accountexpired",
						addmaps = {
							'btcuri': lib.payment.create_payment_uri(btcaddress, 'BTC', amount,
								BMConfig().get("bmgateway", "bmgateway", "companyname"), 'User ' + userdata.bm + " / " + userdata.email + ' subscription'),
				                        'service': 'Subscription for ' + userdata.email + ' from ' + datetime.date.today().strftime("%B %-d %Y") +
								' until ' + userdata.exp.strftime("%B %-d %Y"),
							'email': userdata.email
						})
					logging.warn("User " + message['fromAddress'] + " notified of payment requirement")
					BMMessage.deleteStatic(bm_id)
					continue
	
				bm_subject = base64.b64decode(message['subject'])
	 
				## handle removal of embedded MAILCHUCK-FROM:: tag for replies
				bm_subject = bm_subject.replace('MAILCHUCK-FROM::' + bm_receiver + ' | ', '');
	
				## remove email address from subject
				if field_in_list(message, BMAPI().address_list, 'toAddress', 'relay_address_label'):
					bm_subject = bm_subject.replace(bm_receiver, '')	
	
				## get message contents
				bm_body = base64.b64decode(message['message'])	
	
				## send message and delete bitmessage, bitches
				if (float(userdata.lastrelay) + BMConfig().get("bmgateway", "bmgateway", "throttle") > time.time()):
					SendBMTemplate(
						sender = message['toAddress'],
						recipient = message['fromAddress'],
						template = "relay-throttle",
						addmaps = {
							'email': userdata.email,
							'throttledelta':  str(int((float(userdata.lastrelay) +
								BMConfig().get("bmgateway", "bmgateway", "throttle") - time.time() + 60)/60))
						})
					logging.warn('Throttled %s', message['fromAddress'])
					BMMessage.deleteStatic(bm_id)
					continue
				else:
					send_email(bm_receiver, bm_sender, bm_subject, bm_body, bm_id, userdata = userdata)
					logging.info('Relayed from %s to %s', message['fromAddress'], bm_receiver)

			## remove message
			BMMessage.deleteStatic(bm_id)
		intcond.wait(BMConfig().get("bmgateway", "bmgateway", "process_interval"))
	intcond.release()
	logging.info("Leaving BM inbox checker loop")
def send_email(recipient, sender, subject, body, bm_id, userdata = None):
	## open connection
	server = smtplib.SMTP('localhost')
	server.set_debuglevel(0)

	## build message
	msg = MIMEMultipart()
	msg['From'] = sender
	msg['To'] = recipient
	msg['Subject'] = subject

	enc_body = None
	sender_key = None
	recipient_key = None
	sign = BMConfig().get("bmgateway", "pgp", "sign")
	encrypt = BMConfig().get("bmgateway", "pgp", "encrypt")

	if userdata:
		if userdata.expired():
			sign = False
			encrypt = False
		else:
			# only override if not expired and pgp allowed globally
			if sign:
				sign = (userdata.pgp == 1)
			if encrypt:
				encrypt = (userdata.pgp == 1)

	#TODO find out if already encrypted/signed

	## generate a signing key if we dont have one
	if sign:
		if not lib.gpg.check_key(sender, whatreturn="key", operation="sign"):
			lib.gpg.create_primary_key(sender)
		sender_key = lib.gpg.check_key(sender, whatreturn="key", operation="sign")
		if not sender_key:
			logging.error('Could not find or upload user\'s keyid: %s', sender)

	## search for recipient PGP key
	if encrypt:
#		if lib.gpg.find_key(recipient):
		recipient_key = lib.gpg.check_key(recipient, whatreturn="key", operation="encrypt")
		if not recipient_key:
			logging.info('Could not find recipient\'s keyid, not encrypting: %s', recipient)
		# make sure sender has an encryption key
		if not lib.gpg.check_key(sender, whatreturn="key", operation="encrypt"):
			if not lib.gpg.check_key(sender, whatreturn="key", operation="sign"):
				lib.gpg.create_primary_key(sender)
			lib.gpg.create_subkey(sender)

	if sender_key and recipient_key:
		enc_body = lib.gpg.encrypt_text(body, recipient_key, sender_key)
		logging.info('Encrypted and signed outbound mail from %s to %s', sender, recipient)
	elif recipient_key:
		enc_body = lib.gpg.encrypt_text(body, recipient_key)
		logging.info('Encrypted outbound mail from %s to %s', sender, recipient)
	elif sender_key and not recipient == BMConfig().get("bmgateway", "bmgateway", "bug_report_address_email"):
		logging.info('Signed outbound mail from %s to %s', sender, recipient)
		enc_body = lib.gpg.sign_text(body, sender_key)

	## only encrypt if the operation was successful
	if enc_body:
		body = enc_body

	text = body

	## encode as needed
	body = MIMEText(body, 'plain')

	## attach body with correct encoding
	msg.attach(body)
	text = msg.as_string()

	## send message
	try:
		status = server.sendmail(sender, recipient, text, [], ["NOTIFY=SUCCESS,FAILURE,DELAY", "ORCPT=rfc822;" + recipient])
   		logging.info('Sent email from %s to %s', sender, recipient) 
		BMMessage.deleteStatic(bm_id, folder = "inbox")
	## send failed
	except smtplib.SMTPException as e:
   		logging.error('Could not send email from %s to %s: %s', sender, recipient, e)

	server.quit()