/* Núcleo do Zelador	*/

/* Libraries */
#include <libraries/mui.h>
#include <libraries/gadtools.h> /* for BARLABEL in MenuItem */

/* Prototypes */
#ifdef __GNUC__
#include <proto/muimaster.h>
#include <proto/exec.h>
#include <proto/alib.h>
#include <proto/dos.h>
#else
#include <clib/muimaster_protos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <pragmas/muimaster_pragmas.h>
#endif /* __GNUC__ */

/*  Ansi  */
#include <stdlib.h>
#include <stdio.h>

/* incluído por mim.. */
#include <string.h>
#include <time.h>
#include "ZeladorMain.h"
#include "ZeladorGUI.h"
#include "Zelador_Nucleo.h"
#include "ZeladorAREXXinterface.c"
#include "Zelador_Config.c"
#include "ZeladorFrases.h"
#include <exec/exec.h>
#include <devices/timer.h>

/* minhas variáveis..	*/
int ForcandoEvento;	/* 0-não 1-sim	*/
int StatusEvento;		/* passos de 0-idle 1-event req'ed 2-... n-fim	*/
long	ConectadoDesdeHHMM;	/* somente válido se AutoMiami estiver habilitado-- Faz parte do Varredura()	*/

void ProcessamentoCentral (void)
{
	BOOL	running = TRUE;
	ULONG	sinal;
	ULONG SinalVBLANK;
	ULONG MeusSinais;

PreparativosIniciaEvento ();
PreparativosEncerraEvento ();

	Loga("Zelador started.", 1);

   SinalVBLANK = 1 << MeuTimerVBLANK->tr_node.io_Message.mn_ReplyPort->mp_SigBit;
	FazPedidoVBLANK ();
	MeusSinais = 0;
	sinal = 0;
	StatusEvento = 0;	/* its idle	*/
	ForcandoEvento = 0;

	/* inicializações gerais antes de entrar no loop	*/
	InicializaVarsInternas ();	/* ..do zelador_config.h	*/
	CarregaConfig ();
	set(MeuApp->CHK_EventosAtivos, MUIA_Selected, DadosConfig.CHK_EventosAtivos);
	TransfereParaGUI ();
	FraseStatus (FraCocando);	/* idle string	*/

	Varredura ();	/* única utilidade de chamar isso antes é para atualizar o relógio da janela sem delay	*/

   if (!VerificaSeProgsNaMem ())	/* verifica se Miami e YAM estão na mem	*/
   	running = FALSE;

	while (running)
	{
		if ((MeusSinais&sinal) | !(sinal)) {
		switch (DoMethod(MeuApp->App,MUIM_Application_Input,&sinal))
		{
			case MUIV_Application_ReturnID_Quit:
				if (!StatusEvento)
					running = FALSE;
				break;

			/* Insert your code between the "case" statement and comment "end of case ..." */
			case FazerEventoAgora:
				if (!StatusEvento)	/* forçar evento..	*/
				{
					ForcandoEvento = 1;	/* indica que está forçando evento	*/
					StatusEvento = 1;
				}
				else						/* interromper evento..	*/
				{
					if (StatusEvento < 8000)	/* status abortando.	*/
						StatusEvento = 8000;				
				}
				break;
			/* end of case FazerEventoAgora */

			case ConfGravar:
				CarregaDaGUI ();
				TransfereParaGUI ();
				if (GravaConfig ())
					MUI_Request (MeuApp->App, 0L, 0L, FraIOError1, FraIOError2, FraIOError3);
				break;			

			/* end of case ConfGravar */

			case ConfUsar:
				CarregaDaGUI ();
				TransfereParaGUI ();
				break;
			/* end of case ConfUsar */

			case ConfCancelar:
				TransfereParaGUI ();
				break;
			/* end of case ConfCancelar */

         case AboutPedido:
				SobreAbout ();
				break;
         /* end of case AboutPedido */    

			case Processar_EFR:
				Loga("Manual Execution: Email File Request", 0);
				FraseStatus (FraProcessandoEFR);
				TrancaGUI();
				set(MeuApp->BT_FazerEvento, MUIA_Disabled, TRUE);
				ProcessaFileRequest ();
				set(MeuApp->BT_FazerEvento, MUIA_Disabled, FALSE);
				LiberaGUI();
				FraseStatus (FraCocando);
				break;
			/* end of case Processar_EFR */

			case Processar_RR:
				Loga("Manual Execution: Robot Reply", 0);
				FraseStatus (FraProcessandoRR);
				TrancaGUI();
				set(MeuApp->BT_FazerEvento, MUIA_Disabled, TRUE);
				ProcessaAutoReply ();
				set(MeuApp->BT_FazerEvento, MUIA_Disabled, FALSE);
				LiberaGUI();
				FraseStatus (FraCocando);
				break;
			/* end of case Processar_RR */


			/* End computing of IDCMP */

			default:
				break;
		}
		}

		if (running && (MeusSinais&SinalVBLANK))	/* se foi o vblank q ocorreu..	*/
		{
			Varredura();
			WaitIO (&MeuTimerVBLANK->tr_node);
			FazPedidoVBLANK();
		}
		
		if (running && sinal)
		{
			MeusSinais = Wait(sinal|SinalVBLANK);
		}
	}

	Loga("Zelador finished.", 0);
}

/* abre janela Sobre...	*/
void SobreAbout (void)
{
	char FraseTemp[1024];

	strcpy (&FraseTemp[0], "\033c\033bZelador 1.22\033n\n©1999 Daniel Mealha Cabrita\n(dancab@iname.com)\nCuritiba - BRAZIL\n\nThis application uses MUI which\nwas written by Stefan Stuntz.\033n");
	strcat (&FraseTemp[0], FraVersNaoReg);

	MUI_Request (MeuApp->App, 0L, 0L, FraSobreJan1, FraSobreJan2, &FraseTemp[0]);
}

/* código de atualização que deve ser executado de tempos em tempos	*/
void Varredura (void)
{
	char	eeps[120];	/* utilizado para retorno de string data-hora	*/

	PreencheDataHora (&eeps[0], 0);
	set(MeuApp->TXT_DataHoras, MUIA_Text_Contents, &eeps);

	/* controla tempos, aborta, inicia eventos, etc.. conforme a hora	*/
	if ((StatusEvento) && (StatusEvento < 5000))	/* tem evento acontecendo! (não em status de encerramento)	*/
	{
		if (StatusEvento >= 30)	/* se já estiver conectado no Miami..	*/
		{
			if ((!(HorarioDeQue (ConectadoDesdeHHMM) & 1)) && !ForcandoEvento)	/* ver se passou do horário de permanecer conectado	*/
				StatusEvento = 8000;
		}
		else
		{
			if ((!(HorarioDeQue (5000) & 2)) && !ForcandoEvento)	/* ver se passou do horário de 'tentar' e não estiver forçando evento..	*/
				StatusEvento = 8000;
		}
	}

	switch (StatusEvento)
	{
		case 0:
			/* se os eventos estiverem habilitados..	*/
			get(MeuApp->CHK_EventosAtivos, MUIA_Selected, &DadosConfig.CHK_EventosAtivos);
			if (DadosConfig.CHK_EventosAtivos)
			{
				/* verifica se é hora de fazer evento..	*/
				if (HorarioDeQue (5000) & 2)
				{
					Loga("Starting Event", 0);
					if (!(DadosConfig.CHK_AutoMiami))	/* para evitar ser abortado inadequadamente..	*/
					{
						StatusEvento = 30;
						ConectadoDesdeHHMM = RetornaHora ();	/* hora de início	*/
						PreparativosIniciaEvento ();
					}
					else
					{
						Loga("Dialing...", 0);
						StatusEvento = 1;
					}
				}
			}
			break;

		case 1:
			ConectadoDesdeHHMM = RetornaHora ();	/* hora de inicio	*/
			PreparativosIniciaEvento ();
			StatusEvento = 10;
			
		case 10:
			if (DadosConfig.CHK_AutoMiami)
			{
				FraseStatus (FraLigandoMiami);
				EnviaComandoREXX ("MIAMI.1", "ONLINE");
				StatusEvento = 20;
			}
			else
				StatusEvento = 30;
			break;
			
		case 20:
			if (CodRetorno() != 65535)
			{
				if (!CodRetorno())	/* se CodRetorno() = 0	*/
				{
					ConectadoDesdeHHMM = RetornaHora ();	/* hora da conexão	*/
					StatusEvento = 25;	/* conectado! (er.. não necessariamente)	*/
				}
				else
					StatusEvento = 10;
			}
			break;

		case 25:
			/* pede confirmação de conexão do Miami	*/
			EnviaComandoREXX ("MIAMI.1", "ISONLINE");
			StatusEvento = 26;
			
		case 26:
			if (CodRetorno() != 65535)
			{
				if (CodRetorno())	/* se CodRetorno() = 1 (conectado)	*/
				{
					ConectadoDesdeHHMM = RetornaHora ();	/* hora da conexão	*/
					Loga("Connected.", 0);
					StatusEvento = 30;	/* EFETIVAMENTE conectado! */
				}
				else
					StatusEvento = 10;	/* naahh..	*/
			}
			break;
			
		case 30:
			if (DadosConfig.CHK_EnviarYAM)
			{
				Loga("Sending mails...", 0);
				FraseStatus (FraSendYAM);
				EnviaComandoREXX ("YAM", "mailsendall");
				StatusEvento = 40;
			}
			else
				StatusEvento = 50;
			break;
			
		case 40:
			if (CodRetorno() != 65535)
			{
				if (!CodRetorno())	/* se CodRetorno() = 0	*/
					StatusEvento = 50;	/* enviados os mails!	*/
				else
					StatusEvento = 30;
			}
			break;
			
		case 50:
			if (DadosConfig.CHK_ReceberYAM)
			{
				Loga("Receiving mails...", 0);
				FraseStatus (FraRecYAM);
				EnviaComandoREXX ("YAM", "mailcheck");
				StatusEvento = 60;
			}
			else
				StatusEvento = 70;
			break;
			
		case 60:
			if (CodRetorno() != 65535)
			{
				if (!CodRetorno())	/* se CodRetorno() = 0	*/
					StatusEvento = 70;	/* recebidos os mails!	*/
				else
					StatusEvento = 50;
			}
			break;

		case 70:
			if (DadosConfig.CHK_Ativo1)
			{
				Loga("Executing custom #1", 0);
				FraseStatus (FraCustom1);
				ExecutaComandoCLI (&DadosConfig.PString1[0], DadosConfig.CHK_Espera1);
			}
			StatusEvento = 80;
			break;
			
		case 80:
			if (DadosConfig.CHK_Ativo2)
			{
				Loga("Executing custom #2", 0);
				FraseStatus (FraCustom2);
				ExecutaComandoCLI (&DadosConfig.PString2[0], DadosConfig.CHK_Espera2);
			}
			StatusEvento = 90;
			break;
			
		case 90:
			if (DadosConfig.CHK_Ativo3)
			{
				Loga("Executing custom #3", 0);
				FraseStatus (FraCustom3);
				ExecutaComandoCLI (&DadosConfig.PString3[0], DadosConfig.CHK_Espera3);
			}
			StatusEvento = 95;
			break;

		/* EFR online	*/
		case 95:
			if ((DadosConfig.CHK_FileRequest) && (DadosConfig.CHK_EFRScanWhileConnected))
			{
				Loga("Processing Email File Request...", 0);
				FraseStatus (FraProcessandoEFR);			
				ProcessaFileRequest ();
			}
			StatusEvento = 96;
			break;
			
		/* RR online	*/
		case 96:
			if ((DadosConfig.CHK_HabilitaRobotReply) && (DadosConfig.CHK_RRScanWhileConnected))
			{
				Loga("Processing Robot Reply...", 0);
				FraseStatus (FraProcessandoRR);
				ProcessaAutoReply ();
			}
			StatusEvento = 97;
			break;

		/* envia novamente emails, caso tenha sido selecionado processing while connected	*/
		case 97:
			if ((DadosConfig.CHK_EnviarYAM) &&
			 ((DadosConfig.CHK_RRScanWhileConnected)
			 |(DadosConfig.CHK_EFRScanWhileConnected)))
			{
				Loga("Sending mails...", 0);
				FraseStatus (FraSendYAM);
				EnviaComandoREXX ("YAM", "mailsendall");
				StatusEvento = 98;
			}
			else
				StatusEvento = 100;
			break;
			
		case 98:
			if (CodRetorno() != 65535)
			{
				if (!CodRetorno())	/* se CodRetorno() = 0	*/
					StatusEvento = 100;	/* enviados os mails!	*/
				else
					StatusEvento = 97;
			}
			break;	
		
		case 100:
			if (DadosConfig.CHK_AutoMiami)
			{
				Loga("Disconnecting...", 0);
				FraseStatus (FraDesligaMiami);
				EnviaComandoREXX ("MIAMI.1", "OFFLINE");
				StatusEvento = 110;
			}
			else
				StatusEvento = 200;
			break;
			
		case 110:
			if (CodRetorno() != 65535)
			{
				if (!CodRetorno())	/* se CodRetorno() = 0	*/
					StatusEvento = 200;	/* DESconectado!	*/
				else
					StatusEvento = 100;
			}
			break;

		/* EFR offline	*/
		case 200:
			if ((DadosConfig.CHK_FileRequest) && (!DadosConfig.CHK_EFRScanWhileConnected))
			{
				Loga("Processing Email File Request...", 0);
				FraseStatus (FraProcessandoEFR);			
				ProcessaFileRequest ();
			}
			StatusEvento = 300;
			break;
			
		/* RR offline	*/
		case 300:
			if ((DadosConfig.CHK_HabilitaRobotReply) && (!DadosConfig.CHK_RRScanWhileConnected))
			{
				Loga("Processing Robot Reply...", 0);
				FraseStatus (FraProcessandoRR);
				ProcessaAutoReply ();
			}
			StatusEvento = 5000;
			break;

		case 5000:	/* FIM!!!!	*/
			Loga("Event finished normally.", 0);
			FraseStatus (FraCocando);
			PreparativosEncerraEvento ();
			ForcandoEvento = 0;
			StatusEvento = 0;	/* FIM!	*/
			break;
			
		case 8000:	/* ABORTA evento	*/
			Loga("Aborting event...", 0);
			FraseStatus (FraAbortando);
			if (DadosConfig.CHK_AutoMiami)
			{
				Loga("Disconnection is being forced...", 0);
				ExecutaComandoCLI ("rx \"ADDRESS MIAMI.1 OFFLINE\" >NIL:", 0);
			}
			StatusEvento = 8005;
			break;

		case 8005:
			FraseStatus (FraEsperandoFinalizar);
			StatusEvento = 8010;

		case 8010:
			if (CodRetorno() != 65535)
			{
				PreparativosEncerraEvento ();
				StatusEvento = 0;
			}
			break;
	}

}

/* retorna hora HHMMSS em minutos -- dos.library	*/
long RetornaHora (void)
{
	struct DateStamp DataEstampa;	/* poderá ser necessário alocar isso em PUBLIC MEM	*/
	DateStamp (&DataEstampa);
	return long (DataEstampa.ds_Minute);
}

/* dado o pointer, o preenche com string de data e hora		*/
/* a string receptora deve ser pelo menos 2 * LEN_DATSTRING	*/
/* se tipoData=0, string para janela do zelador	*/
/* se tipoData<>0, string para LOG					*/
void PreencheDataHora (char * OndeEsta, int tipoData)
{
	struct DateTime DataHora;			/* poderá ser necessário alocar isso em PUBLIC MEM	*/
	char DataString [LEN_DATSTRING]; /* idem acima	*/
	char HoraString [LEN_DATSTRING];	/* idem acima	*/
	char Espac[] = "  ";
	struct tm *tempo;
	time_t tempo2;
	
	if (!tipoData)
	{
		DateStamp (&DataHora.dat_Stamp);
		DataHora.dat_Format = 4;			/* FORMAT_DEF	*/
		DataHora.dat_Flags = 0;
		DataHora.dat_StrDay	= 0;
		DataHora.dat_StrDate = DataString;
		DataHora.dat_StrTime = HoraString;	
		DateToStr (&DataHora);

		*OndeEsta = char (0);
		strcat (OndeEsta, DataString);
		strcat (OndeEsta, Espac);
		strcat (OndeEsta, HoraString);
	}
	else
	{
		time(&tempo2);
		tempo=gmtime(&tempo2);
		strftime(OndeEsta, 100, "%d/%m/%Y %I:%M:%S", tempo);
	}
}

/* preenche campos do iorequest e faz um sendio para o timer.device	*/
void FazPedidoVBLANK (void)
{
	MeuTimerVBLANK->tr_node.io_Command = TR_ADDREQUEST;
	MeuTimerVBLANK->tr_time.tv_secs = 1;
	MeuTimerVBLANK->tr_time.tv_micro = 0;
	SendIO (&MeuTimerVBLANK->tr_node);
}

/* muda conteúdo do campo 'status' da gui	*/
void FraseStatus (char * mifrase)
{
	set(MeuApp->TXT_Status, MUIA_Text_Contents, mifrase);	
}

/* ao iniciar evento (forçado ou não)	*/
/* ou processar EFR RR q não seja por evento	*/
void PreparativosIniciaEvento (void)
{
	TrancaGUI();
	set(MeuApp->BT_FazerEvento, MUIA_Text_Contents, FraAbortarEvento);
	FraseStatus (FraInicioEvento);
}

/* desabilita os botões e etc..	*/
void TrancaGUI (void)
{
	/* desabilita certos objetos a fim de evitar 'acidentes'	*/
	set(MeuApp->MN_Config, MUIA_Menuitem_Enabled, FALSE);
	set(MeuApp->MN_Sobre, MUIA_Menuitem_Enabled, FALSE);
	set(MeuApp->MN_Sair, MUIA_Menuitem_Enabled, FALSE);
	set(MeuApp->BT_Config, MUIA_Disabled, TRUE);
	set(MeuApp->CHK_EventosAtivos, MUIA_Disabled, TRUE);

	set(MeuApp->MN_EFR, MUIA_Menuitem_Enabled, FALSE);
	set(MeuApp->MN_RR, MUIA_Menuitem_Enabled, FALSE);

	/* fecha janela de config para evitar 'acidentes'	*/
	set(MeuApp->Janela_Config, MUIA_Window_Open, FALSE);
}

/* habilita os botões e etc..	*/
void LiberaGUI (void)
{
	TransfereParaGUI ();	/* restaura gui do setup, caso user tenha modificado (mas não constante nas vars)	*/

	/* desab eventos (a fim de evitar perda de controle em caso de config errada)	*/
	DadosConfig.CHK_EventosAtivos = FALSE;
	set(MeuApp->CHK_EventosAtivos, MUIA_Selected, DadosConfig.CHK_EventosAtivos);

	/* torna objetos novamente habilitados	*/
	set(MeuApp->MN_Config, MUIA_Menuitem_Enabled, TRUE);
	set(MeuApp->MN_Sobre, MUIA_Menuitem_Enabled, TRUE);
	set(MeuApp->MN_Sair, MUIA_Menuitem_Enabled, TRUE);
	set(MeuApp->BT_Config, MUIA_Disabled, FALSE);
	set(MeuApp->CHK_EventosAtivos, MUIA_Disabled, FALSE);

	set(MeuApp->MN_EFR, MUIA_Menuitem_Enabled, TRUE);
	set(MeuApp->MN_RR, MUIA_Menuitem_Enabled, TRUE);
}

/* ao encerrar evento (normalmente ou interrompendo) (forçado ou não)	*/
/* ou processar EFR RR q não seja por evento	*/
void PreparativosEncerraEvento (void)
{
	LiberaGUI();
	set(MeuApp->BT_FazerEvento, MUIA_Text_Contents, FraFazerEvento2);
	FraseStatus (FraCocando);
}

/* retorna o qualificador da hora atual	*/
/* 0-nada 1-bom para manter-se conectado 3-bom para discar/manter-se conectado	*/
/* 2-bom somente para discar	*/
/* dado, se disponível, o horário em que conectou c/o Miami	(hora a qual irá considerar como inicial) */
int HorarioDeQue (int HorConectou)
{
	int HoraAtual;
	int QuandoAcaba;	/* horário em q/o evento acaba	*/
	int LesFlags;		/* usado p/ composição do código de saída	*/

	HoraAtual = RetornaHora ();
	LesFlags = 0;

	/* verifica se é hora de fazer evento..	*/
	if (DadosConfig.Inicio<DadosConfig.TentarAte)
	{
		if ((HoraAtual >= DadosConfig.Inicio) && (HoraAtual <= DadosConfig.TentarAte))
			LesFlags = LesFlags | 2;
	}
	else
	{
		if ((HoraAtual >= DadosConfig.Inicio) || (HoraAtual <= DadosConfig.TentarAte))
			LesFlags = LesFlags | 2;
	}

	/* CYC_DuracTempo  0-por duração   1-por horário	*/
	if (DadosConfig.CYC_DuracTempo)	/* 1-por horário	*/
		QuandoAcaba = DadosConfig.Limite;
	else
	{
		if (HorConectou >= 1440)	/* hora inválida	*/
			QuandoAcaba = DadosConfig.Inicio + DadosConfig.Limite;
		else
			QuandoAcaba = HorConectou + DadosConfig.Limite;

		if (QuandoAcaba >= 1440)	/* passou da meia-noite, compensa...	*/
			QuandoAcaba = QuandoAcaba - 1440;		
	}

	/* verifica, finalmente, se está em horário de manter-se conectado...	*/
	/* if (DadosConfig.Inicio<DadosConfig.TentarAte)  <-- orig com erro	*/
	if (DadosConfig.Inicio<QuandoAcaba)
	{
		if ((HoraAtual >= DadosConfig.Inicio) && (HoraAtual <= QuandoAcaba))
			LesFlags = LesFlags | 1;
	}
	else
	{
		if ((HoraAtual >= DadosConfig.Inicio) || (HoraAtual <= QuandoAcaba))
			LesFlags = LesFlags | 1;
	}
	
	return(LesFlags);
}

/* verifica se Miami e YAM estão na mem	*/
/* retorna 0-QUIT_Zelador  1-prosseguir	*/
int VerificaSeProgsNaMem (void)
{
	long int tempPutz;
	long tempVerifCoisas = 1;
	long tempOpt;
	char tempBuff[512];

	while (tempVerifCoisas)
	{	
		tempPutz = 0;
		tempBuff[0] = char(0);
		strcat (&tempBuff[0], FraNaoDetectado1);

		if (EnviaEEsperaComandoREXX ("MIAMI.1", "ISONLINE") > 2)
		{
			strcat (&tempBuff[0], FraNaoDetectadoMiami);
			tempPutz = 1;		
		}
		
		/* o abaixo dá erro (-3) por ser comando inválido, mas como -3 < 4...	*/
		if (EnviaEEsperaComandoREXX ("YAM", "setfolder 0") != 0)
		{
			strcat (&tempBuff[0], FraNaoDetectadoYAM);
			tempPutz = 1;
		}

		if (tempPutz)
		{
			strcat (&tempBuff[0], FraNaoDetectado2);
			if (!(tempOpt = MUI_Request (MeuApp->App, 0L, 0L, FraNaoDetectado3, FraNaoDetectado4, &tempBuff[0])))
				return(0);

			if (tempOpt == 2)
				return(1);
		}
		else
			return(1);
	}
}

/* processa Robot Reply	*/
void ProcessaAutoReply (void)
{
	char tempstr[256];
	char tempstrX[256];
	long temploop;
	short int eh_igual_a;	/* 0 a 9 ou -1 se nada	*/
	short int tempcont;
	long nummsgs;
	FILE * atsub;	/* arq-texto c/os subjects	*/
	char tempComandoYAM[256];	/* usado p/ pegar o remetente da msg	*/
	char tempParaQuem[256];		/* contém o remetente da msg				*/

	MinimizaYAM();	/* minimiza YAM, caso contrário a parte seguinte fica uma carroça	*/
	VarreSubjectsYAM ();

	EnviaComandoYAM ("setfolder 0", tempstr, 250);
	EnviaComandoYAM ("getfolderinfo MAX", tempstr, 250);
	nummsgs = strtoul (tempstr, 0, 10);

	temploop = nummsgs-1;

	if (atsub=fopen("t:Zelador.temp", "r"))
	{
		while (temploop>-1)
		{
			fgets (tempstr, 250, atsub);
			ArrumaString(tempstr);

			tempcont = 10;
				
			eh_igual_a = -1;
			while (tempcont)
			{
				tempcont--;		
				/* se coincidir subject e estiver ativada a string..	*/
				strcpy(tempstrX, DadosConfig.RR[tempcont].STR);
				ArrumaString(tempstrX);
				if ((!stricmp(tempstrX, tempstr)) && DadosConfig.RR[tempcont].CHK)
					eh_igual_a = tempcont;		
			}

			/* se coincidiu com algo, envia msg	*/
			if (eh_igual_a != -1)
			{
				sprintf(tempComandoYAM, "setmail %d;getmailinfo STA", temploop);
				EnviaComandoYAM (tempComandoYAM, tempParaQuem, 250);
				
				if (strcmp(tempParaQuem, "R"))	/* se <>"R" (not replied)..	*/
				{
					RespondeMsgYAM (temploop, DadosConfig.RR[eh_igual_a].POP, DadosConfig.RR[eh_igual_a].STR, 0L);
					EnviaComandoYAM ("writequeue", tempstr, 250);	

					/* processa log...	*/
					sprintf(tempComandoYAM, "setmail %d;getmailinfo REP", temploop);
					EnviaComandoYAM (tempComandoYAM, tempParaQuem, 250);
					LogRR("Request Processed", 1);
					LogRR(tempParaQuem, 0);
					LogRR(DadosConfig.RR[eh_igual_a].STR, 0);
				}
				
				/* apaga a msg */
				ApagaMsgYAM(temploop);			
			}		

			temploop--;
		}

		fclose (atsub);
	}

	ApagaArqTempSubjectsYAM ();
}

/* abre texto de reply p/a msg indicada e indica arquivo-texto
   de resposta.. e arq-texto opcional-- porém NAO fecha (writemailqueue)	*/
void RespondeMsgYAM (long qual, char * ArqTxtResposta, char * Assunt, char * ArqTxtExtra)
{
	char tempstr[256];
	char tempstr_frase[256];
	FILE * tempArqResp;	/* arq texto que, efetivamente, será enviado p/o YAM	*/
	FILE * tempArqLeitura;	/* arqs lidos..	*/
	long tempTamArqResp;
	long tempTamArqLista;
	void * tempMemVec;
	char tempFraseFinal[256];	/* usado p/ escrever 'made by Zelador 1.22 etc e tal'	*/

	if (tempArqResp=fopen("t:ZeladorResp.temp", "wb"))
	{
		tempTamArqResp=RetornaTamanhoArq(ArqTxtResposta);
		tempTamArqLista=RetornaTamanhoArq(ArqTxtExtra);

		if (tempTamArqResp|tempTamArqLista)	/* se não for o caso de ambos serem zero..	*/
		{
			if (tempTamArqResp > tempTamArqLista)
				tempMemVec=AllocVec(tempTamArqResp, 0L);
			else
				tempMemVec=AllocVec(tempTamArqLista, 0L);
		}
			
		if (tempMemVec)	/* se realmente alocou a memória..	*/
		{
			if (tempTamArqResp) /* se tamanho não for nulo..	*/
			{
				if (tempArqLeitura=fopen(ArqTxtResposta, "rb"))
				{
					fread(tempMemVec, tempTamArqResp, 1, tempArqLeitura);	
					fclose(tempArqLeitura);
					fwrite(tempMemVec, tempTamArqResp, 1, tempArqResp);
				}
			}

			if (ArqTxtExtra)	/* se pointer não for nulo..	*/
			{
				if (tempTamArqLista) /* se tamanho não for nulo..	*/
				{
					if (tempArqLeitura=fopen(ArqTxtExtra, "rb"))
					{
						fread(tempMemVec, tempTamArqLista, 1, tempArqLeitura);	
						fclose(tempArqLeitura);
						fwrite(tempMemVec, tempTamArqLista, 1, tempArqResp);
					}
				}
			}			

			sprintf(tempFraseFinal, "\n\n * reply automatically generated by Zelador 1.22 for Amiga OS\n\n");
			fwrite(tempFraseFinal, strlen(tempFraseFinal), 1, tempArqResp);
		
			FreeVec(tempMemVec);		
		}

		fclose(tempArqResp);
	}

	sprintf(tempstr_frase, "setmail %d;mailreply", qual);
	EnviaComandoYAM (tempstr_frase, tempstr, 250);

	ComandoRexxEspecial ("writesubject", Assunt);
	ComandoRexxEspecial ("writeletter", "t:ZeladorResp.temp");

	remove("t:ZeladorResp.temp");
}

/* executa comandos 'dfssfd "dfdfdfa"'	*/
/* dados: comando e string do comando (nome de arq, subject, etc etc..)	*/
void ComandoRexxEspecial (char * comesp, char * dadocomesp)
{
	char frase[256];

	sprintf (frase, "rx \"ADDRESS YAM;'%s \"\"%s\"\"'\"", comesp, dadocomesp);
	system (frase);
}

/* carrega subjects do folder 0 do YAM na memória	*/
/* processa-los um a um com RX é muito lento			*/
void VarreSubjectsYAM (void)
{
	system ("rx scrp2 >t:Zelador.temp");
}

/* apaga o arquivo gerado pelo 'VarreSubjectsYAM' no T:	*/
void ApagaArqTempSubjectsYAM (void)
{
	remove("t:Zelador.temp");
}

/* elimina espaços e/ou LFs que estejam no final da string	*/
void ArrumaString (char * frase)
{
	int repe;
	short int coisa;
	
	if (repe=strlen(frase))	/* se string >0..	*/
	{
		repe--;
		coisa=short int(*(frase+repe));
	
		while (((coisa == 32) || (coisa == 10)) && (repe))
		{
			repe--;
			coisa=short int(*(frase+repe));
		}

		if ((coisa == 32) || (coisa == 10))
			*(frase+repe) = char(0);
		else
			*(frase+repe+1) = char(0);
	}
}

/* dada uma string, retorna o checksum (byte) dos bytes da mesma	*/
UBYTE RetornaCheckSumString (char * frase)
{
	char * tempp=frase;
	UBYTE tempcs=0;
	UBYTE tempv;

	while (tempv=UBYTE(*(tempp)))
	{
		tempcs = tempcs + tempv;
		tempp++;	
	}

	return(tempcs);
}

/* gera ID p/ 'file request por email' dado o email de origem	*/
long GeraIDMFR (char * email)
{
	struct DateStamp datasta;
	long meucs;	/* checksum da string fornecida	*/
	long tempID;

	DateStamp (&datasta);
	meucs = long (RetornaCheckSumString (email));
	tempID=datasta.ds_Days ^ (meucs | (meucs<<7));
	tempID=tempID ^ ((tempID & 0xFF)<<8);

	return (tempID);
}

/* verifica o ID do 'file request por email' dado o email,	*/
/* o ID a verificar e o número de dias q/o ID é válido	*/
/* true-se ID válido, false-se não	*/
long VerificaIDMFR (char * email, long meuID, long dias)
{
	struct DateStamp datasta;
	long meucs;				/* checksum da string fornecida	*/
	long tempDia;			/* dia retornado						*/
	long tempDiff;

	DateStamp (&datasta);
	meucs = long (RetornaCheckSumString (email));

	tempDia = meuID ^ ((meuID & 0xFF)<<8);
	tempDia = tempDia ^ (meucs | (meucs<<7));

	tempDiff=datasta.ds_Days-tempDia;
	if ((tempDiff<dias)&&(tempDiff>=0))	/* para um limite de 5 dias..	*/
	{
		return (1);
	}

	return (0);
}

/* processa EFR	*/
void ProcessaFileRequest (void)
{
	char tempstr[256];
	char tempstrX[256];
	long temploop;
	long nummsgs;
	FILE * atsub;	/* arq-texto c/os subjects	*/
	char tempSubReduzido[256];	/* subject de comprimento reduzido para comparação primária	*/
	char tempSubCriado[256];	/* subject a enviar, com o ID adicionado	*/
	char tempParaQuem[256];		/* email do usuário q fez o request	*/
	char tempComandoYAM[256];
	void * tempPoinParam;		/* pointer do "5ab875d 2 3 4 7 8..."	*/
	long tempIDfornecido;		/* ID lido da mensagem	*/
	long tAP[10];	/* array c/os arqs pedidos: 0-null 1-10 nº do arq	*/

	long tempLimPE;	/* limite bytes por evento	*/
	long tempComApg;	/* a partir de XXX bytes, começa a apagar msgs	*/
	long tempKBatual=0;	/* KB já feitos nesse evento	*/
	long tempKBproposto;	/* tempKBatual + kb pedido msg atual -- para ver se não vai estrapolar	*/	
	long tempCont;
	char AttachFrase[768];	/* para o rexx, com o nome do arq e descrição	*/
	char tempstrO[256];		/* tempstr sem o '0 0 0 0 0..'	*/
	char tempParaLog[256];	/* relação com os números dos arqs, para o LOG	*/
	char tempParaLogAux[32];

	tempLimPE = strtoul(DadosConfig.STR_MaxPedidoKbEvento, 0, 10);
	tempComApg = strtoul(DadosConfig.STR_RecusaAPartirKB, 0, 10);

	MinimizaYAM();	/* minimiza YAM, caso contrário vai ficar uma carroça a parte a seguir	*/
	VarreSubjectsYAM ();

	EnviaComandoYAM ("setfolder 0", tempstr, 250);
	EnviaComandoYAM ("getfolderinfo MAX", tempstr, 250);
	nummsgs = strtoul (tempstr, 0, 10);

	temploop = nummsgs-1;

	if (atsub=fopen("t:Zelador.temp", "r"))
	{	
		/* subject a interceptar - nunca muda, então fica aqui	*/
		strcpy(tempstrX, DadosConfig.STR_AssuntoIntercepta);
		ArrumaString(tempstrX);

		while ((temploop>-1) && nummsgs)
		{
			fgets (tempstr, 230, atsub);
			ArrumaString(tempstr);
			/* cria 'zeros' de segurança na string para evitar que a
				sujeira seja interpretada como dado pelo sscanf(xxxxxxxx)	*/
			strcpy(tempstrO, tempstr);
			strcat(tempstr, " 0 0 0 0 0 0 0 0 0 0 0");	/* dez slots + ID para maior segurança	*/

			/* AQUI, verifica se o tópico coincide com algo (first request, second request ou nada)	*/

			/* subject atual, reduzido para comparação	*/
			strcpy(tempSubReduzido, tempstr);
			tempSubReduzido[strlen(tempstrX)]=char(0);	/* torna-a do mesmo tamanho que a do assunto	*/

			if (!stricmp(tempstrX, tempSubReduzido))
			{
				sprintf(tempComandoYAM, "setmail %d;getmailinfo STA", temploop);
				EnviaComandoYAM (tempComandoYAM, tempParaQuem, 250);
				
				if (strcmp(tempParaQuem, "R"))	/* se <>"R" (not replied)..	*/
				{

				/* *** */

				/* pega endereço de email correspondente a msg	*/
				sprintf(tempComandoYAM, "setmail %d;getmailinfo REP", temploop);
				EnviaComandoYAM (tempComandoYAM, tempParaQuem, 250);

				if (strlen(tempstrX)==strlen(tempstrO))	/* se for request primário..	*/
				{
					sprintf(tempSubCriado, "%s %p", tempstrO, GeraIDMFR (tempParaQuem));
					CriaArqTxtListagem("t:ZeladorList.temp");
					RespondeMsgYAM (temploop, DadosConfig.POP_TxtApresentacao, tempSubCriado, "t:ZeladorList.temp");
					remove("t:ZeladorList.temp");
					EnviaComandoYAM ("writequeue", tempstr, 250);

					LogEFR("Primary request processed", 1);
					LogEFR(tempParaQuem, 0);
					
					/* apaga a msg */
					ApagaMsgYAM(temploop);
				}
				else
				{
					/* tempstr=full tempstrX=só o intercept	*/
					tempPoinParam=tempstr+strlen(tempstrX);
					sscanf(tempPoinParam, "%x %d %d %d %d %d %d %d %d %d %d", &tempIDfornecido,
						&tAP[0], &tAP[1], &tAP[2], &tAP[3], &tAP[4],
						&tAP[5], &tAP[6], &tAP[7], &tAP[8], &tAP[9]);
					/* se ID fornecido for válido, processa request	*/
					if (VerificaIDMFR (tempParaQuem, tempIDfornecido, strtoul(DadosConfig.STR_MaxDaysValidID, 0, 10)))
					{
						/* calcula KBs do request da msg atual..	*/
						tempParaLog[0]=char(0);
						tempCont=10;
						tempKBproposto=tempKBatual;
						while (tempCont)
						{
							tempCont--;						
							if ((tAP[tempCont]) && (tAP[tempCont]<11))	/* se <> 0 e <11adiciona da contagem de KB	*/
								tempKBproposto=tempKBproposto+(RetornaTamanhoArq(DadosConfig.Req[tAP[tempCont]-1].POP)>>10);

							/* p/o log..	*/
							if (tAP[tempCont])	/* se != 0 (válido, portanto)	*/
							{
								sprintf(tempParaLogAux, "%d ", tAP[tempCont]);
								strcat (tempParaLog, tempParaLogAux);
							}
						}
						
						if (tempKBproposto < tempLimPE)	/* se for possível incluir ainda nesse evento..	*/
						{
							/* responde msg..	*/
							RespondeMsgYAM (temploop, DadosConfig.POP_EnviandoArq, tempstrX, 0L);

							/* attacha os arquivos pedidos pelo usuário..	*/
							tempCont=10;
								
							while (tempCont)
							{
								tempCont--;						
								if ((tAP[tempCont]) && (tAP[tempCont]<11))	/* se <> 0 e <11 faz o attach	*/
								{
									sprintf (AttachFrase, "rx \"ADDRESS YAM;'writeattach \"\"%s\"\" \"\"%s\"\"'\"", DadosConfig.Req[tAP[tempCont]-1].POP, DadosConfig.Req[tAP[tempCont]-1].STR);
									system (AttachFrase);
								}							
							}

							/* finaliza pacote com msg e arquivos attachados	*/
							EnviaComandoYAM ("writequeue", tempstr, 250);

							/* apaga a msg (já foi processada mesmo..)	*/
							ApagaMsgYAM(temploop);

							LogEFR("Secondary request processed", 1);
							LogEFR(tempParaQuem, 0);
							LogEFR(tempParaLog, 0);
							sprintf(tempParaLog, "%d Kb total", (tempKBproposto-tempKBatual));
							LogEFR(tempParaLog, 0);
							
							tempKBatual=tempKBproposto;
						}
						else
						{
							if (tempKBproposto > tempComApg)	/* não vai nesse evento e, pior, já entra como 'para apagamento'	*/
							{
								/* excedeu ambos os limites de KB e será apagado.. */
								LogEFR("Secondary request not processed - Beyond both KB limit. Deleted.", 1);
								LogEFR(tempParaQuem, 0);
								LogEFR(tempParaLog, 0);
								sprintf(tempParaLog, "%d Kb total", (tempKBproposto-tempKBatual));
								LogEFR(tempParaLog, 0);

								/* apaga a msg */
								ApagaMsgYAM(temploop);
							}
							else
							{
								/* excedeu o limite de evento MAS não será apagado.. */
								LogEFR("Secondary request not processed - Beyond KB/event limit. Skipped for later.", 1);
								LogEFR(tempParaQuem, 0);
								LogEFR(tempParaLog, 0);
								sprintf(tempParaLog, "%d Kb total", (tempKBproposto-tempKBatual));
								LogEFR(tempParaLog, 0);								
							}
						}															
					}
					else
					{
						LogEFR("Secondary request not processed - Invalid ID given by user", 1);
						LogEFR(tempParaQuem, 0);
						LogEFR(tempstrO, 0);
						
						/* apaga a msg */
						ApagaMsgYAM(temploop);
					}
				}		

				/* *** */
				}
				else	/* mensagem já respondida; resta apenas deletá-la	*/
				{
					/* apaga a msg */
					ApagaMsgYAM(temploop);
				}
			}
			/* AQUI termina a parte de verificação do tópico	*/

			temploop--;
		}
		
		fclose (atsub);
	}

	ApagaArqTempSubjectsYAM ();
}

/* retorna o tamanho do arquivo indicado	*/
long RetornaTamanhoArq(char * frase)
{
	FILE * tempA;
	long tempTam = 0;
	
	if (tempA=fopen(frase, "rb"))
	{	
		fseek(tempA, 0, SEEK_END);
		tempTam=ftell(tempA);
		fclose(tempA);
	}

	return (tempTam);
}

/* cria arq texto c/a listagem dos arquivos do EFR	*/
void CriaArqTxtListagem(char * frase)
{
	FILE * ArqList;
	char * PosBarra;
	char * PosDoispontos;
	char * PointCorreto;
	short int temploop=0;
	char minhafrase[512];
	
	if (ArqList=fopen(frase, "w"))
	{
		while (temploop < 10)
		{
			if (DadosConfig.Req[temploop].CHK)
			{
				PosBarra = strrchr(DadosConfig.Req[temploop].POP, '/');
				PosDoispontos = strrchr(DadosConfig.Req[temploop].POP, ':');

				if (PosBarra > PosDoispontos)
					PointCorreto = PosBarra;
				else
					PointCorreto = PosDoispontos;
					
				if (!PointCorreto)	/* se não existir nem barra nem doispontos..	*/
					PointCorreto = DadosConfig.Req[temploop].POP;
				else
					PointCorreto++;

				sprintf(minhafrase, "[%d] %s (%dKb)\n    %s\n\n", (temploop+1), PointCorreto, (RetornaTamanhoArq(DadosConfig.Req[temploop].POP) >> 10), DadosConfig.Req[temploop].STR);
				fputs(minhafrase, ArqList);
			}
			temploop++;
		}

		fclose (ArqList);
	}
}


/* log p/ operações genéricas do programa	*/
/* deve cuidar de fornecer a hora e etc	*/
/* se cabeca <> 0, imprime uma marca de 'header' na fte da string	*/
void Loga(char * frase, long cabeca)
{
	char	eeps[120];	/* utilizado para retorno de string data-hora	*/
	PreencheDataHora (eeps, 1);

	if (ArqLogGeral)
	{
		if (cabeca)
			fprintf(ArqLogGeral, "\n%s %s\n", eeps, frase);
		else
			fprintf(ArqLogGeral, "%s %s\n", eeps, frase);
	}
}

/* log p/o email file request	*/
/* se cabeca <> 0, imprime uma marca de 'header' na fte da string	*/
void LogEFR(char * frase, long cabeca)
{
	char	eeps[120];	/* utilizado para retorno de string data-hora	*/
	PreencheDataHora (eeps, 1);

	if (ArqLogEFR)
	{
		if (cabeca)
			fprintf(ArqLogEFR, "\n%s %s\n", eeps, frase);
		else
			fprintf(ArqLogEFR, "%s %s\n", eeps, frase);
	}
}

/* log p/o robot reply	*/
/* se cabeca <> 0, imprime uma marca de 'header' na fte da string	*/
void LogRR(char * frase, long cabeca)
{
	char	eeps[120];	/* utilizado para retorno de string data-hora	*/
	PreencheDataHora (eeps, 1);

	if (ArqLogRR)
	{
		if (cabeca)
			fprintf(ArqLogRR, "\n%s %s\n", eeps, frase);
		else
			fprintf(ArqLogRR, "%s %s\n", eeps, frase);
	}
}

void ApagaMsgYAM(int numeroMe)
{
	char tempstr[256];
	char tcomando[256];

	sprintf(tcomando, "setmail %d;maildelete FORCE", numeroMe);
	EnviaComandoYAM (tcomando, tempstr, 250);
}

void MinimizaYAM(void)
{
	EnviaComandoYAM("hide", 0, 0);
}
