# File: superbox.py
# Purpose: Message box superclass.

OPT_THREAD = 1		# sort messages into threads
OPT_HEADERS_ONLY = 2	# only collect headers (without body text)

# Flags the various box types have
BOX_ISDELETEABLE = 0x01 # Can delete box
BOX_MAKE_NEW_MSG = 0x02 # Can compose new messages from it
BOX_REPLY_SINGLE = 0x04
BOX_REPLY_GROUP  = 0x08
BOX_REPLY_FORWARD= 0x10
BOX_DEL_MESSAGE  = 0x20 # allow deletion of messages
BOX_UPDATE_METHOD= 0x40 # there is an update method
BOX_IMPORT_TO    = 0x80 # may import ascii or unix messages to box

import os
import time
import threading
import cPickle
from boxtypes.net_exceptions import *
from pyneheaders import *

class superbox:
	"""
	Message box superclass.
	"""
	def load_box (self, user, uid):
		self.__dict__ = {}
		version = ver_stamp
		try:
			f = open(uid+".fol", "r")
		except IOError:
			# Creating new folder
			pass
		else:
			try:
				version = cPickle.load(f)
				type = cPickle.load(f)
				self.__dict__ = cPickle.load(f)
			except Exception,e:
				print "Error loading box '"+uid+"': "+str(e)
				print "Restoring defaults..."
			f.close()
	
	def delete_article(self, msg_id):
		self._io.delete_article(msg_id)
		self.messages.remove(msg_id)

	def save_article(self, msg):
		self._io.save_article(msg)
	
	def save_new_article(self, msg):
		self._io.save_article(msg)
		msg_id = msg.headers["message-id"]
		if not (msg_id in self.messages):
			self.messages.append(msg_id)

	def move_article(self, user, msg_id, folder_uid):
		to_folder = user.get_folder_by_uid (folder_uid)
		msg = self.load_article (msg_id)
		to_folder.save_new_article (msg)
		to_folder.changed = 1
		self.delete_article (msg_id)
		self.changed = 1

	def load_article(self, msg_id):
		return self._io.load_article(msg_id)

	def load_header(self, msg_id):
		return self._io.load_header(msg_id)

	def get_default_personality(self, user):
		return user.get_personality( self.default_personality )

	def nuke_storage(self):
		"""
		Delete all messages in folder and lose io reference.
		Also delete folder .fol settings file.
		Do this before deleting a folder.
		"""
		if self.__dict__.has_key("_io"):
			self._io.nuke()
		try:
			os.remove(self.uid+".fol")
		except OSError:
			pass
	
	# If you want to do remote send/recv implement these in
	# derived class (or override):
	# (Pass verbose=1 to logfunc when giving verbose info)
	#
	# Return list of messages available for collection
	# def recv_get_pending(self, servers, logfunc)
	#
	def recv_collect_threaded(self, user, servers, recvfunc, logfunc, incfunc, articles):
		"""
		Collect articles in this list using all servers, threaded.
		Calling incfunc each time a message has been collected.
		Pass just one server in servers if multi-threaded collection
		not desired.
		"""
		def _collect_thread(self, user, servers, server_num, recvfunc, logfunc, incfunc, articles):
			import msgfilter
			# make sure the connection has not died
			if len(articles) != 0:
				try:
					servers[server_num].check_renew_connection()
				except (connect_exception, auth_exception):
					return
			server = servers[server_num]
			# download the articles
			while 1:
				try:
					x = articles.pop()
				except IndexError:
					return
				# if the article isn't already cached get it
				if not x in self.messages:
					try:
						# Let recvfunc do what it wants with message id 'x'
						status_msg = recvfunc(user, self, server, x)
						if status_msg != "":
							logfunc(status_msg)
					except timeout_exception:
						# Failed to collect message. shove back on pending
						articles.append(x)
				# update progress bar
				num_left = len(articles)
				incfunc()
		# start collection threads
		threads = []
		for i in range(1, len(servers)):
			t = threading.Thread(target=_collect_thread, args=(self, user, servers, i, recvfunc, logfunc, incfunc, articles))
			t.start()
			threads.append(t)
		_collect_thread(self, user, servers, 0, recvfunc, logfunc, incfunc, articles)
		# wait till threads are finished executing
		while 1:
			finished = 1
			for i in threads:
				if i.isAlive():
					finished = 0
			if finished:
				break
			time.sleep(1)
	
	def shutdown(self, user):
		if self.__dict__.has_key("_io"):
			del self._io



syntax highlighted by Code2HTML, v. 0.9.1