#! /usr/bin/python
# -*- coding: iso-8859-1 -*-

#####################################################
#    Copyright (C) 2006 by Cesar Kallas   	
#    cesarkallas@soulivre.org   
#    http://cesarkallas.soulivre.org
#                                                                          
#    This program is free software; you can redistribute it and#or modify  
#    it under the terms of the GNU General Public License as published by 
#    the Free Software Foundation; either version 2 of the License, or     
#    (at your option) any later version.                                   
#                                                                          
#    This program is distributed in the hope that it will be useful,       
#    but WITHOUT ANY WARRANTY; without even the implied warranty of        
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         
#    GNU General Public License for more details.                          
#                                                                          
#    You should have received a copy of the GNU General Public License     
#    along with this program; if not, write to the                         
#    Free Software Foundation, Inc.,                                       
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             
#####################################################

import Log, Ambiente, Acoes
import socket, md5, time, xml.dom.minidom


class Atualizacoes(object):
	"""
	Busca atualizacoes no servidor
	"""
	
	def __init__(self):
		self.servidor = Ambiente.servidor
		self.porta = Ambiente.porta
		
		# Inicia Log 
		self.log = Ambiente.log
	
		self.acoes = Acoes.Acoes()


	def buscar(self):
		"""
		Busca arquivo XML de atualizacoes disponiveis no servidor
		"""
		self.log.info("Atualizacao: buscando atualizacoes, conexao: %s:%s", self.servidor, self.porta)
		try:
			# Cria novo socket TCP
			conexao = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			conexao.connect((self.servidor, self.porta))
			conexao.settimeout(None)
			
		except socket.error, se:
			erro = "Atualizacao: " + str(se.args[0]) + " ~ " + str(se.args[1])
			self.log.error(erro)
			raise
			return -1
		except Exception:
			self.log.error("Atualizacao: ao criar conexao com servidor")
			raise
			return -1
			
		# Busca atualizacao
		try:
			if len(Ambiente.mac_address) != 17:
				self.log.erro("Atualizacao: Mac Address invalido: " + str(Ambiente.mac_address))
				return -2
			mensagemAtualizacao = Ambiente.mac_address + " " + "consulta"
			
			# Envia pedido para buscar atualizacoes disponiveis
			conexao.sendall(mensagemAtualizacao + "\n")
			
			# Recebe md5 do arquivo xml de acoes
			resposta = conexao.recv(1024)
			conexao.sendall("IniciarTransferencia")
			
			if resposta[0:3] == "900":
				self.log.error("Atualização: Falha interna.")
				return -900

			elif resposta[0:3] == "901":
				self.log.error("Atualização: Mac Address não reconhecido pelo servidor.")
				return -901
				
			elif resposta[0:3] == "902":
				self.log.error("Atualização: Servidor falhou ao gerar atualizacoes.")
				return -902
				
			elif resposta[0:3] == "101":
				self.log.info("Atualização: Sem atualizações disponiveis no momento.")
				# Limpa lista de acoes pendentes
				self.acoes.remove(status="agendada")
				return -101
				
			elif resposta[0:3] == "100":
				self.log.info("Atualização: Atualizacoes disponiveis, buscando-as...")
				# MD5 do arquivo de atualizacoes disponiveis
				arquivoMD5 = resposta[4:32+4]

				# Faz o download das atualizacoes disponiveis
				nomeArquivo = str(time.localtime().tm_year) + "-" + str(time.localtime().tm_mon) + "-" + str(time.localtime().tm_mday) #+ "-" + str(time.localtime().tm_hour) + "-" + str(time.localtime().tm_min) + "-" + str(time.localtime().tm_sec)
				arquivoAtualizacoes = open("temp/" +  str(nomeArquivo) + ".xml", 	'wb')
				while True:
					atualizacao = conexao.recv(1024)
					if not atualizacao: 
						break
					arquivoAtualizacoes.write(atualizacao)
				
				arquivoAtualizacoes.close()
				conexao.close()

				# Gera assinatura MD5 do arquivo xml recebido, para comparacao
				arquivoAtualizacoes = open("temp/" +  str(nomeArquivo) + ".xml", 'rb')
				arquivoMD5_2 = md5.new(arquivoAtualizacoes.read())
				arquivoMD5_2 = arquivoMD5_2.hexdigest()
				arquivoAtualizacoes.close()
				
				if arquivoMD5 != arquivoMD5_2:
					print "diferente"
					self.log.error("Atualizacao: assinaturas diferentes nos arquivos de atualizacao. Informada: '" + arquivoMD5 + "' Adquirida: '" + arquivoMD5_2 + "'")
					return -3
				else:
					self.log.info("Atualizacao: download de atualizacoes realizado com sucesso!")
					
				# Recupera informacoes do arquivo de atualizacoes
				listaAcoes = self.__parseXML("temp/" +  str(nomeArquivo) + ".xml")

				# Limpa lista de acoes pendentes
				self.acoes.remove(status="agendada")

				# Adiciona as acoes no banco de dados
				for acao in listaAcoes:
					resposta = self.acoes.adiciona(acao)
					if resposta < 1:
						self.log.error("Atualizacao: ao adicionar acao na base de dados: " + str(acao))
						return -5
				self.log.info("Atualizacao: atualizacoes adicionadas com sucesso!")
				return len(listaAcoes)
			else:
				print resposta
				self.log.error("Atualizacao: Mensagem de resposta invalida do servidor: " + str(resposta))
				return -4
		except:
			raise

	
	def __parseXML(self, arquivoXML):
		"""
		Recupera acoes do arquivo de atualizacoes
		"""
		if arquivoXML == None:
			return -1
			
		listaAcoes = []
		dicAcoes = {}
		
		doc = xml.dom.minidom.parse(arquivoXML)
		opcoes = ("instalar", "atualizar", "desinstalar")
	
		# Faz o parse do xml
		for opcao in opcoes:
			for acao in doc.getElementsByTagName(opcao):

				# Seta opcao do software (instalar etc)
				dicAcoes["acao"] = str(opcao)
				dicAcoes["status_execucao"] = "agendada"
				# Busca os elementos
				for ac in acao.childNodes:
					node = ac.nodeName
					
					if node == "acao_id":
						dicAcoes["acao_id"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "acao_operador":
						dicAcoes["acao_operador"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "acao_data_criacao":
						dicAcoes["acao_data_criacao"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "acao_data_execucao":
						dicAcoes["acao_data_execucao"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_nome":
						dicAcoes["software_nome"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_versao":
						dicAcoes["software_versao"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_liberacao":
						dicAcoes["software_liberacao"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_tamanho":
						dicAcoes["software_tamanho"] = str(ac.childNodes[0].nodeValue)
					
					elif node == "software_descricao":
						dicAcoes["software_descricao"] = str(ac.childNodes[0].nodeValue)
							
					elif node == "software_grupo":
						dicAcoes["software_grupo"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_localizacao":
						dicAcoes["software_localizacao"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_plataforma":
						dicAcoes["software_plataforma"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_nomeArquivo":
						dicAcoes["software_nomeArquivo"] = str(ac.childNodes[0].nodeValue)
						
					elif node == "software_md5":
						dicAcoes["software_md5"] = str(ac.childNodes[0].nodeValue)

				listaAcoes.append(dicAcoes)
				dicAcoes={}
		return listaAcoes
