jueves, 28 de noviembre de 2019

Crear ID Dinamicos con POSTGRESQL

CREATE OR REPLACE FUNCTION GeneraID() RETURNS VARCHAR AS $$
DECLARE numFechaActual VARCHAR(100);
DECLARE strEnc CHAR(32);
DECLARE contador INT DEFAULT 0;
DECLARE genID VARCHAR DEFAULT '';
DECLARE contRest INT DEFAULT 1;
DECLARE incVar INT DEFAULT 1;
BEGIN
numFechaActual := REPLACE(CONCAT(TO_CHAR(NOW(), 'YYYYMMDDHHIISS'), EXTRACT(EPOCH FROM (SELECT NOW())) * 1000),'.','');
strEnc := MD5(numFechaActual);
genID := SUBSTRING(strEnc, 1, 8);
FOR contador IN 1.. LENGTH(strEnc) LOOP
IF (contRest = 8)
THEN
IF (contador IN (8,16,24))
THEN
IF (contador > 0)
THEN
incVar := contador + 1;
ELSE
incVar := contador;
END IF;
genID := CONCAT(genID, '-',SUBSTRING(strEnc, incVar, contRest));
END IF;
contRest := 1;
ELSE
contRest := contRest + 1;
END IF;
END LOOP;
return genID;
END;
$$
LANGUAGE plpgsql;

miércoles, 3 de enero de 2018

Obtener el DV de un RUN Chileno con Python.


def obtieneDV(rutSinDv):
    suma = 0
    incrementa = 2
    dv = ""
    for i in reversed(rutSinDv):
        suma +=  (int(i) * incrementa)
        incrementa = incrementa+1
        if (incrementa == 8):
            incrementa = 2
    division =  suma / 11
    resto = suma % 11
    dv = 11-resto
    if (dv == 11):
        dv = 0
    elif (dv == 10):
        dv = "K"
    return dv


Saludos.

miércoles, 13 de febrero de 2013

Funcion random en MySQL


En base a la necesidad de esta funcionalidad, 
he creado una funcion para suplir dicha falencia.
 
Espero que a alguien le sea de utilidad... 
 
Saludos. 
 
DROP FUNCTION IF EXISTS random;
DELIMITER //
CREATE FUNCTION random
(
   numero_inicial INT,
   numero_final INT
)
RETURNS INT
DETERMINISTIC
BEGIN
   DECLARE numero INT DEFAULT 0;
   DECLARE retorno INT;
   DROP TEMPORARY TABLE IF EXISTS randinit;
   CREATE TEMPORARY TABLE randinit (num INT NOT NULL);
   IF (numero_inicial > numero_final)
   THEN
      contador: LOOP
      IF (numero = numero_inicial)
      THEN
         LEAVE contador;
      ELSE
         SET numero = numero +1;
         INSERT INTO randinit(num) VALUES (numero);
      END IF;
      END LOOP contador;
   ELSEIF (numero_final > numero_inicial)
   THEN
      contador: LOOP
      IF (numero = numero_final)
      THEN
         LEAVE contador;
      ELSE
         SET numero = numero +1;
         INSERT INTO randinit(num) VALUES (numero);
      END IF;
      END LOOP contador;
   ELSE
      SET numero = numero_inicial;
      INSERT INTO randinit(num) VALUES (numero);
   END IF;
   SET retorno = (SELECT num FROM randinit ORDER BY RAND() LIMIT 1);
   RETURN retorno;
END//
DELIMITER ;

miércoles, 5 de septiembre de 2012

Obteniendo el Digito Verificador del Run Chileno con Python

Me dio por realizar esta función con el objeto de que a alguien le sirva.

Saludos!.
(Obtiene el DV del RUN chileno).

#!/usr/bin/env python
# -*- coding: utf8 -*-
"""
Script para obtener el digito verificador del RUN
e imprime todo el RUN
@author: felcontreras@gmail.com
"""
import os
import sys

def number_format(num):
    """
    Funcion la cual realiza el formateo del numero
    dejandolo asi separado por puntos.
    (USO SIMPLE)
    """
    numero = str(num)
    i = 0
    numfinal = ""
    numdex = ""
    for concat in reversed(numero):
        numfinal += concat
        if i == 2:
            numfinal += "."
            i = 0
        else:
            i += 1
    for numreal in reversed(numfinal):
        numdex += numreal
    if numdex[0] == ".":
        retorno = numdex[1:len(numdex)]
    else:
        retorno = numdex
    return retorno

def obtienedv(run):
    """
    Funcion la cual retorna el digito verificador
    a su vez el run ya formateado.
    Eso ya me voy a dormir.
    """
    permitido = "1234567890"
    total = 0
    multiplo = 2
    rutx = ""
    for cambio in run:
        if cambio in permitido:
            rutx += cambio
    for reverso in reversed(rutx):
        total += int(reverso) * multiplo
        if multiplo == 7:
            multiplo = 2
        else:
            multiplo += 1
        modulus = total % 11
        verificador = 11 - modulus
        if verificador == 10:
            div = "k"
        elif verificador == 11:
            div = "0"
        else:
            if verificador < 10:
                div = verificador
        retorno = rutx+str(div)
    return retorno

def abreArchivo(archivo):
    """
    Funcion la cual lee el archivo de origen para la opcion -i
    """
    abre = open(archivo, 'r')
    arreglo = []
    for linea in abre.readlines():
        arreglo.append(obtienedv(linea))
    abre.close()
    return "\n".join(arreglo)

def creaArchivo(archivo, info):
    """
    Funcion la cual crea el archivo de destino y almacena la información del archivo de entrada
    """
    try:
        cnuevo = open(archivo, 'w')
    except:
        print "Imposible escribir en archivo"
        sys.exit()
    cnuevo.write(info)
    cnuevo.close()
    return True

if '__main__' == __name__:
    if "--help" in sys.argv:
        print "Modo de uso:"
        print sys.argv[0]+ " 123456789 # (run)"
        print sys.argv[0]+ " -i archivo_entrada # Imprime en Pantalla | -o archivo_de_salida (opcional)"
        sys.exit()
    if len(sys.argv) > 2:
        if "-i" in sys.argv:
            try:
                archivo = sys.argv[sys.argv.index("-i")+1]
            except IndexError:
                print "Debes definir el archivo a leer"
                sys.exit()
            runs = abreArchivo(os.getcwd()+"/"+archivo)

            if "-o" in sys.argv:
                try:
                    anuevo = sys.argv[sys.argv.index("-o")+1]
                    creaArchivo(anuevo, runs)
                except:
                    print "Imposible crear el archivo de salida."
                    sys.exit()
            else:
                print runs
    elif len(sys.argv) == 2:
        print obtienedv(sys.argv[1])
    else:
        print sys.argv[0]+" --help. Para obtener mayor infromacion."

martes, 4 de septiembre de 2012

Validador de Run Chileno en Python

#!/usr/bin/env python
#-*- coding: utf8 -*-
"""
Script para la validación de RUN Chileno.
@author: felcontreras@gmail.com
"""
import sys

def filtra(rut):
    """
    Esta funcion cumple el trabajo de filtrar el RUN.
    Omitiendo asi los puntos (.) y Guiones (-) y cualquier otro caracter
    que no incluya la variable 'caracteres'.
    """
    caracteres = "1234567890k"
    rutx = ""
    for cambio in rut.lower():
        if cambio in caracteres:
            rutx += cambio
    return rutx

def valida(rut):
    """
    Esta funcion cumple el trabajo de realizar la logica de negocio,
    ya sea matematica como logica.
    """
    rfiltro = filtra(rut)
    rutx = str(rfiltro[0:len(rfiltro)-1])
    digito = str(rfiltro[-1])
    multiplo = 2
    total = 0
    for reverso in reversed(rutx):
        total += int(reverso) * multiplo
        if multiplo == 7:
            multiplo = 2
        else:
            multiplo += 1
        modulus = total % 11
        verificador = 11 - modulus
        if verificador == 10:
            div = "k"
        elif verificador == 11:
            div = "0"
        else:
            if verificador < 10:
                div = verificador
    if str(div) == str(digito):
        retorno = "Valido"
    else:
        retorno = "Invalido"
    return retorno

if __name__ == "__main__":
    if len(sys.argv) == 2:
        print valida(sys.argv[1])
    else:
        print "* Atención - Utilizando RUN: 11.111.111-1 en modo prueba.*"
        print "# Modo de empleo: 'python "+sys.argv[0]+" 22.222.222-2'. (RUN A VALIDAR) #"
        print valida("11.111.111-1")

Generador de Runs y DV Chilenos en Python

#!/usr/bin/env python
"""
Genera RUN V1.0
Este script genera RUN Chilenos validados
Utiles para registrarse en algun sitio que requiera dichos datos
y no colocar los propios.

uso: Generarut.py 10000000 10000050
Por defecto generara 500 runs entre: 10.000.000 y 10.000.500
Esto generara 50 Runs validos
"""
import sys

def generarut(desde, hasta):
    """
    Funcion que permite la generacion de runs.
    """
    arreglo = []
    multiplo = 2
    total = 0
    for i in range(desde, hasta):
        rut = str(i)
        for rinverso in reversed(rut):
            total += int(rinverso) * multiplo
            if multiplo == 7:
                multiplo = 2
            else:
                multiplo += 1
            modulus = total % 11
            verificador = 11 - modulus
            if verificador == 10:
                div = "k"
            elif verificador == 11:
                div = "0"
            else:
                    if verificador < 10:
                        div = verificador
        arreglo.append(rut + "-" + str(div))
    return arreglo

if "__main__" == __name__:
    if len(sys.argv) == 3:
        DESDE = int(sys.argv[1])
        HASTA = int(sys.argv[2])
    else:
        DESDE = 10000000
        HASTA = 10000500

     for runs in generarut(DESDE, HASTA):
         print runs

martes, 8 de febrero de 2011

Clase de conexión php-mysql

Bueno, como estaba aburrido y las clases de conexion con mysql y php no son muy completas o bien no se adaptan a mis necesidades, me dio por hacer esta que espero que a alguien le sirva de ayuda.


El codigo acontinuación.

<?php
class conSQL
{
private $usuarioDB='';
private $claveDB='';
private $hostDB='';
private $baseDB='';
public $consulta;
public $numfield;
public $affected;
public $numrows;
public $sql;
public $insertid;
private $conexion;

public function __construct($sql)
{
$this->sql = $sql;
}

private function conecta()
{
$this->conexion = @mysql_connect($this->hostDB,$this->usuarioDB,$this->claveDB) or die ("Base de datos en mantención.");
@mysql_select_db($this->baseDB);
return $this->conexion;
}

public function desconecta()
{
return mysql_close($this->conecta());
}

public function executeQuery()
{
$this->conecta();
$this->consulta = mysql_query($this->sql);
$this->numfield = mysql_num_fields($this->consulta);
$this->numrows = mysql_num_rows($this->consulta);
$this->desconecta();
$i=0;
$arreglo = array();
if ($rs = mysql_fetch_array($this->consulta)) {
do {
for ($j=0;$j<$this->numfield;$j++) {
$nombrecampo = mysql_field_name($this->consulta,$j);
$arreglo[$i][$nombrecampo] = $rs[$nombrecampo];
if ($j == $this->numfield) { $j = 0;}
}
$i++;
} while ($rs = mysql_fetch_array($this->consulta));
}
mysql_free_result($this->consulta);
return $arreglo;
}

public function executeUpdate()
{
$this->conecta();
$this->consulta = @mysql_query($this->sql);
$this->insertid = mysql_insert_id();
$this->affected = mysql_affected_rows();
$this->desconecta();
return $this->consulta;
}
}
?>

Modo de empleo:

Para este ejemplo simularemos una consulta tipo "SELECT" para que retorne algo, luego se mostrara una para el modo INSERT o UPDATE, que generalmente no retornan nada, excepto la cantidad de filas insertadas y/o actualizadas ah! y el ultimo insert realizado.

Ejemplo de SELECT.

require_once("/path/to/file/of/class/to/conexion.php");
$consulta="SELECT nombre,apellido FROM usuario";
$db = new conSQL($consulta);
$retorno = $db->executeQuery();
if ( $db->numrows > 0 )
{
foreach ( $retorno as $row )
{
echo $row['nombre']." ";
echo $row['apellido']."<br />";
}
}

?>

Ejemplo de UPDATE.
<?php

require_once("/path/to/file/of/class/to/conexion.php");
$consulta="UPDATE tbl1 SET apellido='macabeillo' WHERE nombre='juan'";
$db = new conSQL($consulta);
$db->executeUpdate();
if ( $db->affected > 0 ) // o tambien podria ser "if ( $db->affected )"
{
echo "El usuario ha sido actualizado";
}
?>

Ejemplo de INSERT.
<?php

require_once("/path/to/file/of/class/to/conexion.php");
$consulta="UPDATE tbl1 SET apellido='macabeillo' WHERE nombre='juan'";
$db = new conSQL($consulta);
$db->executeUpdate();
if ( $db->insertid > 0) // Al igual que UPDATE esto se puede hacer "if ( $db->insertid )
{
echo "El ultimo ingreso en la base de datos es: ".$db->insertid;
}

?>

martes, 5 de enero de 2010

Python y conexion a base de datos postgreSQL

Buscando información referente a las conexiones y querys de postgreSQL, me percate que no hay mayor detalle, como por ejemplo, recorrer una query a través de un SELECT...

Para este ejemplo se utilizara la API "psycopg2"

Bueno, rebuscandome una forma, encontre algo que quizas no sea muy elegante, pero el punto es que funciona...
A continuación les mostrare como.

# la variable argumentos contendria algo como esto:
# argumentos="host=localhost dbname=base_de_datos user=tu_usuario password=tu_clave port=5432"

class conexionSQL:
def __init__(self,argumentos=connectionString):
self.argumentos = argumentos

def select(self,query):
argumentos = self.argumentos
con = psycopg2.connect(argumentos)
cur = con.cursor()
cur.execute(query)
rows = cur.fetchall()
for row in range(len(rows)):
for campos in range(len(rows[row])):
print rows[row][campos]
cur.close()
con.close()

Creo que no hay mucho que agregar, pero el resultado seria:

campo1 campo2 campo3 campo4...
campo1 campo2 campo3 campo4...
campo1 campo2 campo3 campo4...

Saludos.

lunes, 20 de julio de 2009

*FIX* mod_rewrite: could not init rewrite log lock in child

Error al momento de enjaular apache y su respectiva solución.

Error
[crit] (2)No such file or directory: mod_rewrite: could not init rewrite log lock in child

Agregar esto

<ifmodule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^TRACE
RewriteRule .* - [F]
</IfModule>

O esto:

<ifmodule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^TRACE
RewriteRule .* - [F]
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 0
</IfModule>

Saludos.

jueves, 16 de julio de 2009

Pasar de extención nrg a iso en linux, cuando nrg2iso no funciona.

El otro dia me tope con la desagradable sorpresa al momento de intentar pasar una imagen nrg a iso con nrg2iso, lo cual desafortunadamente no funciono...

Buscando dentro de los repositorios de debian y/o ubuntu, encontre una aplicación llamada "iat" la cual cumple la misma función.

yo@mi-maquina:~$ apt-cache search iat && su root -c "apt-get install iat"
Password:

Y listo...
La forma de utilizar el programa, es a prueba de $%&/()!·$...
o sea...

yo@mi-maquina:~$ iat imagen.nrg nueva_imagen.iso

Saludos.

martes, 23 de junio de 2009

Problemas con locate + FreeBSD.

Uno de los problemas que me he encontrado al momento de leer foros de freebsd, es que en la mayoria de los casos no pueden utilizar el comando "locate", debido a que la forma de actualizar la base de datos interna, no es la misma que en linux.

Bueno, lo unico que tienen que hacer es ejecutar:

/usr/libexec/locate.updatedb

Aunque si quieren actualizar esto al modo linux, solo basta con hacer un simple enlace simbolico...

ln -s /usr/libexec/locate.updatedb /usr/bin/updatedb

Saludos.

lunes, 9 de marzo de 2009

Levantando un simple servidor DNS interno y externo con vistas.

Primero que todo "Hola", ya procedamos...
que necesitamos?
un servidor de nombre 2 tarjetas de red un cafe expreso sera suficiente, ya que este tema es bastante simple.

Instalando bind...
No explicare como hacerlo ya que es demasiado simple...
un ./configure --opciones && make && make install, y listo...

Antes de comenzar con la edición de los archivos debemos tener en cuenta o en su defecto saber que red interna tenemos...
En mi caso la "10.10.1.x".
Y como ip publica usaremos la 200.111.111.11.

Comenzamos la edición del corazon del dns...
en mi caso : "/etc/bind/named.conf"

Agregamos la siguiente vista interna:

view "internal" {
match-clients {10.10.1.0/24; 127.0.0.0/8;};
recursion yes;

zone "." {
type hint;
file "/etc/bind/db.root";
};

zone "dominio.cl" {
type master;
file "/etc/bind/internal.dominio.cl";
allow-transfer {any;};
allow-update {none;};
};
zone "localhost" {
type master;
file "/etc/bind/db.local";
};

zone "127.in-addr.arpa" {
type master;
file "/etc/bind/db.127";
};

zone "0.in-addr.arpa" {
type master;
file "/etc/bind/db.0";
};

zone "255.in-addr.arpa" {
type master;
file "/etc/bind/db.255";
};
};

Ahora la vista "externa":

view "external" {
match-clients {any;};
recursion no;
zone "dominio.cl" {
type master;
notify yes;
file "/etc/bind/external.dominio.cl";
};
};

Cabe destacar que por motivos de seguridad tenemos denegado la recursion a las zonas externas.

Bien...
Ahora vamos por la configuración de los archivos en si.

primero internal.dominio.cl

$TTL 1D ; 1 day
@ IN SOA ns.dominio.cl. info.dominio.cl. (
2009022777 ; Serial number
1600 ;
300 ; 5 minutes retry
17280 ; 2 days expiry
43200) ; 12 hours minimum
IN NS ns.dominio.cl.
IN MX 10 mail.dominio.cl.
IN A 10.10.1.2
$ORIGIN dominio.cl.
ns A 10.10.1.2
mail A 10.10.1.1
www A 10.10.1.2

Aca le estamos diciendo que el servidor NS es la ip del servidor de nombre...
en mi caso: 10.10.1.2, el servidor de correo esta en la ip 10.10.1.1
y bueno...
el resto es deducible.

Ahora vamos con external.dominio.cl
$TTL 1D ; 1 day
@ IN SOA ns.dominio.cl. info.dominio.cl. (
2009022777 ; Serial number
1600 ;
300 ; 5 minutes retry
17280 ; 2 days expiry
43200
) ; 12 hours minimum

IN NS ns.dominio.cl.
IN MX 0 mail.dominio.cl.
IN A 200.111.111.111

$ORIGIN dominio.cl.
ns IN A 200.111.111.112
www IN A 200.111.111.112
mail IN A 200.111.111.111


Una vez tenemos todos nuestros registros agregado a los archivos, procedemos reiniciar el servicio...

Con el tipico "/etc/init.d/{bind,named} restart"
o si no con un simple "kill -9 $PID && named"

En fin...
eso es todo.

Saludos.

sábado, 7 de marzo de 2009

Fecha en php

El motivo de esta entrada, es que varias veces foreando, me he encontrado con la pregunta...
"Como pongo la fecha en español con la funcion date de php?".

Por ello, he creado un script simple, sin muchas lineas, las cuales les ayudaran para ello.

<?php
$meses=array(
"Janaury"=>"Enero",
"Febraury"=>"Febrero",
"March"=>"Marzo",
"April"=>"Abril",
"May"=>"Mayo",
"June"=>"Junio",
"July"=>"Julio",
"August"=>"Agosto",
"September"=>"Septiembre",
"October"=>"Octubre",
"November"=>"Noviembre",
"December"=>"Diciembre"
);

$semana=array(
"Monday"=>"Lunes",
"Tuesday"=>"Martes",
"Wednesday"=>"Miercoles",
"Thursday"=>"Jueves",
"Friday"=>"Viernes",
"Saturday"=>"Sabado",
"Sunday"=>"Domingo"
);
echo $meses[date("F")]." - ".$semana[date("l")];
?>

Al final aparece como usarlo...

por ejemplo si queremos imprimir en pantalla, hoy es sabado 7 de Marzo del 2009

solo tendriamos que escribir:

echo "hoy es ".$semana[date("l")]." de ".$meses[date("F")]." del ".date("Y");


Saludos.

martes, 24 de febrero de 2009

Agis + php + GotoIfTime + mysql + asterisk = Un par de horas de trabajo.

Bueno...
Primero que todo "hola", ya mucho saludo...

El motivo de esta entrada es ayudar a los Sysadmin que tienen bajo responsabilidad servidores asterisk.
Con el fin de que la telefonia, no se transforme en un abuso despues del horario laboral.

Caso hipotetico:
- Supongamos que el horario laboral de una empresa es entre las 09 y 19 hrs entre lunes a viernes,
una vez que todo el personal se halla retirado de las dependencias de su empresa, llega la persona encargada de realizar el aseo a esta. A lo que vamos, es que nadie nos asegura que esta persona, no se pondra a realizar largas llamadas con coste para la empresa.

Entonces, nos quedan 3 opciones...
- Limitamos para que nadie realice llamadas.
- Dejamos el sistema abierto y que llame descontroladamente.
- Generamos un sistema de autentificación el cual funcionara despues de la jornada laboral.

Obviamente descartaremos las primeras 2 opciones.
En la tercera opción, la podemos realizar de 2 formas...
Una con authenticate y disa, las cuales me dio flojera adentrarme en el tema...
y la otra con Agi y bases de datos...

Obviamente, por el titulo de esta entrada, ya sabran cual usaremos esta vez.
ya...
manos a la obra...
lo primero que necesitaremos es:
Un servidor corriendo con asterisk, lo ideal que la distribución sea Debian en el caso de linux.
Ya que Redhat y CentOS apéstan.

Necesitaremos:
php5
php5-mysql
php5-cli
mysql-server
y amigos (o sea... dependencias).
phpagi v2.

Una vez que tengan todo esto instalado,
Procederemos a la configuración.

Todos las AGI de asterisk, por defecto se encuentran en el directorio "/var/lib/asterisk/agi-bin"
Las AGI son como los cgi del http, esto quiere decir que a nuestra central le haremos ejecutar un archivo, al cual le pasaremos parametros de asterisk para que ejecute de mejor forma el proceso.

descomprimir el archivo phpagi-2.14.tar.gz (este es el usado en este ejemplo, aunque la version puede variar) dentro del directorio "/var/lib/asterisk/agi-bin", lo cual nos dara un directorio llamado "phpagi-2.14/", renombrenlo como quieran, es cosa de cada uno...

El tema es que en mi caso particular lo deje tal cual.:

pbx:~# ls /var/lib/asterisk/agi-bin/phpagi-2.14
COPYING docs mkdocs.php phpagi-asmanager.php phpagi-fastagi.php phpagi.php README

ya...
ahora procederemos a crear una nueva entrada en el dialplan (extensions.conf).

Con su editor de texto favorito editen el archivo...
en mi caso estoy acostumbrado a "vi".
############################################

Asterisk

############################################
pbx:~# vi /etc/asterisk/extensions.conf #### y agregamos lo siguiente.

[locales_prueba]
exten => _XXXXXXX,1,GotoIfTime(9:00-19:00|mon-fri|*|*?dentrohorario,${EXTEN},1)
exten => _XXXXXXX,n,Answer
exten => _XXXXXXX,n,Agi(logea|${EXTEN}|${CALLERID(NUM)})
exten => _XXXXXXX,n,hangup

[dentrohorario]
exten => _XXXXXXX,1,Dial(Zap/g1/${EXTEN},50)
exten => _XXXXXXX,n,hangup

######### EOF

la primera entrada es la que le definiremos a los usuarios SIP como contexto.
En la primera prioridad del contexto vemos algo como GotoIfTime, hare una explicación corta, ya que me cargan las explicaciones largas...
Quiere decir que haga un salto a otro contexto u otra prioridad si se cumple la condición del horario.
es decir... que si se encuentra dentro del horario, entonces salte al contexto [dentrohorario] que ejecute la primera prioridad de la llamada...
me entienden?...
un poco mas simple....

si realizan una llamada dentro del horario al telefono 1111111, entonces esta le pasa la llamada al contexto [dentrohorario] y la prioridad 1, que esta vendria ejecutando la llamada.
Si esto no fuera asi, entonces ejecutaria la prioridad 2 dentro del contexto [locales_prueba], la cual lo que hace es ejecutar el script AGI llamado logea, con sus respectivos parametros.

${EXTEN} = "Telefono de destino, o sea... a que numero se esta llamando (1111111)".
${CALLERID(NUM)} = "Quien es el que realiza la llamada".

################################

phpagi

################################

Una vez destarjetezeado el archivo (que chileno), ingresamos a el...
pbx:~# cd /var/lib/asterisk/agi-bin/phpagi-2.14/
pbx:~# ls
CHANGELOG CVS fastagi.xinetd phpagi.example.conf README.phpagi README.phpagi-asmanager README.phpagi-fastagi

Aca lo unico que nos interesa es el archivo phpagi.example.conf, el cual copiaremos a /etc/asterisk/phpagi.conf

posterior a ello, editamos el archivo:

pbx:~# vi /etc/asterisk/phpagi.conf
Lo unico que editamos es la seccion [phpagi] y modificamos los parametros.
[phpagi]
debug=true
error_handler=true
admin=tu@correo
hostname=el_host_de_la_maquina_de_asterisk
tempdir=/var/spool/asterisk/tmp/

############ EOF ################

Ahora procederemos a configurar nuestros scripts.
Primero debemos crear una base de datos para los usuarios y las claves.

pbx:~# mysql asterisk
mysql> create table usuario ( id_usuario int(10) not null auto_increment, nombre_usuario char(100) not null default'', clave_usuario char(64) not null default'', primary key(id_usuario));

#### Donde nombre_usuario contendra el numero que realiza la llamada, enrealidad deberia llamarse numero_usuario, pero ahi lo modifican ustedes, ya que esto es un mero y funcional ejemplo del mini sistema.

Una vez generada la tabla para los usuarios, le agregamos uno de prueba...
insert into usuario values (0,'123','e10adc3949ba59abbe56e057f20f883e');

La clave del usuario es "123456" (sin comillas), esto es sumamente facil con php y la funcion md5
resumido...

hagan un script php y pongan lo siguiente:

vi archivo.php e ingresan esto a continuación.

#!/usr/bin/php5 -q
<?php
$string="123456";
$clave=md5($string);
printf("$clave\n");
?>

pbx:~# chmod +x archivo.php
pbx:~# ./archivo.php
e10adc3949ba59abbe56e057f20f883e
pbx:~#

ahora bien...
Necesitamos crear el archivo "logeo" el cual contendra la logica que procesara los nombres de usuarios y a su vez les solicitara la clave correspondiente.

#!/usr/bin/php5 -q
<?php
$org=$argv[2];
$dst=$argv[1];
require ("phpagi-2.14/phpagi.php");
error_reporting(E_ALL);
$agi = new AGI();
$agi->answer();
$agi->text2wav("Porfavor ingrese su clave");
$recoje=$agi->get_data('beep',3000,10);
$clavex=$recoje['result'];
if(!empty($clavex)){
$host="localhost";
$user="USUARIO";
$pass="PASSWORD";
$db="asterisk";
$con=mysql_connect($host,$user,$pass) or die(mysql_error());
mysql_select_db($db,$con);
$clave=md5($clavex);
$sql=mysql_query("select * from usuario where nombre_usuario='$org' and clave_usuario='$clave'",$con);
$rs=mysql_fetch_array($sql);
$logeado=$rs['nombre_usuario'];
if(empty($logeado)){
$agi->text2wav("La clave ingresada es incorrecta Adios");
} else {
$agi->exec("Dial Zap/g1/$dst,50");
}
mysql_close($con);
} else {
$agi->text2wav("El tiempo de espera ha concluido Adios");
}
$agi->Hangup();
?>

############
Aca hay un tema que no se ha tocado, y que es el que el lector actualemente se haya dado cuenta...
es sobre "text2wav", creo que con solo leer sabran para que sirve...
Para esto necesitamos el programa festival el cual pasa de texto a voz, pero sinceramente las voces por defecto son demasiado roboticas, asi que les aconsejaria que siguieran el siguiente "howto" el cual explica como instalarlo y dejarlo funcional:

festival en spanish (Coño!)
############

Ahora bien...
Para que los mismos usuarios realicen sus propios cambios de claves, sin necesidad que nos esten molestando, o por solamente dejar esto mas transparente, realizamos el siguiente AGI (cambiarclave).
Que a continuación se muestra.:

#!/usr/bin/php5 -q
<?php
require("phpagi-2.14/phpagi.php");
$host="localhost";
$user="USUARIO";
$pass="PASSWORD";
$db="asterisk";
$con=mysql_connect($host,$user,$pass) or die(mysql_error());
mysql_select_db($db,$con);
error_reporting(E_ALL);
$org=$argv[1];
$agi=new AGI();
$agi->answer();
$agi->text2wav("Por favor ingrese su actual clave");
$datos=$agi->get_data('beep',3000,10);
$clave=$datos['result'];
if(!empty($clave)){
$clave=md5($clave);
$sql=mysql_query("select clave_usuario from usuario where nombre_usuario='$org'",$con);
$res=mysql_fetch_array($sql);
$cl=$res['clave_usuario'];
do {
$agi->text2wav("La clave ingresada es incorrecta");
$agi->text2wav("Por favor ingrese su actual clave");
$datos=$agi->get_data('beep',3000,10);
$clave=$datos['result'];
$clave=md5($clave);
} while($cl!=$clave);
$agi->text2wav("Por favor ingrese su nueva clave");
$actualiza1=$agi->get_data('beep',3000,15);
$nueva=$actualiza1['result'];
$agi->text2wav("Reingrese la nueva clave");
$actualiza2=$agi->get_data('beep',3000,15);
$nclave=$actualiza2['result'];
do {
$agi->text2wav("Las claves no coinciden");
$agi->text2wav("Por favor ingrese su nueva clave");
$actualiza1=$agi->get_data('beep',3000,15);
$nueva=$actualiza1['result'];
$agi->text2wav("Reingrese la nueva clave");
$actualiza2=$agi->get_data('beep',3000,15);
$nclave=$actualiza2['result'];
} while($nclave!=$nueva);
if($nclave==$nueva){
$clave_nueva=md5($nclave);
$update="update usuario set clave_usuario='$clave_nueva' where nombre_usuario='$org'";
mysql_query($update,$con);
$agi->text2wav("La clave ha sido cambiada exitosamente su nueva clave es $nclave");
$agi->text2wav("adios");
$agi->hangup();
}
mysql_close($con);
} else {
$agi->text2wav("El tiempo limite ha sido excedido adios");
$agi->hangup();
}
?>

Para habilitar este servicio.
debemos generar una nueva entrada al contexto de los usuarios, por ejemplo designemosles el numero "222", la sintaxis seria la siguiente:

exten => 222,1,Answer
exten => 222,n,Agi(cambiarclave|${CALLERID(NUM)})
exten => 222,n,Hangup

Dentro del contexto definido para los usuarios, que no se les olvide...
En este caso ponganlo dentro locales_prueba y dentrohorario.

Solo nos queda darles permiso de ejecución a los archivos.
esto seria:

pbx:~# cd /var/lib/asterisk/agi-bin
pbx:/var/lib/asterisk/agi-bin# chmod +x logeo cambiarclave

y Realizamos las pruebas correspondiente...

Espero que les sirva, y he intentado no dejar nada en el tintero...
si falta algo o no funciona, posteenlo y lo respondere a la brevedad...

Dedicatoria:

- A mi compare Poncio Monsalvez (talla interna).
- A mi PC que le cayo cafe en el teclado el dia de hoy, pero ni se quejo.
- Al Juan por hablar estupideces...
- Al Poncio que me presiona para que le envie los tips.

Eso seria...

Fuentes:
http://phylevn.mexrom.net/index.php/blog/show/Como_implementar_un_AGI_con_PHP_en_un_conmutador_de_VoIP_sobre_Asterisk.html
http://google.cl
http://www.voip-info.org

jueves, 29 de enero de 2009

Tomcat +ssl +jboss

Es un asco...
recorri bastantes foros buscando la bendita forma de como hacerlo...
hasta que di con una solución...
la mas practica y simple que habia visto...
por mi parte tambien pense que se podia hacer, pero me deje guiar por la documentación.
beps
solución simple.


openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out cert.pem -days 365
openssl pkcs12 -export -in cert.pem -inkey key.pem -out cert.p12 -name

Asegurence de ponerle clave al certificado.

posteriormente, modificar el server.xml de tomcat.

<connector port="8443" address="${jboss.bind.address}" maxthreads="100" strategy="ms" maxhttpheadersize="8192" emptysessionpath="true" scheme="https" secure="true" clientauth="false" keystoretype="PKCS12" keystorefile="/path/al/archivo/conf/ssl/cert.p12" keystorepass="LA_PASS_QUE_LE_PONEMOS_AL_CERTIFICADO" sslprotocol="TLS">


Despues reiniciar el servicio.

/opt/jboss-4.2.2.GA/bin/shutdown.sh -S
nohup /opt/jboss-4.2.2.GA/bin/run.sh -b 0.0.0.0 &

realizamos un nmap y que lindo

el puerto 8443 esta en escucha...
abrimos firefox y aceptamos el certificado autofirmado y felices para siempre :D

Para dejarlo transparente...
deben modificar el mod_jk, pero eso sera en otra ocación miren que ahora estoy chato
xD
bye

viernes, 23 de enero de 2009

Dolor de cabeza por ruby +mongrel +windows +postgresql

Como se hace mensión en el titulo, estos 2 ultimos dias han sido algo desagradables...

Comenzamos el dia en una prestigiosa empresa vinicola en a la cual debia levantar una aplicación escrita en ruby, pero en un ambiente windows.

Lo primero que se me vino a la mente fue...
"Descargar la aplicación y derivados, hacer un par de configuraciones y en 1 hora deberia estar listo, incluyendo las pruebas para que el cliente estubiese conforme".
Resultado "LAS PELOTAS"
6 horas me tomo el chiste...
Detalle de la aventura...

Llevaba en mi buen pendrive las aplicaciones o sea:
- Ruby 1.8.x
- PostgreSQL 8.3.x
- Apache 2.2.x

Comenzamos la instalación con ruby...
Ningún problema, pero para mi desagradable sorpresa, necesitaba algunas librerias las cuales se instalaban via "gem", lo cual en esa situación me complico un poco debido a que en la empresa a la cual fui, por defecto tienen denegado el acceso a internet excepto el puerto 80...
Desconosco el protocolo de comunicación que utiliza 'gem', pero el punto es que no pude instalarlo tan rapido como ubiese querido...

Ya...
Nos comunicamos con el administrador de red para solicitar permiso y que nos permitiera el acceso total a la ip que tenia ese equipo.
La buena noticia es que se logro la comunicación necesaria para que comenzase la descarga.
La mala noticia es que el enlace internacional que tiene esa empresa es un asco.

Mientras que se realizaba la descarga de las librerias, nos encontramos con otra desagradable sorpresa...
El paquete de instalación de postgres al finalizar la instalación encontraba un error y no permitia continuar con esta y comenzaba a desinstalarse...
"Bendita suerte..."
Lo unico que se me ocurrio en ese momento fue downgradear la versión la cual se iba a instalar en dicho equipo...
o sea...
volver a la versión 8.2.x, la cual al comenzar a descargar nos demoramos cerca de 3 horas en bajar todas las librerias necesarias de ruby y tambien postgres 8.2.x.

3 horas despues estaba instalando postgres 8.2.x, el cual al finalizar la instalación me arrojo un error de permisos... (lo raro es que estabamos con un usuario el cual tenia privilegios de administrador), pero en fin "Es windows" y ya no me sorprende los errores tontos que este trae...
Le pregunte la password de administrador, cosa que no tenia idea...
Despues de llamar a la mesa de ayuda de la empresa, intentamos todas las contraseñas posibles que ellos nos decian, PERO NINGUNA FUNCIONO!!!...
ahora viene la parte (Ley de murphy).
Intentamos sin usar clave y voila!, funciono...
En fin, se instalo postgres sin ningún inconveniente.

Pero...
Para mi desagradable sorpresa, nos encontramos con un problema con las librerias de postgres, ya que no se instalaba de la misma forma que en Unix.

En windows el paquete se llama:
ruby-postgres
y en Unix solo se llama:
postgres

o sea... debiamos instalar en windows de la siguiente manera...
gem install ruby-postgres
en vez de:
gem install postgres

En teoria, una vez realizado esto, el tema de la sincronización con la base de datos deberia quedar resuelto.
Cosa que no fue tan asi...
debido a que nos pedia algunas librerias de postgres, mas conocidas como las "postgres-dev" en Unix.
La solución encontrada por aca fue que debiamos realizar una copia de X librerias al directorio de Ruby.
En este caso C:\ruby\bin desde C:\path\postgresql\bin
estos son:

- comerr32.dll
- krb5_32.dll
- k5sprt32.dll
- libeay32.dll
- libpq.dll
- libiconv2.dll
- libintl3.dll
- ssleay32.dll
- gssapi32.dll

Yo felizmente pensaba...
Por fin... ahora levanto el servicio y chao!...
Me limito a decir que solo me que quede con las ganas, ya que al correr el comando:
// En la directorio de la aplicación.

mongrel_rails start -d -p 3000 -e production
Y me sorprendo con lo que me arroja de vuelta es un lindo error que dice que win32 no soporta este servicio...
Fue cuando dije...
"Este sera un laaaaaaargo dia..."
Afortunadamente, san google siempre esta ahi cuando tenemos problemas.
No recuerdo con exactitud que pagina es pero, pongo la solución.

mongrel_rails service::install -N NOMBRE_APLICACION -c "C:\APLICACION" -p 3000 -e production

seguido por:
net start NOMBRE_APLICACION

y listo.
Problema solucionado.
Ahora el tema era que se iniciara automaticamente...
Con la primera linea, si se percatan dice... "service::install"
con esto creamos una entrada en "services.msc", y solo nos faltaria modificarla para que el servicio se iniciara automaticamente al prender el equipo.

Nos fuimos a Inicio, ejecutar y ahi escribimos: services.msc
buscamos el nombre que le pusimos al servicio... En este ejemplo "NOMBRE_APLICACION"
y lo editamos, y le decimos que se inicie automaticamente...

Despues de realizar unas pruebas con internet explorer, decidimos a cambiar a firefox
ya que no habria por IE, pero si con firefox...

Bueno...
demostrado que el tema fue solucionado, el cliente se quedo tranquilo
Fin.

NO QUIERO SABER MAS DE WINDOWS!!!