Newer
Older
Import / projects / LGN-IP3870 / t / orig / sim.py
from phonedb import phonedb, PhoneItem
from basemodel import NotifyStage, ListStage, Stage, CheckListStage, YesNoStage, PINInputStage
import config, runtime, uiconfig, baseui, ui
from setting import setting
import simreader, utils, status

class SIM:
	def __init__(self):
		self.module_ready = False
		self.already_load_list = False

	def init_sim(self):
		if config.sim_debug:
			print '## sim open'
		self.simreader = simreader.SIMReader('/dev/misc/usim')
		try:
			resp = self.simreader.get_resp(80)
		except:
			pass

		# spec 을 지원하지 않아서 생기는 문제에 대한 Protect
		try:
			self.simreader.select_adn()
		except:
			return False
		return True
	def check_pin_enabled(self):
		return self.simreader.check_pin_enabled()

	def load_list(self):
		if self.already_load_list:
			if config.sim_debug:
				print '## already load_list'
			return
		self.already_load_list = True

		self.max = self.simreader.num_adn
		self.name_max = self.simreader.len_adn - 14
		self.number_max = 24
		self.lists = []
		try:
			for i in range(self.max):
				adn = self.simreader.get_adn(i+1)
				name, number = adn
				if not name:
					continue

				# +34, 0034 로 시작하면 그부분은 버림
				if number.startswith('0034'):
					number = number[4:]

				# insert 할때의 check 를 위해서 마지막에 index 추가
				self.lists.append((name, number, i+1))
			self.len = len(self.lists)
			self.sort()
		except:
			import traceback
			traceback.print_exc()

			return False # load fail
		return True # load success

	def sort(self):
		# load_list 할때만 sort 호출함...
		# insert_item 할때는 할 필요없음
		def sort_func(x, y):
			xname = x[0].lower()
			yname = y[0].lower()
			return cmp(xname, yname)
		self.lists.sort(sort_func)

	def insmod(self):
		if config.sim_debug:
			print '## insmod usim driver'
		import os
		
# eicho add 06.09.07 (copy from Nortel-P)
		ret =  os.system('insmod /usr/lib/modules/2.4.25-vrs2-pxa1/kernel/drivers/misc/pxa27x_usim.o')
		return ret


	def rmmod(self):
		if not self.module_ready:
			if config.sim_debug:
				print '## already sim module rmmod'
			return

		if config.sim_debug:
			print '## sim close'
		#self.simreader.close()
		try :
			self.simreader.close()
		except:
			print 'SIM) EXCEPTION - SIM READER CLOSE'

		if config.sim_debug:
			print '## rmmod usim driver'
		import os
		os.system('rmmod pxa27x_usim')
		self.module_ready = False
		self.already_load_list = False

	def inserted(self):
		if config.sim_debug:
			print '## sim card check'
#
		import time
		i=3
		ret = self.insmod()
		if config.sim_debug:
			print 'SIM) insmod ret=', ret , ', count=', i
		while ret == 256 and i>0 :	# already sim inserted
			self.rmmod()
			time.sleep(1)
			ret = self.insmod()
			i = i-1

			if config.sim_debug:
				print 'SIM) insmod ret=', ret , ', count=', i
# end 06.09.07 (copy from Nortel-P)
			
		for line in file('/proc/misc'):
			if line.find('usim') >= 0:
				if config.sim_debug:
					print '## sim card ready'
				self.module_ready = True
				return True
		if config.sim_debug:
			print '## sim card not ready'
		return False


	def count(self):
		return self.len

	def get_phonedb(self):
		# lists of (name, number, index)
		return self.lists

	def get_free_slot(self):
		return (self.max - self.len)

	def is_full(self):
		if self.max <= self.len:
			return True
		else:
			return False

	def pin_check(self, pin):
		if config.sim_debug:
			print 'SIM:pin_check, pin:', pin
		try:
			self.simreader.verify_chv(1, pin)
		except:
			# fail
			return False
		return True

	def insert_item(self, item):
		# item은  (name, number)
		name = item[0]
		number = item[1]

		if config.sim_debug:
			print 'SIM:insert_item(),', 'name:', name, 'number:', number

		# copy to sim 시 모든 번호앞에 0034 를 붙인다.
		if not number.startswith('00'):
			number = '0034' + number

		# name length check, len_adn
		if len(name) > self.name_max:
			#name = name[:self.name_max]
			#simreader.py 에서 max 만큼 잘라준다.
			pass
		if len(number) > self.number_max:
			number = number[:self.number_max]
		try:
			self.write_sim(name, number)
		except:
			#print 'ERROR!!!'
			import traceback
			traceback.print_exc()
			return False
		return True

	def write_sim(self, name, number):
		# index check
		idx = 1
		check = False
		while not check:
			check = True
			for i in range(self.len):
				if self.lists[i][2] == idx:
					idx += 1
					check = False
					break

		# record num check, num_adn
		# 절대 여기 들어와져서는 안됨, 이미 여기 이전에서 체크 되었음
		if idx > self.max:
			if config.sim_debug:
				print '### insert failed...'
			return
		if config.sim_debug:
			print 'SIM:insert_item, idx:', idx, 'name:', name, 'number:', number
		self.lists.append((name, number, idx))
		self.len += 1
		self.simreader.update_adn(idx, name, number)

	def find_by_name(self, name):
		# return index of list(sim record 의 인덱스가 아닌 현재 가지고 있는 리스트의 idx)
		if len(name) > self.name_max:
			name = name[:self.name_max]

		for i in range(self.len):
			if name.lower() == self.lists[i][0].lower():
				return i
		return -1

	def modify_number(self, index, name, number):
		# index: 현재 가지고 있는 리스트의 index(sim record의 index 아님...헷갈리면 안됨)

		# sim record의 index
		sim_record_index = self.lists[index][2]
		if self.lists[index][0] != name:
			# name 이랑 self.lists[index][0] 랑 다를 수 없음...여기 들어와져서는 안됨
			if config.sim_debug:
				print '### modify failed...'
			return

		# copy to sim 시 모든 번호앞에 0034 를 붙인다.
		if not number.startswith('00'):
			number = '0034' + number

		if len(name) > self.name_max:
			#name = name[:self.name_max]
			#simreader.py 에서 max 만큼 잘라준다.
			pass
		if len(number) > self.number_max:
			number = number[:self.number_max]
		try:
			self.simreader.update_adn(sim_record_index, name, number)
			self.lists[index] = (name, number, sim_record_index)
			if config.sim_debug:
				print '#### modified item:', self.lists[index]
		except:
			import traceback
			traceback.print_exc()
			return False
		return True

	def find_by_char(self, name):
		name = name.lower()
		for i in range(self.len):
			item = self.lists[i]
			if name <= item[0].lower():
				if item[0].lower().startswith(name):
					return i
		return -1#

class SIMNotifyStage(NotifyStage):
	def __init__(self, message,cb=None):
		icon = uiconfig.baloon_phonebook_icon
		NotifyStage.__init__(self, message, icon, cb)

class SIMReplaceStage(YesNoStage):
	agenda_forbidden = True
	def __init__(self, message, yes_cb, no_cb):
		icon = uiconfig.baloon_phonebook_icon
		YesNoStage.__init__(self, message, yes_cb, no_cb, '', icon)

	def handle_key(self, key):
		if key == config.Red:
			self.no_cb()
		return YesNoStage.handle_key(self, key)

class AlreadyExistStage(Stage):
	agenda_forbidden = True
	def __init__(self, item, view_cb, ignore_cb):
		# remain copy list
		icon = uiconfig.baloon_phonebook_icon
		message = item[0] + '\n' + _('already exists.')
		self.ui = baseui.BaloonMessageUI(_('VIEW'), _('IGNORE'), '', icon, message)
		self.view_cb = view_cb
		self.ignore_cb = ignore_cb

	def handle_key(self, key):
		if key == config.Menu1:
			self.view_cb()
		elif key in (config.Menu2, config.Red):
			self.ignore_cb()

class CopyFromPINCheckStage(PINInputStage):
	def __init__(self):
		PINInputStage.__init__(self, _('PIN')+':', '', _('Insert PIN'))

	def activate(self, pin):
		if sim.pin_check(pin):
			if config.sim_debug:
				print 'SIM PIN check ok'
			if phonedb.count() >= config.phone_db_size:
				stage = SIMNotifyStage(_('Impossible to copy.')+'\n'+_('Memory full.'), None)
			else:
				sim.load_list()
				stage = CopyFromStage()
			runtime.manager.change_stage(stage)
		else:
			self.ui.pin = ''
			self.ui.update()
			stage = SIMNotifyStage(_('Wrong PIN!'))
			runtime.manager.change_stage(stage)

	def destroy(self):
		PINInputStage.destroy(self)
		sim.rmmod()

class CopyToPINCheckStage(PINInputStage):
	def __init__(self):
		PINInputStage.__init__(self, _('PIN')+':', '', _('Insert PIN'))

	def activate(self, pin):
		if sim.pin_check(pin):
			if config.sim_debug:
				print 'SIM PIN check ok'
			sim.load_list()
			if sim.is_full():
				sim.rmmod()
				stage = SIMNotifyStage(_('Impossible to copy.')+'\n'+_('Memory full.'), None)
			else:
				stage = CopyToStage()

			runtime.manager.change_stage(stage)
		else:
			self.ui.pin = ''
			self.ui.update()
			stage = SIMNotifyStage(_('Wrong PIN!'))
			runtime.manager.change_stage(stage)
			sim.rmmod()

	def handle_key(self, key):
		# Red or Menu2 로 back 할시에는 sim 모듈 내리게끔
		if key == config.Red:
			sim.rmmod()
		elif key == config.Menu2:
			if self.ui.pin == '':
				sim.rmmod()
		return PINInputStage.handle_key(self, key)

class CopiedEntryStage(ListStage):
	def __init__(self, choice):
		self.title = _('COPIED ENTRIES')

		ListStage.__init__(self, choice)
		self.ui.set_left('')
		self.ui.set_right(_('EXIT'))
		self.len = len(choice)
	def handle_key(self, key):
		if key == config.Menu2:
			runtime.manager.back_stage()
		else:
			return self.ui.handle_key(key)
		return True
	def show(self):
		if self.len <= 0:
			runtime.manager.back_stage()
			return
		ListStage.show(self)


class SIMDetailViewStage(Stage):
	def __init__(self, item, copy_type, replace_cb, ignore_cb):
		if copy_type == 'copyto':
			item = PhoneItem((item[0], item[1]))
		self.item = item
		self.ui = ui.PhoneItemDetailUI(self.item)
		self.ui.set_left(_('REPLACE'))
		self.ui.set_right(_('IGNORE'))
		self.replace_cb = replace_cb
		self.ignore_cb = ignore_cb

	def handle_key(self, key):
		if key == config.Menu1:
			def yes_cb():
				runtime.manager.change_stage(SIMNotifyStage(_('Number replaced'), self.replace_cb))
			def no_cb():
				self.ignore_cb()
			stage = SIMReplaceStage(_('Replace ') + '\n' + self.item[1] + ' ?', yes_cb, no_cb)
			runtime.manager.change_stage(stage)
		elif key in (config.Menu2, config.Red):
			self.ignore_cb()
		return False

class CopyFromProgressStage(Stage):
	agenda_forbidden = True
	def __init__(self, lists=None):
		if not lists:
			lists = sim.get_phonedb()
		self.ui = ui.SIMCopyUI(_('COPY FROM SIM'), lists)
		self.total_len = len(lists)
		self.n_copied_entries = 0
		self.n_ignore_entries = 0
		self.lists = lists
		self.timer = utils.Timer(300, self.copy_from_sim)

	def handle_key(self, key):
		if key in (config.Menu2, config.Red):
			final_copied_entries = self.n_copied_entries - self.n_ignore_entries
			message = _('Copy interrupted.') + '\n' + \
				"%d " % final_copied_entries + _('entries copied.') + '\n' + \
				"%d " % (self.total_len - self.n_copied_entries) + _('not copied.')
			self.copy_interrupt(message)
			return True
		return False

	def done(self):
		if self.timer:
			self.timer = None
		final_copied_entries = self.n_copied_entries - self.n_ignore_entries
		if final_copied_entries == 0:
			runtime.manager.back_stage()
			return
		if final_copied_entries == 1:
			message = _('Selected entry copied.')
		else:
			message = _('All selected entries copied.')
		stage = SIMNotifyStage(message, None)
		runtime.manager.change_stage(stage)

	def already_exist(self, phonedb_index):
		self.timer = None
		sim_index = self.n_copied_entries
		item = phonedb.get_item(phonedb_index)
		self.n_copied_entries += 1

		def view_cb():
			def replace_cb():
				# 기존의 entry 는 지우고 number를 바꾼 new_entry 추가
				phonedb.remove(phonedb_index)
				new_item = PhoneItem(item)
				# number 필드는 새로 바꾸기
				new_item.number = self.lists[sim_index][1]
				phonedb.insert_item(new_item)

				runtime.manager.back_stage()
				if self.n_copied_entries == self.total_len:
					self.done()
					return
				if not self.timer:
					self.timer = utils.Timer(300, self.copy_from_sim)
			def ignore_cb():
				runtime.manager.back_stage()
				self.n_ignore_entries += 1
				if self.n_copied_entries == self.total_len:
					self.done()
					return
				if not self.timer:
					self.timer = utils.Timer(300, self.copy_from_sim)
			stage = SIMDetailViewStage(item, 'copyfrom', replace_cb, ignore_cb)
			runtime.manager.change_stage(stage)
		def ignore_cb():
			runtime.manager.back_stage()
			self.n_ignore_entries += 1
			if self.n_copied_entries == self.total_len:
				self.done()
				return
			if not self.timer:
				self.timer = utils.Timer(300, self.copy_from_sim)
		stage = AlreadyExistStage(item, view_cb, ignore_cb)
		runtime.manager.stack_stage(stage)

	def copy_from_sim(self):
		# memory 가 부족함에도 proceed-ok 해서 copy from 하다가 memory full 된 경우
		free_slot = config.phone_db_size - phonedb.count()
		if free_slot < 0:
			free_slot = 0
		if free_slot <= 0:
			final_copied_entries = self.n_copied_entries - self.n_ignore_entries
			message = _('Memory full.') + '\n' + \
				"%d " % final_copied_entries + _('entries copied.') + '\n' + \
				"%d " % (self.total_len - self.n_copied_entries) + _('not copied.')
			self.copy_interrupt(message)
			return False

		i = self.n_copied_entries
		self.ui.set_value(i)

		# already exist
		if config.sim_debug:
			print '######### already check, name:', self.lists[i][0]
		if phonedb.has_name(self.lists[i][0]):
			phonedb_idx = phonedb.find_by_name_near(self.lists[i][0])
			self.already_exist(phonedb_idx)
			return False

		item = PhoneItem()
		item.name = self.lists[i][0]
		item.number = self.lists[i][1]
		phonedb.insert_item(item)
		self.n_copied_entries += 1

		if self.n_copied_entries == self.total_len:
			self.done()
			return False
		return True

	def copy_interrupt(self, message):
		self.timer = None
		def cb():
			choice = []
			for i in range(self.n_copied_entries):
				choice.append(self.lists[i][0])
			stage = CopiedEntryStage(choice)
			# free_slot 이 0보다 작으면 바로 phonebook 메뉴로 나갈 수 있게 back을 한번더
			free_slot = config.phone_db_size - phonedb.count()
			if free_slot <= 0:
				runtime.manager.back_stage()
			runtime.manager.change_stage(stage)
		stage = SIMNotifyStage(message, cb)
		runtime.manager.change_stage(stage)

	def destroy(self):
		Stage.destroy(self)
		self.timer = None

class CopyToProgressStage(Stage):
	agenda_forbidden = True
	def __init__(self, lists=None):
		# lists 는  (name, number, ...) 로 된 리스트임
		if not lists:
			lists = []
			for i in range(phonedb.count()):
				lists.append(phonedb.get_item(i))

		new_lists = []
		t_mobile = runtime.evas.text(text=_('Mobile'))
		mobile = t_mobile.text_get()
		t_mobile.free()
		t_fax = runtime.evas.text(text=_('Fax'))
		fax = t_fax.text_get()
		t_fax.free()
		for item in lists:
			t = (item[0], item[1])
			new_lists.append(t)
			if item[2]:
				# mobile
				t = (item[0] + ' ' + mobile, item[2])
				new_lists.append(t)
			if item[4]:
				# mobile
				t = (item[0] + ' ' + fax, item[4])
				new_lists.append(t)
		self.ui = ui.SIMCopyUI(_('COPY TO SIM'), new_lists)
		self.total_len = len(new_lists)
		self.n_copied_entries = 0
		self.n_ignore_entries = 0
		self.lists = new_lists
		self.timer = utils.Timer(300, self.copy_to_sim)

	def handle_key(self, key):
		if key in (config.Menu2, config.Red):
			final_copied_entries = self.n_copied_entries - self.n_ignore_entries
			message = _('Copy interrupted.') + '\n' + \
				"%d " % final_copied_entries + _('entries copied.') + '\n' + \
				"%d " % (self.total_len - self.n_copied_entries) + _('not copied.')
			self.copy_interrupt(message)
			return True
		return False

	def done(self):
		if self.timer:
			self.timer = None
		final_copied_entries = self.n_copied_entries - self.n_ignore_entries
		if final_copied_entries == 0:
			runtime.manager.back_stage()
			return

		if final_copied_entries == 1:
			message = _('Selected entry copied.')
		else:
			message = _('All selected entries copied.')
		stage = SIMNotifyStage(message, None)
		runtime.manager.change_stage(stage)

	def already_exist(self, sim_index):
		self.timer = None
		phonedb_index = self.n_copied_entries
		item = self.lists[phonedb_index]
		sim_item = sim.get_phonedb()[sim_index]
		self.n_copied_entries += 1
		def view_cb():
			def replace_cb():
				# 기존의 entry에 number를 update하기
				if not sim.modify_number(sim_index, item[0], item[1]):
					#print '#### ERROR: insert_item failed...sim removed'
					self.n_copied_entries -= 1
					runtime.manager.pop_stage().destroy()
					self.copy_interrupt(_('SIM removed!')+_('Stop copying.'), sim_removed=True)
					return

				runtime.manager.back_stage()
				if self.n_copied_entries == self.total_len:
					self.done()
					return
				if not self.timer:
					self.timer = utils.Timer(300, self.copy_to_sim)
			def ignore_cb():
				runtime.manager.back_stage()
				self.n_ignore_entries += 1
				if self.n_copied_entries == self.total_len:
					self.done()
					return
				if not self.timer:
					self.timer = utils.Timer(300, self.copy_to_sim)
			stage = SIMDetailViewStage(sim_item, 'copyto', replace_cb, ignore_cb)
			runtime.manager.change_stage(stage)
		def ignore_cb():
			runtime.manager.back_stage()
			self.n_ignore_entries += 1
			if self.n_copied_entries == self.total_len:
				self.done()
				return
			if not self.timer:
				self.timer = utils.Timer(300, self.copy_to_sim)
		stage = AlreadyExistStage(sim_item, view_cb, ignore_cb)
		runtime.manager.stack_stage(stage)

	def copy_to_sim(self):
		# SIM memory 가 부족함에도 proceed-ok 해서 copy to 하다가 SIM memory full 된 경우
		free_slot = sim.get_free_slot()
		if free_slot < 0:
			free_slot = 0
		if free_slot <= 0:
			final_copied_entries = self.n_copied_entries - self.n_ignore_entries
			message = _('SIM memory full!') + '\n' + \
				"%d " % final_copied_entries + _('entries copied.') + '\n' + \
				"%d " % (self.total_len - self.n_copied_entries) + _('not copied.')
			self.copy_interrupt(message)
			return False

		i = self.n_copied_entries
		self.ui.set_value(i)

		# sim_index 는 현재 리스트에서의 인덱스임, sim에서의 record 인덱스랑 헷갈리면 안됨
		# already exist
		sim_idx = sim.find_by_name(self.lists[i][0])
		if sim_idx >= 0:
			self.already_exist(sim_idx)
			return False

		if not sim.insert_item(self.lists[i]):
			#print '#### ERROR: insert_item failed...sim removed'
			self.copy_interrupt(_('SIM removed!\nstop copying'), sim_removed=True)
			return False

		self.n_copied_entries += 1
		if config.sim_debug:
			print '########## CopyToSim, n_copied_entries:', self.n_copied_entries

		if self.n_copied_entries == self.total_len:
			self.done()
			return False
		return True

	def copy_interrupt(self, message, sim_removed=False):
		self.timer = None
		def cb():
			choice = []
			for i in range(self.n_copied_entries):
				choice.append(self.lists[i][0])
			stage = CopiedEntryStage(choice)
			# free_slot 이 0보다 작으면 바로 phonebook 메뉴로 나갈 수 있게 back을 한번더
			if sim.is_full() or sim_removed:
				runtime.manager.back_stage()
			runtime.manager.change_stage(stage)
		stage = SIMNotifyStage(message, cb)
		runtime.manager.change_stage(stage)

	def destroy(self):
		Stage.destroy(self)
		self.timer = None

class CopyFromSelectEntryStage(CheckListStage):
	title = _('SELECT ENTRIES')
	def __init__(self):
		choice = []
		# sim.get_phonedb() return lists of tuple(name, number, idx)
		self.all_lists = sim.get_phonedb()
		for i in range(len(self.all_lists)):
			choice.append(self.all_lists[i][0])
		CheckListStage.__init__(self, choice)
		self.ui.set_left(_('SELECT'))
		self.ui.set_right(_('COPY'))
		self.last_digit = '0'

	def handle_key(self, key):
		if key in '23456789':
			a_lists = {'2':'abc', '3':'def', '4':'ghi',
				'5':'jkl', '6':'mno', '7':'pqrs', '8':'tuv', '9':'wxyz'}
			alphabet = a_lists[key]
			if self.last_digit in alphabet:
				i = alphabet.find(self.last_digit) + 1
				if i >= len(alphabet):
					i = 0
				self.last_digit = alphabet[i]
			else:
				self.last_digit = alphabet[0]

			focus = sim.find_by_char(self.last_digit)
			if config.sim_debug:
				print self.last_digit, focus
			if focus >= 0:
				self.ui.set_focus(focus)
			return True

		if key == config.Menu1:
			self.ui.toggle()
		elif key == config.Menu2:
			lists = []
			for index, checked in enumerate(self.ui.list.checked):
				if checked:
					lists.append(index)
			free_slot = config.phone_db_size - phonedb.count()
			if free_slot < 0:
				free_slot = 0
			nlists = len(lists)

			# make selected_lists: selected list of tuple(name, number, idx)
			selected_lists = []
			for i in range(nlists):
				selected_lists.append(self.all_lists[lists[i]])

			if nlists == 0:
				stage = SIMNotifyStage(_('No entry selected!'))
				runtime.manager.change_stage(stage)
				return True

			if free_slot > nlists:
				stage = CopyFromProgressStage(selected_lists)
				runtime.manager.change_stage(stage)

			else:
				message = _('Memory insufficient.') + '\n' + "%d " % free_slot + \
						_('free slots.') + '\n' + _('Proceed?')
				def yes():
					stage = CopyFromProgressStage(selected_lists)
					runtime.manager.change_stage(stage)
				def no():
					runtime.manager.back_stage()
				stage = YesNoStage(message, yes, no, '', uiconfig.baloon_phonebook_icon)
				runtime.manager.change_stage(stage)
		else:
			return self.ui.handle_key(key)
		return True

class CopyToSelectEntryStage(CheckListStage):
	title = _('SELECT ENTRIES')
	def __init__(self):
		# all_lists 는  (name, number, ...) 로 된 리스트임
		self.all_lists = []
		for i in range(phonedb.count()):
			self.all_lists.append(phonedb.get_item(i))

		# name 으로만 된 choice 리스트 만듬
		choice = []
		for i in range(len(self.all_lists)):
			choice.append(self.all_lists[i][0])
		CheckListStage.__init__(self, choice)
		self.ui.set_left(_('SELECT'))
		self.ui.set_right(_('COPY'))
		self.last_digit = '0'
		self.phonedb_indexes = range(phonedb.count())

	def handle_key(self, key):
		if key in '23456789':
			a_lists = {'2':'abc', '3':'def', '4':'ghi',
				'5':'jkl', '6':'mno', '7':'pqrs', '8':'tuv', '9':'wxyz'}
			alphabet = a_lists[key]
			if self.last_digit in alphabet:
				i = alphabet.find(self.last_digit) + 1
				if i >= len(alphabet):
					i = 0
				self.last_digit = alphabet[i]
			else:
				self.last_digit = alphabet[0]

			focus = phonedb.find_by_char(self.last_digit, self.phonedb_indexes)
			if config.sim_debug:
				print self.last_digit, focus
			if focus >= 0:
				self.ui.set_focus(focus)
			return True

		if key == config.Menu1:
			self.ui.toggle()
		elif key == config.Menu2:
			lists = []
			for index, checked in enumerate(self.ui.list.checked):
				if checked:
					lists.append(index)
			free_slot = sim.get_free_slot()
			if free_slot < 0:
				free_slot = 0
			nlists = len(lists)

			# make selected_lists: selected lists of (name, number, ...)
			selected_lists = []
			for i in range(nlists):
				selected_lists.append(self.all_lists[lists[i]])

			if nlists == 0:
				stage = SIMNotifyStage(_('No entry selected!'))
				runtime.manager.change_stage(stage)
				return True

			if free_slot > nlists:
				stage = CopyToProgressStage(selected_lists)
				runtime.manager.change_stage(stage)
			else:
				message = _('Memory insufficient.') + '\n' + "%d " % free_slot + \
					_('free slots.') + '\n' + _('Proceed?')
				def yes():
					stage = CopyToProgressStage(selected_lists)
					runtime.manager.change_stage(stage)
				def no():
					runtime.manager.back_stage()
				stage = YesNoStage(message, yes, no, '', uiconfig.baloon_phonebook_icon)
				runtime.manager.change_stage(stage)
		else:
			return self.ui.handle_key(key)
		return True

class CopyFromStage(ListStage):
	name = 'copyfromstage'
	def __init__(self):
		self.title = _('COPY FROM SIM')
		self.choice = _('All entries'), _('Some entries')

		if not sim.load_list():
			def cb():
				runtime.manager.change_stage(SIMNotifyStage(_('SIM removed!')+'\n'+_('Stop loading.')))
			runtime.evas.idle_add(cb)
		ListStage.__init__(self)

	def activate(self, index):
		free_slot = config.phone_db_size - phonedb.count()
		if free_slot < 0:
			free_slot = 0
		# sim 에 저장된 데이터가 하나도 없을 경우
		if sim.count() == 0:
			stage = SIMNotifyStage(_('SIM card has no data!'))
			runtime.manager.change_stage(stage)
			return

		if index == 0:
			if sim.count() > free_slot:
				message = _('Memory insufficient.') + '\n' + "%d " % free_slot + \
					_('free slots.') + '\n' + _('Proceed?')
				def yes():
					stage = CopyFromProgressStage
					runtime.manager.change_stage(stage)
				def no():
					runtime.manager.back_stage()
				stage = YesNoStage(message, yes, no, '', uiconfig.baloon_phonebook_icon)
				runtime.manager.stack_stage(stage)
			else:
				# sim.count() <= phone's free_slot
				stage = CopyFromProgressStage
				runtime.manager.stack_stage(stage)
		else:
			def done_cb():
				stage = CopyFromSelectEntryStage
				runtime.manager.change_stage(stage)
			stage = SIMNotifyStage("%d " % free_slot + _('free slots.') + '\n' + _('Select entries to copy.'), done_cb)
			runtime.manager.stack_stage(stage)

	def destroy(self):
		sim.rmmod()
		ListStage.destroy(self)


class CopyToStage(ListStage):
# eicho add 06.09.08
	name = 'copytostage'
	def __init__(self):
		self.title = _('COPY TO SIM')
		self.choice = _('All entries'), _('Some entries')

		#sim.load_list()
		ListStage.__init__(self)

	def activate(self, index):
		free_slot = sim.get_free_slot()
		if index == 0:
			if phonedb.count() > free_slot:
				if free_slot < 0:
					free_slot = 0

				message = _('Memory insufficient.') + '\n' + "%d " % free_slot + _('free slots.') + '\n' + _('Proceed?')

				def yes():
					stage = CopyToProgressStage
					runtime.manager.change_stage(stage)
				def no():
					runtime.manager.back_stage()
				stage = YesNoStage(message, yes, no, '', uiconfig.baloon_phonebook_icon)
				runtime.manager.stack_stage(stage)
			else:
				stage = CopyToProgressStage
				runtime.manager.stack_stage(stage)
		else:
			def done_cb():
				stage = CopyToSelectEntryStage
				runtime.manager.change_stage(stage)
			stage = SIMNotifyStage("%d " % free_slot + _('free slots.') + '\n' + _('Select entries to copy.'), done_cb)
			runtime.manager.stack_stage(stage)

	def destroy(self):
		ListStage.destroy(self)
		sim.rmmod()

class WaitingInsertSIMStage(Stage):
	agenda_forbidden = True
	def __init__(self, cb):
		status.supervision_not_allowed = 1
		self.ui = baseui.BaloonMessageUI('',_('CANCEL'),'', \
			uiconfig.baloon_phonebook_icon, _('Insert SIM card.'))
		self.checker = runtime.evas.timeout_add(1000, self.check_sim_card_insertion)
		self.cb = cb

	def check_sim_card_insertion(self):
		if sim.inserted():
			self.cb()
			return False
		return True

	def handle_key(self, key):
		if key == config.Menu2:
			runtime.manager.back_stage()

	def destroy(self):
		status.supervision_not_allowed = 0
		Stage.destroy(self)
		runtime.evas.timeout_remove(self.checker)


class HasPINStage(YesNoStage):
	agenda_forbidden = True
	def __init__(self, message):
		icon = uiconfig.baloon_phonebook_icon
		YesNoStage.__init__(self, message, self.yes_cb, self.no_cb, '', icon)
		self.ui.set_left('')
		self.ui.set_right(_('BACK'))

	def yes_cb(self):
		pass
	def no_cb(self):
		runtime.manager.back_stage()

class SIMReadingStage(Stage):
	agenda_forbidden = True
	def __init__(self, start_func):
		icon = uiconfig.baloon_phonebook_icon
		message = _('Please wait for a moment.')
		self.ui = baseui.NotifyUI(message, icon)
		runtime.evas.idle_add(start_func)

def CopyFromSIMStage():
	if phonedb.count() >= config.phone_db_size:
		return SIMNotifyStage(_('Impossible to copy.')+'\n'+_('Memory full.'))
	def start():
		if sim.inserted():
			if not sim.init_sim():
				sim.rmmod()
				runtime.manager.change_stage(SIMNotifyStage(_('Not supported SIM card!')))
				return
			if sim.check_pin_enabled():
				#return CopyFromPINCheckStage()
				sim.rmmod()
				stage = HasPINStage(_('SIM PIN set.')+' '+('To copy entries from SIM, disable PIN in your mobile phone.'))
			else:
				stage = CopyFromStage()
			runtime.manager.change_stage(stage)
		else:
			def cb():
				if not sim.init_sim():
					sim.rmmod()
					runtime.manager.change_stage(SIMNotifyStage(_('Not supported SIM card!')))
					return
				if sim.check_pin_enabled():
					#stage = CopyFromPINCheckStage()
					sim.rmmod()
					stage = HasPINStage(_('SIM PIN set.')+' '+_('To copy entries from SIM, disable PIN in your mobile phone.'))
				else:
					stage = CopyFromStage()
				runtime.manager.change_stage(stage)
			runtime.manager.change_stage(WaitingInsertSIMStage(cb))
	return SIMReadingStage(start)

def CopyToSIMStage():
	def start():
		if sim.inserted():
			if not sim.init_sim():
				sim.rmmod()
				runtime.manager.change_stage(SIMNotifyStage(_('Not supported SIM card!')))
				return
			if sim.check_pin_enabled():
				#return CopyToPINCheckStage()
				sim.rmmod()
				stage = HasPINStage(_('SIM PIN set.')+' '+_('To copy entries from SIM, disable PIN in your mobile phone.'))
			else:
				if not sim.load_list():
					#print 'ERROR!!'
					sim.rmmod()
					runtime.manager.change_stage(SIMNotifyStage(_('SIM removed!')+'\n'+_('Stop loading.')))
					return

				if sim.is_full():
					sim.rmmod()
					stage = SIMNotifyStage(_('Impossible to copy.')+'\n'+_('Memory full.'))
				else:
					stage = CopyToStage()
			runtime.manager.change_stage(stage)
		else:
			def cb():
				if not sim.init_sim():
					sim.rmmod()
					runtime.manager.change_stage(SIMNotifyStage(_('Not supported SIM card!')))
					return
				if sim.check_pin_enabled():
					#stage = CopyToPINCheckStage()
					sim.rmmod()
					stage = HasPINStage(_('SIM PIN set.')+' '+_('To copy entries from SIM, disable PIN in your mobile phone.'))
				else:
					if not sim.load_list():
						#print 'ERROR!!'
						sim.rmmod()
						runtime.manager.change_stage(SIMNotifyStage(_('SIM removed!')+'\n'+_('Stop loading.')))
						return

					if sim.is_full():
						sim.rmmod()
						stage = SIMNotifyStage(_('Impossible to copy.')+'\n'+_('Memory full.'))
					else:
						stage = CopyToStage()
				runtime.manager.change_stage(stage)
			runtime.manager.change_stage(WaitingInsertSIMStage(cb))
	return SIMReadingStage(start)

sim = SIM()