forward
global type n2_smtp from smtpclient
end type
end forward

global type n2_smtp from smtpclient
boolean ignoreservercertificate = true
end type
global n2_smtp n2_smtp

type variables

//    Datos  Remitente 
String     is_email                       // Email del usuario (remitente)
string      is_servidor                   // Servidor de correo electrónico
integer    ii_puerto                      // Puerto al que se conecta el servidor
long       il_firma_html                // codigo en t_obj_datos de imagen firma cuando es html
string      is_firma                       // firma formato de  texto
boolean   ib_es_html                   // determina si el mail se envia en formato texto o formato HTML
string      is_es_html                   // campo string de table usuarios (S/N)
string      is_clave_crypt             // donde se guarda clave encriptada que se va a utilizar en servidor de correos
string      is_clave                      // donde se guarda clave
string      is_usuario                   // Nombre de usuario para el servidor de correos (generalmente es el correo)  
string      is_nombre                  // Nombre a mostrar correspondiente al correo del remitente

//     seguridad  y otros
boolean ib_enableTLS              // Habilitado TLS (el objeto por defecto es true)
string    is_proxy_server            // Ip de proxy para SMTP
long      ii_proxy_puerto            // Puerto para proxy 
long      il_proxy_tipo                // tipo de proxy
string    is_proxy_user              // nombre usuario para proy
string    is_proxy_pass              // password de proxy

string    is_encoding                 // Encoding de caracteres del correo, generalmente es    Unicode (UTF-8)
string    is_token                      // Token de acceso oauth2
integer  ii_priority =0                   // prioridad de envio 0- ninguna 1-baja 2-alta 
integer  ii_timeout                   // tiempo en segundos de espera por correo antes de devolver error
integer  ii_mime_reset      // tipo de reset 0 -- (Default all) 1- Recipients 2-  Ccs 3 -Bccs 4 - Attachments 5- LinkedResources 6 -Sender ( >10 no aplica, f_pre_send_settings)
boolean ib_cert_ignore             // ignora ciertos valores al enviar certificados 
boolean ib_cert_check           // realiza check de  certificados  si fueron revocados al realizar request (default en falso)

string   is_subject                     // Asunto  
string   is_textbody                   // Cuerpo de correo
string   is_recipient                   // Destinatario/s  (uno o o mas ) mas de un mail separado por ";" esquema -> email1 : nombre1; email2:nombre2;...
string   is_recipientCC				// Destinatario  con copia (uno o o mas ) mas de un mail separado por ";" esquema -> email1 : nombre1; email2:nombre2;...
string   is_recipientCO			 // Destinatario con copia oculta  (uno o o mas ) mas de un mail separado por ";" esquema -> email1 : nombre1; email2:nombre2;...

string   is_name_rec                // Nombre a mostrar correspondiente al correo de receptor
string   is_name_recCC		    // Nombre a mostrar correspondiente al correo de receptor CC (carbon copy)
string   is_name_recCO	          // Nombre a mostrar correspondiente al correo de receptor CO (Blind Carbon copy o Copia Oculta)

string   is_email_rec                // Correo correspondiente al correo de receptor
string   is_email_recCC		    // Correo a mostrar correspondiente al  receptor CC (carbon copy)
string   is_email_recCO	          //Correo correspondiente al receptor CO (Blind Carbon copy o Copia Oculta)

string   is_logfile                      // ruta y archivo de log 
string   is_attachment               // Adjuntos  (uno o o mas ) mas de un mail separado por ";"
integer ii_result                        // Resultado del envio del correo
long     il_handle_async             // Resultado del envio del correo asíncrono
long     il_async_ok[]                  // lista con los handles devuletos OK
long     il_async_Notok[]            // lista con los handles devuletos con error
string   is_async_Notok_msg[]            // lista con los mensajes de error devuletos 
string   is_asyncNook               // lista con los mensajes de error devuletos 
string   is_asyncok               // lista con los mensajes de error devuletos 
string   is_handle_async               // variable intermedia para manejo de envíos asíncronos
string   is_msgError                   // Mensaje de error
string   is_filelinkr                        // archivo adjunto de recurso path+nombre
string   is_filelinkr_tag	          	// archivo adjunto de recurso etiqueta 
string  is_logfile_Email 			  //archivo de log 
boolean ib_data_conect              // boleano para evitar repetir carga datos en bucles (falso se carga una vez) [f_pre_rend_settings]
boolean ib_data_body          // se usa en bucles, determina si debe cargar nuevamente body (falso se carga una vez) [f_pre_rend_settings]

string is_body                         //cuerpo del mensaje (html o texto plano)

// Creacion SmtpClient
SMTPClient n2_smtpClient
	

end variables

forward prototypes
public subroutine _readmefirst ()
public subroutine f_set_sgap_sender ()
public subroutine f_set_logfile (string archivo)
public subroutine f_set_destinatario ()
public subroutine f_inicial ()
public subroutine f_set_eshtml (boolean eshtml)
public subroutine f_set_enable_tls (boolean enabletls)
public function string f_get_error_message (integer errornumber)
public function integer f_async_cancel (long handle)
public subroutine f_async_estado_de (long handle)
public function integer f_get_array_string (string ps_cadena, ref string array_string[], string separador)
public subroutine f_agregar_firma ()
public function jsongenerator f_async_onfinish (long handle)
public subroutine enviar_email ()
public subroutine f_set_mime_asunto (string asunto)
public subroutine f_set_mime_encoding (string encoding)
public subroutine f_set_cfg_token (string token)
public function integer f_set_cfg_logfile (string archivonombre)
public subroutine f_certificado_ignore (boolean value)
public subroutine f_set_cfg_password (string password)
public function int f_send ()
public function integer f_test_mail ()
public function boolean f_pre_send_settings (ref string ls_mensaje)
public function boolean f_validar_email (string as_email, string as_errormsg)
public subroutine f_set_cfg_proxy (string servidor, long puerto)
public subroutine f_set_mime_dest (string email, string nombre)
public subroutine f_set_cfg_timeout (integer timeout)
public subroutine f_set_mime_remitente (string email, string nombre)
public subroutine f_set_mime_remitente (string email)
public subroutine f_set_mime_dest_cc (string email_cc)
public subroutine f_set_mime_dest_cc (string email_cc, string nombre_cc)
public subroutine f_set_mime_dest_co (string email_co)
public subroutine f_set_mime_dest_co (string email_co, string nombre_co)
public subroutine f_set_mime_html_adj_link (long cod_obj_datos, string etiqueta)
public subroutine f_set_mime_body (string bodytext)
public subroutine f_set_mime_adjuntos (string adjunto)
public subroutine f_set_mime_dest (string email)
public function boolean f_recuperar_archivo (long cod_ent_datos, ref string nom_recuperado)
public subroutine f_set_mime_reset_var (integer tipo_reset)
public subroutine f_certificado_check (boolean check_cert_revocado)
public subroutine f_set_mime_priority (integer prioridad)
public subroutine f_set_conect (string servidor, string usuario, long puerto, string email)
public function boolean f_get_sender_loaded ()
public function long f_send_async ()
public subroutine f_async_lis_clear ()
public subroutine f_async_lis_push (long valor)
public subroutine f_objeto_cerrar ()
public subroutine f_objeto_abrir ()
public subroutine f_set_loaded (boolean isloaded)
public subroutine log (string msj, string newfilepath)
public function string log_getfile ()
public subroutine log (string msj)
public function boolean f_task_validaciones (ref string ps_mensaje)
public subroutine f_task_load_dest ()
public function boolean f_task_load_destinatarios (ref string ps_mensaje[])
public subroutine f_set_data_body (boolean loadagain)
public subroutine f_set_data_conect (boolean loadagain)
public subroutine f_set_mime_adjunto_limpiar ()
public function boolean f_get_html ()
public function integer f_set_mime_reset (integer type_reset)
public function boolean f_async_lis_quitar_derecha (ref string ps_cadena, long valor)
public function string f_async_get_handle ()
public function string f_get_logfile ()
public function string f_get_async_result ()
public subroutine f_set_default (integer value)
end prototypes

public subroutine _readmefirst ();/*  INC11488 DJimenez 22/02/2024

El  objeto SMTPClient empaqueta un mensaje para ser enviado por internet a servidores de correo que entregaran el mail
 SMTPClient incluye al objeto MimeMessage - 
			SmtpCliente tiene que ver con  permisos en la cabecera del paquete (cabecera del paquete a ser manipulado por servidores )
			 https://docs.appeon.com/pb2022r2/objects_and_controls/SMTPClient_object.html
			MIMEMessage tiene que ver con el mensaje en sí (contenido del paquete)
			 https://docs.appeon.com/pb2022r3/objects_and_controls/MimeMessage_object.html
			
ver : https://docs.appeon.com/pb/whats_new/Native_email_support_SMTP_Client.html			
			
El mail se puede enviar sincrono o asíncrono (No bloquea el hilo de ejecución durante la transmisión)
Si se envía asíncrono, retorna el nro de envío  y se quiere realizar seguimiento de los enviados 
IMPORTANTE: NO se debe hacer destroy del objeto ya que se pierde todo rastro
el rastro se realiza con funciones  f_async_onFinish(), también se puede cancelar con f_async_cancel() 
----------
formas de autenticar 
con usuario y password en objeto smtpclient (username y password)
		(con google funciona de esta manera, en password se puede poner la clave en generada en google para aplicaciones externas)
enviando un token request al servidor (oauth2) 
		(usar objeto tokenrequest ver:  https://docs.appeon.com/pb2022r3/objects_and_controls/ch03s377s01.html	)
--------------
Modo de uso: 

se deben completar las variables y llamar a funcion f_pre_send_settings(), para usaurios sgap se carga remitente con f_set_sgap_sender()

1. se llenan las variables que se necesitan
     (obs: f_set_sgap_sender()  -> toma datos de usuario como remitente)
	  set_mime_body, set_mime_asunto, etc
2. se llama a la funcion f_pre_send_settings() (preset de varables proxy, log, token, nombre, encoding si tienen valor)
3. hacer un set de asunto, mensaje, adjunto, destinatario 
4. se llama la función  f_send() o f_send_async()
5. si es async se puede manejar con (f_async_XXX)
6.llamar a  f_cerrar() que hace el destroy del objeto

--------------
para envios masivo se crea is_varios destinatarios, que contiene email separados en un string 

se puede resetear valores asignados en f_set_mime_xx con f_set_mime_reset(reset_ok , type)

i reset_ok es FALSE -> no se aplcia reset y se ignora tipo
			  TRUE -> se aplica reset tipo 
type_reset			
0 -- (Default) Reset all the following types
1 -- Reset Recipients
2 -- Reset Ccs    
3 -- Reset Bccs
4 -- Reset Attachments
5 -- Reset LinkedResources
6 -- Reset Sender	
---------
se concatenan string y separarlos según algún string, para destinatarios y/o adjuntos

cuando se usan bucles Se puede reseter parte (o todo) el contenido de mime 

tanto el destinatario como adjuntos se pueden llamar mas de una vez, los acumula en un string separandolo con un separador 



 
*/
end subroutine

public subroutine f_set_sgap_sender ();
if NOT f_get_sender_loaded( ) then
	
	// Si remitente es usuario Sgap
	select  e_mail,SMTP_host, puerto_SMTP,email_firma,email_es_html,	email_clave_crypt,	email_usuario, nombre, cod_firma_html &
	  into :is_email, :is_servidor, :ii_puerto,:is_firma,:is_es_html,:is_clave_crypt,:is_usuario,:is_nombre,: il_firma_html &
			from t_pbcat_as_usuarios &
		where cod= :guo_admin_perfiles.ii_usuario;
	
	// set de booleano ib_es_html
	ib_es_html = trim(upper(is_es_html)) = "S"
	
	//set  clave
	if not isnull(is_clave_crypt) then & 
		is_clave = uo_fg.f_desencriptar(is_clave_crypt,2)
	
	//Set de  is_fileLinkR (archivo) is_fileLinkR_tag (etiqueta) para anexar como firma en body
	if (not isnull(il_firma_html) and il_firma_html <>0 ) then
		if NOT f_recuperar_archivo( il_firma_html, is_fileLinkR) then
			uo_fg.minimensaje( "no se pudo recuperara archivo de firma")
		end if 
		 is_filelinkr_tag = "firma" 
	end if 
end if 


end subroutine

public subroutine f_set_logfile (string archivo);is_logfile = archivo
end subroutine

public subroutine f_set_destinatario ();
end subroutine

public subroutine f_inicial ();
end subroutine

public subroutine f_set_eshtml (boolean eshtml);ib_es_html = eshtml
end subroutine

public subroutine f_set_enable_tls (boolean enabletls);// segun help solo lo quita al usar puerto 25
ib_enabletls= enabletls
end subroutine

public function string f_get_error_message (integer errornumber);choose case errornumber
	CASE  1 
		RETURN "Enviado satisfactoriamente"	
	CASE -1 
		RETURN "Se ha producido un error general."
	CASE -2 
		RETURN "No se puede conectar al servicio a través de proxy."
	CASE -3 
		RETURN "No se pudo resolver el servidor proxy dado."
	CASE -4 
		RETURN "No se pudo resolver el servidor remoto dado."
	CASE -5 
		RETURN "No se pudo conectar al servidor."
	CASE -6 
		RETURN "El servidor tiene un formato malo/ilegal o falta."
	CASE -7 
		RETURN "El protocolo no es compatible."
	CASE -8 
		RETURN "Eror en conexión SSL."
	CASE -9 
		RETURN "Se revoco el certificado del servidor."
	CASE -10 
		RETURN "Error en la autenticación del certificado de servicio."
	CASE -11 
		RETURN "Tiempo de espera de la operación (timeout)."
	CASE -12 
		RETURN "El servidor remoto denegó inicio de sesión."
	CASE -13 
		RETURN "Error al enviar datos de red."
	CASE -14 
		RETURN "Falla en la recepción de datos de red."
	CASE -15 
		RETURN "Nombre de usuario o contraseña incorrectos."
	CASE -16 
		RETURN "Error al leer el archivo local."
	CASE -17 
		RETURN "No se ha especificado ningún remitente."
	CASE -18 
		RETURN "No se han especificado destinatarios."
	CASE -18 
		RETURN "No se pudo convertir el parámetro con su codificación actual. El parámetro no es válido."
	CASE -18 
		RETURN "No se pudo convertir el correo electrónico con su codificación actual debido a que no hay suficiente memoria."
	CASE -18 
		RETURN "No se pudo enviar el correo electrónico porque su codificación no es compatible."	
	CASE -18 
		RETURN "No se pudo convertir el correo electrónico con su codificación actual. Se ha producido un error general."	
	case else
		return "Error no identificado nro:"+string(errornumber)
end choose
	
end function

public function integer f_async_cancel (long handle);/* cancela email enviado asincrónicamente, 
parametro:
			handle (long)  si es cero cancela todos,
								sino el especificado por el handle
retorno      1 ok
		      -1 error  				*/
				
return n2_smtpclient.sendasynccancel( handle)
end function

public subroutine f_async_estado_de (long handle);
end subroutine

public function integer f_get_array_string (string ps_cadena, ref string array_string[], string separador);//retorna por referencia una array de string de ps_cadena
//la funcion retorna nro de elementos del array

return uo_fg.string_to_arraystring( ps_cadena, array_string, separador )
end function

public subroutine f_agregar_firma ();
end subroutine

public function jsongenerator f_async_onfinish (long handle);JsonGenerator uo_JsonGenerator
uo_JsonGenerator = Create JsonGenerator
double err_number
string err_text

n2_smtpclient.event onsendfinished( handle, err_number, err_text)

uo_jsongenerator.additemnumber('/',"handle",handle)
uo_jsongenerator.additemnumber('/',"err_number",err_number)
uo_jsongenerator.additemstring('/',"err_text",err_text)

return uo_jsongenerator

end function

public subroutine enviar_email ();
end subroutine

public subroutine f_set_mime_asunto (string asunto);is_subject = asunto
end subroutine

public subroutine f_set_mime_encoding (string encoding);is_encoding = encoding
end subroutine

public subroutine f_set_cfg_token (string token);is_token = token
end subroutine

public function integer f_set_cfg_logfile (string archivonombre);return n2_smtpclient.logfile( archivonombre)
end function

public subroutine f_certificado_ignore (boolean value);/* ignora o no ciertos tipos de errores al enviar el request */
ib_cert_ignore = value
end subroutine

public subroutine f_set_cfg_password (string password);is_clave = password
end subroutine

public function int f_send ();return n2_smtpclient.send( )

end function

public function integer f_test_mail ();/*
debe tener prconfigurado: is_servidor, is_puerto, is_usuario, ii_puerto, is_clave , is_email
envia un mail de prueba
*/
string ls_txtmsg
integer li_resp

// Cargo las variables al objeto
if NOT f_pre_send_settings( ls_txtmsg ) then
	uo_fg.minimensaje( ls_txtmsg)
	return -1
end if 

//pre_send OK, envio
li_resp = this.f_send( )
if li_resp <> 1 then 
	uo_fg.minimensaje(this.f_get_error_message( li_resp) )
	return -1
end if 

//Envio Ok
 return 1
 
end function

public function boolean f_pre_send_settings (ref string ls_mensaje);// Esta función vuelca el contenido de las variables cargadas (con f_set) al objeto 

integer li_cant, i
string ls_adjuntos[],ls_err[]

// Validaciones de  datos de conexión

if not f_task_validaciones(ls_mensaje) then 	return false

/****** Destinatario/s carga siempre (sea bucle o un envío) **********/

// destinatarios
if not f_task_load_destinatarios( ls_err) then
	for i = 1 to upperbound(ls_err)
		ls_mensaje +="Error en email"+ ls_err[i]
	next
	return false	
end if 

/**********************************************
            ------          Valores del objeto  ------                      
  que se cargan si tienen contenido, usar para blaquear f_set_mime_adjunto_limpiar
*************************************************/  

// Adjuntos
li_cant = uo_fg.string_to_arraystring( is_attachment, ls_adjuntos, ";")
if li_cant >0 then
	for i = 1 to li_cant 
		if  n2_smtpclient.message.addattachment( ls_adjuntos[i]) < 0 then 
			ls_mensaje = "error al adjuntar archivo:" + ls_adjuntos[i]
			return false
		end if 
	next
end if 

/*************************************************/
/*            ------          Valores del objeto  ------                             */
/*                    Que se cargan una vez en bucles,                          */
/*          solo si luego del send ->  f_set_data_conect(false)            */
/*************************************************/

if ib_data_conect then 
	// conexion
	n2_smtpclient.host           =  is_servidor 
	n2_smtpclient.port           = ii_puerto
	n2_smtpclient.username   = is_usuario
	n2_smtpclient.password   = is_clave   
	
	/*encoding*/
	if len(is_encoding)>0 then n2_smtpclient.message.encoding=is_encoding
	
	/* timeout*/
	if (ii_timeout >0) then n2_smtpclient.timeout = ii_timeout
	
	/* setea remitente */
	if len(is_nombre)=0 then 
		if n2_smtpclient.message.setsender( is_email ) < 1  then
			ls_mensaje = "Error al configurar emisor "
			return false
		end if 
	else
		if 	n2_smtpclient.message.setsender( is_email,is_nombre )<>1 then
			ls_mensaje = "Error al configurar emisor y nombre"
			return false
		end if 
	end if 	

	/* ES HTML*/	 
	//set de nombre con imagen en firma para anexarlo despues al final del body
	if len( is_filelinkr_tag)>0 and len( is_filelinkr) >0 then n2_smtpclient.message.addlinkedresource( is_filelinkr, is_filelinkr_tag)
	
end if 


/**********************************************
            ------          Valores del objeto  ------                      
SE CARGAN UNA VEZ SI  f_set_data_body(false) DESPUES DEL SEND EN BUCLE 
si queda en true (valor por defecto) se re carga si tiene contenido
 --------------------------------------------------------------------
-> para body f_set_mime_body y f_set_mime_asunto
/// para volver a setear las variables o blanquearlas en objeto usar:
		 f_set_mime_reset (reset de objeto) y 
 		 f_set_mime_reset_var (reset de variables de objetos)

0 -- (Default) Reset all the following types
1 -- Reset Recipients (destinatario)   
2 -- Reset Ccs
3 -- Reset Bccs
4 -- Reset Attachments (adjunto)
5 -- Reset LinkedResources (firma) -no necesario si se activa ib_data_conect-
6 -- Reset Sender	(remitente)	  -no necesario si se activa ib_data_conect-

**********************************************/
IF ib_data_body then

	/*Asunto*/
	if len(is_subject) > 0 then n2_smtpclient.message.subject = is_subject
	
	
	/*body */
	if len(is_body) >0 then
		if (ib_es_html) then
			// agrego al final del body el link si se cargo datos en variables
			if len( is_filelinkr_tag)>0 and len( is_filelinkr) >0 then is_body +=crlf+crlf+crlf+"<img src='cid:" + is_filelinkr_tag + "'/>" 
			is_body ="<html><body>"+is_body+"</body></html>"
			n2_smtpclient.message.htmlbody = is_body
		else
			/*Es texto plano*/
			// tenemos cargado is_body, le agregamos la firma texto
			if len(is_firma)>0 then is_body += crlf+crlf+is_firma
			// set body texto
			 n2_smtpclient.message.textbody = is_body
		end if 
	end if 

end if 

// Ok
return true

end function

public function boolean f_validar_email (string as_email, string as_errormsg);// -----------------------------------------------------------------------------
// SCRIPT:     ValidEmail
//
// PURPOSE:    This function determines if the email address is valid syntax.
//
// ARGUMENTS:  as_email		- Email address to analyze
//					as_errormsg	- Error message describing the problem
//
// RETURN:     True = Valid syntax, False = Invalid Syntax
//
// DATE        PROG/ID		DESCRIPTION OF CHANGE / REASON
// ----------  --------		-----------------------------------------------------
// 08/12/2017  RolandS		Initial creation
// -----------------------------------------------------------------------------
// DJimenez inc9824 paso al Español-Castellano Msjs de retorno

String ls_localpart, ls_domain, ls_domainpart[]
Integer li_pos, li_idx, li_max, li_asc

If Len(as_email) < 2 Then
	as_errormsg = "Complete dirección de Email destinatario" 
	Return False
End If

If isnull(as_email) Then
	as_errormsg = "La dirección de email está vacia"
	Return False
End If

If Len(as_email) > 254 Then
	as_errormsg = "Dirección de Email no debe tener mas de 254 caracteres!" // "Email address cannot be more than 254 characters!"
	Return False
End If

li_pos = Pos(as_email, "@")
If li_pos < 2 Then
	as_errormsg = "Dirección de Email debe contener un caracter @" //Email address must have an @ character!
	Return False
End If

If LastPos(as_email, "@") > Pos(as_email, "@") Then
	as_errormsg = "Dirección de Email no debe tener más de un caracter @" //Email address cannot have more than one @ character!
	Return False
End If

li_pos = Pos(as_email, " ")
If li_pos > 0 Then
	as_errormsg = "Dirección de Email no debe tener espacios en blanco" //Email address cannot have any spaces
	Return False
End If

// split local & domain
li_pos = Pos(as_email, "@")
ls_localpart = Left(as_email, li_pos - 1)
ls_domain    = Mid(as_email, li_pos + 1)

If Len(ls_localpart) > 64 Then
	as_errormsg =" Segmento  buzón de correo  (en email)  no puede tener más de 64 caracteres"// "The mailbox part of the email address cannot be more than 64 characters!"
	Return False
End If

If Len(ls_domain) > 253 Then
	as_errormsg = "Segmento dominio de correo  (en email)  no puede tener mas de 253 caractres"//"The domain part of the email address cannot be more than 253 characters!"
	Return False
End If

If Left(ls_localpart, 1) = "." Then
	as_errormsg = "Segmento de casilla de correo (en email)  no debe empezar con punto" //The mailbox part of the email address cannot start with a period!
	Return False
End If

If Right(ls_localpart, 1) = "." Then
	as_errormsg = "Segmento de casilla de correo  (en email) no debe finalizar con punto"   //The mailbox part of the email address cannot end with a period!"
	Return False
End If

If Pos(ls_localpart, "..") > 0 Then
	as_errormsg = "Segmento de casilla de correo  (en email) no debe tener mas de un punto"   //"The mailbox part of the email address cannot have more than one period in a row!"
	Return False
End If

// check local for allowed characters
li_max = Len(ls_localpart)
For li_idx = 1 To li_max
	li_asc = Asc(Mid(ls_localpart, li_idx, 1))
	choose case li_asc
		case 65 to 90
			// Lower case a-z
		case 97 to 122
			// Upper case A-Z
		case 48 to 57
			// Digits 0-9
		case 33, 35 to 39, 42, 43, 45, 47, 61, 63, 94 to 96, 123 to 126
			// Characters !#$%&'*+-/=?^_`{|}~
		case 46
			// Period
		case else
			as_errormsg = "Segmento de casilla de correo  (en email) no debe contener caracteres inválidos" //"The mailbox part of the email address contains invalid characters!"
			Return False
	end choose
Next

If Left(ls_domain, 1) = "." Then
	as_errormsg = "Segmento de dominio (en email) no debe empezar con punto" //"The domain part of the email address cannot start with a period!"
	Return False
End If

If Right(ls_domain, 1) = "." Then
	as_errormsg = "Segmento de dominio (en email) no debe terminar con punto!" //"The domain part of the email address cannot end with a period!"
	Return False
End If

li_pos = Pos(ls_domain, ".")
If li_pos = 0 Then
	as_errormsg = "Segmento de dominio (en email) debe temer al menos un punto!"  //"The domain part of the email address must have at least one period!"
	Return False
End If

// check domain for allowed characters
li_max = Len(ls_domain)
For li_idx = 1 To li_max
	li_asc = Asc(Mid(ls_domain, li_idx, 1))
	choose case li_asc
		case 65 to 90
			// Lower case a-z
		case 97 to 122
			// Upper case A-Z
		case 48 to 57
			// Digits 0-9
		case 45
			// Hyphen
		case 46
			// Period
		case else
			as_errormsg = "Segmento de dominio  (en email) no debe contener caracteres inválidos!"  //"The domain part of the email address contains invalid characters!"
			Return False
	end choose
Next

// break domain into parts
li_max= uo_fg.string_to_arraystring( ls_domain, ls_domainpart, ".")
//li_max = Parse(ls_domain, ".", ls_domainpart)

If li_max > 127 Then
	as_errormsg = "Segmento de domino (en email) contiene muchos puntos!" //"The domain part of the email address contains too many periods!"
	Return False
End If

For li_idx = 1 To li_max
	If Left(ls_domainpart[li_idx], 1) = "-" Then
		as_errormsg = "Segmento de domino (en email) no puede tener punto y guión consecutivo!"  //"The domain part of the email address cannot have a hyphen and a period next to one another!"
		Return False
	End If
	If Right(ls_domainpart[li_idx], 1) = "-" Then
		as_errormsg = "Segmento de domino (en email) no puede tener punto y guión consecutivo!"  //The domain part of the email address cannot have a hyphen and a period next to one another!"
		Return False
	End If
Next

Return True

end function

public subroutine f_set_cfg_proxy (string servidor, long puerto);is_proxy_server =  servidor
ii_proxy_puerto =  puerto
end subroutine

public subroutine f_set_mime_dest (string email, string nombre);is_email_rec = email
is_name_rec = nombre
uo_fg.addtostring(is_recipient , is_email_rec + ":"+is_name_rec , ";")

end subroutine

public subroutine f_set_cfg_timeout (integer timeout);ii_timeout = timeout
end subroutine

public subroutine f_set_mime_remitente (string email, string nombre);is_email    = email
is_nombre = nombre

end subroutine

public subroutine f_set_mime_remitente (string email);is_email = email

end subroutine

public subroutine f_set_mime_dest_cc (string email_cc);is_email_recCC = email_cc
is_name_recCC = ""  //nombre
uo_fg.addtostring(is_recipient , is_email_recCC + ":"+is_name_recCC , ";")


end subroutine

public subroutine f_set_mime_dest_cc (string email_cc, string nombre_cc);is_email_recCC = email_cc
is_name_recCC = nombre_CC
uo_fg.addtostring(is_recipient , is_email_recCC + ":"+is_name_recCC , ";")
end subroutine

public subroutine f_set_mime_dest_co (string email_co);// bcc = Blind Carbon Copy
is_email_recCO = email_co
is_name_recCO = "" //nombre_co
uo_fg.addtostring(is_recipient , is_email_recCO + ":"+is_name_recCO , ";")
end subroutine

public subroutine f_set_mime_dest_co (string email_co, string nombre_co);// bcc = Blind Carbon Copy
is_email_recCO = email_co
is_name_recCO = nombre_co
uo_fg.addtostring(is_recipient , is_email_recCO + ":"+is_name_recCO , ";")
end subroutine

public subroutine f_set_mime_html_adj_link (long cod_obj_datos, string etiqueta);/*  Este adjunto no va en la lista de adjunto, sino que se necesita para conformar el html con imagen (usualmente firma)
	luego en el html se hace referencia al mismo por medio de la ETIQUETA asignada con  CDI:
	EJ: 
		en powerscript 
		  f_set_mime_html_adj_lnk("c_/firma.jpg","firma")
		en html 
		  is_html += "<img src='cid:" +firma + "'/>"
	*/
	 il_firma_html = cod_obj_datos
	is_filelinkr_tag = etiqueta

end subroutine

public subroutine f_set_mime_body (string bodytext);is_body = bodytext

end subroutine

public subroutine f_set_mime_adjuntos (string adjunto);/* carga en  is_attachment, el/los nombre de los adjuntos y separa por ";" si hay mas de uno	al ejecutar f_pre_send_settings los carga al objeto */
uo_fg.addtostring(is_attachment,adjunto,";")


end subroutine

public subroutine f_set_mime_dest (string email);is_email_rec = email
is_name_rec = ""
uo_fg.addtostring(is_recipient,is_email_rec+":"+is_name_rec,";")



end subroutine

public function boolean f_recuperar_archivo (long cod_ent_datos, ref string nom_recuperado);nom_recuperado = uo_fg.f_mail_create_file( cod_ent_datos, nom_recuperado) 
if nom_recuperado = "" then return false
return true

end function

public subroutine f_set_mime_reset_var (integer tipo_reset);/*  reseteo de variables involucradas con el objeto mime
type_reset			
0 -- (Default) Reset all the following types
1 -- Reset Recipients (destinatario)
2 -- Reset Ccs
3 -- Reset Bccs
4 -- Reset Attachments (adjunto)
5 -- Reset LinkedResources (firma)
6 -- Reset Sender	(remitente)		
			*/
choose case tipo_reset
	case 0  //restet type 1 to 4
		is_recipient=""  //destinatarios
		is_recipientcc=""
		is_recipientco=""
		is_attachment="" //adjuntos
		//is_filelinkr  = ""    //firma
		//is_filelinkr_tag  = ""
	case 1
		 is_recipient =""
	case 2
		is_recipientcc=""
	case 3
		is_recipientco=""
	case 4
		is_attachment="" 
	case 5
		is_filelinkr  = ""
		is_filelinkr_tag  = ""
	case 6
		is_email=""
		is_nombre=""
	case 9
		 ib_data_conect= true
		 ib_data_body= true
	case 10

		is_asyncok =""
		is_asyncnook=""
		is_handle_async=""

		is_subject=""
		is_textbody=""
end choose
	


end subroutine

public subroutine f_certificado_check (boolean check_cert_revocado);ib_cert_check = check_cert_revocado
end subroutine

public subroutine f_set_mime_priority (integer prioridad);ii_priority= prioridad
end subroutine

public subroutine f_set_conect (string servidor, string usuario, long puerto, string email);
is_usuario = usuario
is_email    = email
 is_servidor = servidor
 ii_puerto = puerto
end subroutine

public function boolean f_get_sender_loaded ();boolean resp = true

// condiciones que hacen ejecutar sql de carga de remitente
if len(is_clave) = 0 then resp = false
if len(is_servidor) = 0 then resp = false
if len(is_usuario) = 0 then resp = false

return resp
end function

public function long f_send_async ();return n2_smtpclient.sendasync( )



end function

public subroutine f_async_lis_clear ();is_handle_async = ""
end subroutine

public subroutine f_async_lis_push (long valor);uo_fg.addtostring(is_handle_async, trim(string(valor)), ";")
end subroutine

public subroutine f_objeto_cerrar ();Destroy n2_smtpclient

end subroutine

public subroutine f_objeto_abrir ();// Creacion SmtpClient
//SMTPClient n2_smtpClient
n2_smtpClient =  create SMTPClient
end subroutine

public subroutine f_set_loaded (boolean isloaded);ib_data_conect = isloaded
end subroutine

public subroutine log (string msj, string newfilepath);//set de nuevo archivo de log
is_logfile_Email = newfilepath
//log
log(msj)

end subroutine

public function string log_getfile ();return is_logfile_Email
end function

public subroutine log (string msj);Long li_FileNum

li_FileNum = FileOpen(is_logfile_Email, LineMode!, Write!, Shared!, Append!,EncodingUTF8!)
if isnull(li_FileNum) then uo_fg.minimensaje( "error en log file")
if li_FileNum <> 1 then uo_fg.minimensaje( "log error: "+string(li_FileNum))
FileWrite(li_FileNum, msj)
FileClose(li_FileNum)
end subroutine

public function boolean f_task_validaciones (ref string ps_mensaje);// validacion datos de conexión

if is_usuario="" then 
		ps_mensaje = "Campo Usuario debe contener un valor"
		return false
end if 		
if is_clave="" then 
		ps_mensaje = "Campo Passw0rd debe contener un valor"
		return false
end if 		
if  ii_puerto=0 then 
		ps_mensaje = "Campo Puerto debe contener un valor"
		return false
end if 		
if is_servidor="" then 
	ps_mensaje = "Campo Servidor debe contener un valor"
	return false
end if 

return true
end function

public subroutine f_task_load_dest ();
end subroutine

public function boolean f_task_load_destinatarios (ref string ps_mensaje[]);long li_cant,i,indice = 0
string ls_dest[],ls_destcc[],ls_destco[],ls_err[],ls_mensaje,ls_aux
boolean lb_retorno = true

// carga en objeto desde variables 

//   Emails  - separado por ";" tiene esquema -> email ":" nombre  

li_cant = uo_fg.string_to_arraystring(is_recipient, ls_dest, ";")
if li_cant = 0 then
	ls_mensaje = "Debe haber al menos un destinatario de mensaje"
	return false
end if 
for i = 1 to li_cant 
	ls_aux = ls_dest[i]
	is_name_rec = uo_fg.f_string_pop(  ls_aux, ":") 
	is_email_rec  = uo_fg.f_string_pop(ls_aux, ":")
	
	// Set del Objeto 
	if len(is_name_rec)>0 then 
		if n2_smtpclient.message.addrecipient( is_email_rec, is_name_rec) < 0 then lb_retorno = false			
	else
		if n2_smtpclient.message.addrecipient( is_email_rec) < 0 then   lb_retorno = false
	end if 
	
	if not lb_retorno then 
		indice += 1
		ps_mensaje[indice]= "Error en email "+is_email_rec+" nombre "+is_name_rec
		lb_retorno = true
	end if 			
next



//Set destinatario CC

if len(is_recipientCC)>0 then
	li_cant = uo_fg.string_to_arraystring(is_recipientcc, ls_destCC, ";")
	for i = 1 to li_cant 
		ls_aux = ls_destCC[i]
		is_name_recCC = uo_fg.f_string_pop(  ls_aux, ":") 
		is_email_recCC = uo_fg.f_string_pop(ls_aux, ":")
		
		// Set del Objeto
		if len(is_name_recCC)>0 then 
			if n2_smtpclient.message.addCC( is_email_recCC, is_name_recCC) < 0 then   lb_retorno = false
		else
		    if n2_smtpclient.message.addCC( is_email_recCC) < 0 then   lb_retorno = false
		end if 
	next
	if not lb_retorno then 
		indice += 1
		ps_mensaje[indice]= "Error en email "+is_email_reccc+" nombre "+is_name_reccc
		lb_retorno = true
	end if 			
end if 


// Set destinatario (CO ) si se agregó
//------------------------------------------------------------

// Si hay destinatario CO, validar y setear
if len(is_recipientCO)>0 then
	li_cant = uo_fg.string_to_arraystring(is_recipientCO, ls_destCO, ";")
	for i = 1 to li_cant 
		ls_aux = ls_destCO[i]
		is_name_recCO = uo_fg.f_string_pop(  ls_aux, ":") 
		is_email_recCO = uo_fg.f_string_pop(ls_aux, ":")
		
	// Set del Objeto
		if len(is_name_recCO)>0 then 
			if n2_smtpclient.message.addBCC( is_email_recCO, is_name_recCO) < 0 then   lb_retorno = false
		else
			if n2_smtpclient.message. addBCC( is_email_recCO) < 0 then   lb_retorno = false
		end if
		if not lb_retorno then 
		indice += 1
		ps_mensaje[indice]= "Error en email "+is_email_reccc+" Nombre "+is_name_reccc 
		lb_retorno = true
	end if 
	next
end if 

// Si hubo algun error en los set devuelvo falso
if indice <> 0 then return false
return true	




end function

public subroutine f_set_data_body (boolean loadagain);// en bucles determina si se deben cargar al objeto datos del mensaje  body en cada ciclo, 
//se utiliza en f_pre_send_settings se setea luego del envio, default true (que cargue pase una vez)
ib_data_body = loadagain
end subroutine

public subroutine f_set_data_conect (boolean loadagain);// en bucles determina los objetos NO que no se deben cartgar nuevamente -
//se utiliza en f_pre_send_settings, se setea luego del envio , default true (que cargue pase una vez)
ib_data_conect =loadagain


end subroutine

public subroutine f_set_mime_adjunto_limpiar (); is_attachment  =""
end subroutine

public function boolean f_get_html ();return ib_es_html
end function

public function integer f_set_mime_reset (integer type_reset);/* type_reset			
0 -- (Default) Reset all the following types
1 -- Reset Recipients (destinatario)
2 -- Reset Ccs
3 -- Reset Bccs
4 -- Reset Attachments (adjunto)
5 -- Reset LinkedResources (firma)
6 -- Reset Sender	(remitente)		
			*/

ii_mime_reset = type_reset

return n2_smtpClient.message.reset(ii_mime_reset )
end function

public function boolean f_async_lis_quitar_derecha (ref string ps_cadena, long valor);return uo_fg.f_string_quitar_der( ps_cadena , string(valor), ";")

end function

public function string f_async_get_handle ();return is_handle_async
end function

public function string f_get_logfile ();return is_logfile_Email
end function

public function string f_get_async_result ();return "No Ok:"+is_asyncNook+"Ok: "+is_asyncok

end function

public subroutine f_set_default (integer value);choose case value
	case 0
		ib_enableTLS = true 
		ii_mime_reset  =20     // if > 10 dont change dont execute any change ( values from 0-6)
		ib_cert_check = false 
		is_logfile_Email 	= 'c:\sistemas\logs\email.txt'	
		is_asyncok =""
		is_asyncNook =""
		ib_data_conect= true 
		ib_data_body= true  
	case 1
		ib_data_conect= true
		ib_data_body= true
end choose
end subroutine

on n2_smtp.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n2_smtp.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on

event onsendfinished;choose case errornumber
	case is > 0 
	//Sended
	 is_asyncok += "handle:"+string(handle)+" Nro ERROR : "+ string(errornumber)
case is < 0
	 is_asyncnook+= "handle:"+string(handle)+" Nro ERROR : "+ string(errornumber)
case else
	is_asyncok += "sin respuesta "
end choose

//
//errortext Spanish
//ls_err_msg = f_get_error_message( errornumber)
//if pos(ls_err_msg,'no identificado') > 0 then ls_err_msg = errortext
//if errornumber = 1 then
//	//Sended
//	  il_async_ok[upperbound( il_async_ok)+1] = handle
//	else	
//		//errornumber
//		il_async_NotOk[upperbound( il_async_NotOk)+1] = errornumber
//		//errortext Spanish
//		ls_err_msg = f_get_error_message( errornumber)
//		if pos(ls_err_msg,'no identificado') > 0 then ls_err_msg = errortext
//		is_async_NotOk_msg[upperbound( is_async_NotOk_msg)+1] =ls_err_msg
//end if 
//



end event

