#!/usr/bin/perl 

# Envío de mensajes a teléfonos móviles
# -------------------------------------
# Este script recibe como parámetros el número de telefono y el 
# mensaje a enviar (ojo a las comillas) y lo reenvía por la
# pasarela que esté disponible para ese número (según el proveedor)
# ------------------------------------------------------------
#        Copyright (C) 1999 Javier Fernandez-Sanguino Peña
#
# Este programa es software libre; puedes redistribuirlo y/o modifcarlo
# bajos los términos de la Licencia General Pública GNU como la publica
# la Free Software Foundation; o bien la versión 2 de esta Licencia, o
# (a su elección) cualquier versión posterior.

# Este programa se distribuye con la idea de que esa útil, pero 
# SIN NINGUNA GARANTÍA; ni siquiera la garantía implícita de 
#  COMERCIABILIDAD o AJUSTE A UN PROPÓSITO PARTICULAR. Lea la Licencia
# Pública General de GNU para más detalles.
# 
# Debería haber recibido una copia de la Licencia Púbilca General
# junto con este programa; si no es así, escriba a la Free Software
# Foundation, Inc.,  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# ( o búsquela en http://www.gnu.org)
#
# -------------------------------------------------------
# Copyright (C) 1999,2000,2001 Javier Fernandez-Sanguino Peña (jfs@computer.org)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc.,  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# ------------------------------------------------------------


# Direcciones útiles:
# Airtel (607-XXXXXXX)  http://www.airtel.es/airtel/10/1020/1020d/1020d.html?
# o http://www.navegalia.com/sms/sms_.htm
# Movistar (616) 
# Retevisión (656) http://www.amena.com

# TODO: 
#- Permitid uso de pasarela generica con opcion de linea comangos. 
#- que no pida email siempre  (HECHO Mon, 17 Apr 2000 18:33:02 +0200)
# -probar si funciona la pasarlea activajoven de verdad 
# -añadir más pasarelas genéricas 


# Los datos se nos pasan por línea de comandos
use Getopt::Std;
use HTTP::Date;
require HTTP::Request;
require LWP::UserAgent;
getopts ('pdhvm:t:e:o:');

# Configuración por parte del usuario
# El correo se podría pasar como opción (debe ser el del usuario o el del agente)
$test_e_mail="test\@test.com";

# Configuración
$PROGRAM_NAME="SMSbot";
$VERSION="0.1";
$action{'airtel'}="http://teleav.airtelmovil.net/cgi-bin/cgi-nav";
$referer{'airtel'}="http://www.navegalia.com/portal/ofiweb/sms/index.htm";
$action{'amena'}="http://62.81.255.3/sms-cgi/sendsms.pl";
$referer{'amena'}="http://62.81.255.3/sms-cgi/websms.pl";
$action{'movistar'}="";
$referer{'movistar'}="";
$action{'generico'}="http://www.terra.es/sms/envio.cfm";
$referer{'generico'}="http://www.terra.es/sms";
#$action{'generico'}="http://www.mtnsms.com/sms.asp";
#$referer{'generico'}="http://www.mtnsms.com/";
# Máximo número de octetos a enviar 
$MAX_OCT=140;
$PREFIX=34;
$PRE_PART = " (p ";
$POST_PART = " )";

my $numTelefono=$opt_t;
my $totalMensaje=$opt_m;
my $e_mail="$opt_e";
$e_mail =~ s/\@/\\\@/;
$not_sent=1;


if ( $opt_h or ! $numTelefono or ! $totalMensaje  )  
{
	print <<EOM;
Uso: $0 [-hv] -m mensaje -t teléfono -e tu_dirección_de_correo
Manda un mensaje corto SMS a un teléfono móvil GSM
\t-h\testa ayuda
\t-v\tdar información de lo que hace
\t-d\tmostrar información de depuración
\t-e\tdirección de correo (ejemplo $test_e_mail)
\t-p\tprueba pero no hace nada
\t-o\toperador al que enviar los mensajes siempre ("generico") va al genérico
EOM
#TODO: implementar bien las funciones de depuración
	     exit 1;
}

# A partir de aquí el programa 
print "Numero de Telefono: $numTelefono\n" if $opt_d;
print "Mensaje: $totalMensaje\n" if $opt_d;

if ( length $totalMensaje >$MAX_OCT )
{ 
    print "Es necesario partir el mensaje\n" if $opt_d; 
    
    my $posicion = 0 ; my $part = 1;
    my $exit_code = 0;
    while ($posicion < length ($totalMensaje) ){
	$mensaje = substr ($totalMensaje, $posicion, $MAX_OCT);
#TODO: Podría poner mejor el número de partes que quedan para enviar
# (que es más útil que sólo la parte actual)
	$mensaje = $mensaje.$PRE_PART.$part.$POST_PART;
	$posicion = $posicion + $MAX_OCT;
	$part++;
# TODO: Debería comprobar que el mensaje + el PRE_PART y POST_PART
# y el número no se sale de MAX_OCT
# TODO: Poner un límite máximo al tamaño del mensaje (o decidir no poner
# PRE y POST si está en ciertos márgenes)
	print localtime()." Ahora enviaremos el trozo (nueva posicion $posicion): \"$mensaje\"\n" if $opt_d;
	$exit_code = enviaMensaje ($numTelefono, $mensaje);
	last if $exit_code ; # Si no se ha podido enviar un trozo no seguimos
    }
}
else
{
    $exit_code = enviaMensaje ($numTelefono, $totalMensaje);
}

exit $exit_code;

sub enviaMensaje () {
# Esta función es la que realiza el envío del mensaje
# supuestamente deberían llegarle no más de 150 caracteres
    
    my ($numTelefono, $mensaje) = @_;
    print localtime()." Enviando mensaje \"$mensaje\" al número $numTelefono\n" if $opt_d;
# Si está el prefijo internacional español lo quitamos, ya lo pondremos en la pasarela internacional
    $numTelefono =~ s/^\+${PREFIX}//; 

if ( ! ( $numTelefono =~ /^\d{9}$/ ) )
{
    print  STDERR "El teléfono $numTelefono no es válido debe estar en un formato soportado\n" if $opt_v;
# TODO: indicar los formatos
    exit 1;
}

if ( length $mensaje > $MAX_OCT )
{
    print STDERR "El mensaje indicado es demasiado largo (más de $MAX_OCT) y no seré enviado";
    exit 1;
}
$numTelefono =~ s/^9(.*)/6$1/; # En España cambió la numeración de un 9 a un 6

# Una vez hechas las comprobaciones empieza a discriminar por números
# de teléfono, para ver la asignación hecha por la CTM
# probar http://www.cmt.es/cmt/info/numer/m_num.htm
# Los datos (en julio 1999) eran:
# Telefónica: 601, 606, 609, 616, 619, 626, 629, 630, 636, 639, 646, 649, 676, 686, 689, 696
# Airtel: 600, 607,  610, 617, 666, 667, 670, 677
# Retevisión: 654, 656

#TODO: algo de inteligencia, que saque el la numeración de la página 
# y pruebe el operador que le devuelva (formulario en página
# http://www.cmt.es/cmt/numeracion/b_num4_2.htm?campo=DIGITOS&buscar.x=0&buscar.y=0 (campo valor)

if ( ! $opt_o ) {
    $operadores{'airtel'}="^(607|670|610|617|666|667|670|677)";
    $operadores{'amena'}="^(656|654)";
    $operadores{'movistar'}="^(649|639|601|606|609|616|619|626|629|630|636|646|676|686|689|696)";
    $current_op=$opt_o if $opt_o;
    foreach $operador (keys %operadores) {
	$current_op=$operador if $numTelefono =~ /$operadores{$operador}/ ;
    }
}

print "El operador de este telefono es $current_op\n" if $opt_v;
$current_op=$opt_o if $opt_o;

if ( $current_op eq 'airtel' )
{
    print  localtime()." El teléfono $numTelefono es Airtel\n" if $opt_v;
# Variables en http://www.navegalia.com/sms/sms_.htm
# tNumber: telefono, nAddress: e-mail de aviso, mBody: texto
# action : http://www.airtelmovil.net:80/cgi-bin/cgi-nav

# DONE-TODO: La pagina de Airtel mira el navegador que se esta usando,
# hacerle creer que es un navegador y no un robot
# Usa el User-Agent? 
# 30 julio: Descartado después de pruebas con varios User-Agents
# 30 julio: Fixed con las cabeceras (mirado el código de Lynx)

# Antes de nada hay que pasar el mensaje a formato CGI estandar
# TODO: Pasar con la libreria de CGIs al fomarto estandar 
    $mensaje =~ s/ /+/g;
    $get = "?tNumber=${numTelefono}\&nAddress=$e_mail\&mBody=$mensaje\&submit=Enviar+mensaje";
    $not_sent=send2WWW ("$action{'airtel'}", "$referer{'airtel'}", "$get", 'GET');
#	$not_sent=send2WWW ("http://cabezon.gsi.dit.upm.es/cgi-bin/test-cgi", "$get", 'GET');
}

# Telefónica: 601, 606, 609, 616, 619, 626, 629, 630, 636, 639, 646, 649, 676, 686, 689, 696
if ( $current_op eq 'movistar' )
{
    print localtime()." El teléfono $numTelefono es un Movistar Activa Joven.\n" if $opt_v;
#		$mail = $numTelefono."\@activajoven.tsm.es";
    $mail = $numTelefono."\@correo.movistar.net";
    print localtime()." La dirección de correo a enviar es $mail.\n" if $opt_v;
    $not_sent  = send2Mail ("$mail","", "$mensaje") ;
}

if ( $current_op eq 'amena' )
{
    print localtime()." El teléfono $numTelefono es un Amena.\n" if $opt_v;
    my $wwwmsg = $mensaje;
    $mail = $numTelefono."\@amena.com";
    print localtime()." La dirección de correo a enviar es $mail.\n" if $opt_v;
# A los amenas hay que ponerles el texto del mensaje
# en el asunto para que les llegue como mensaje SMS
    $not_sent  = send2Mail ("$mail", "$mensaje","") ;
    if ( $not_sent == 1 )
    {
	$wwwmsg =~ s/ /+/g;
	$post = "?number=${numTelefono}\&msg=$wwwmsg\&submit=Enviar\n";
	$not_sent=send2WWW ("$action{'amena'}", "$referer{'amena'}", "$post", 'GET');
    }
    
}


if ( $not_sent == 1  or $current_op eq 'generico' )
{
# Intentará enviarlo por la pasarela genérica de
# para telefonos moviles (y buscas)
    print localtime()." No se ha podido enviar por pasarelas específicas probando pasarela genérica.\n" if $opt_v;
    $mensaje =~ s/ /+/g;

#  http://www.mtnsms.com/
#	$numTelefono = "+".$PREFIX.$numTelefono; #La pasarela es internacional hay que poner el prefijo de España
#		$post = "msgTo=".$numTelefono."\&";
#TODO: utilizar CGI.pl para pasar a formato normal
#	$post = $post."msgText=".$mensaje."\&";
#	$post = $post."msgCL=160\&";
#	$post = $post."msgSig=0\&";
#	$post = $post."butSub=send\&";
#	$post = $post."lenSSig=6\&";
#	$post = $post."lenLSig=21\&";
#	$post = $post."lenSysSig=11\&";

# http://www.terra.es
# TODO: no funciona
#		$post = $post."telefono=".$numTelefono."\&";
#		$post = $post."mensaje=".$mensaje."\&";
#		$post = $post."fecha=ts+'2000-03-30+18:03:43'";
#		$not_sent = send2WWW ("$action{'generico'}", "$referer{'generico'}", "$post", 'POST')

# http://www.navegalia.com
    
    $get = "?tNumber=${numTelefono}\&nAddress=$e_mail\&mBody=$mensaje\&submit=Enviar+mensaje";
    $not_sent=send2WWW ("$action{'airtel'}", "$referer{'airtel'}", "$get", 'GET');
    
# http://www.jumpy.it
# numero=XXX
# prefisso=0034
# messaggio=
# action:http://sms.jumpy.it/cgi-bin/sendsms.pl
# GET
# referer: http://www.jumpy.it/830sms.html


# http://www.lycos.de/service/sms.htm
# (Cookie: SMS=Okay) ???
# No disponible 30 dic 2000



#Para probar: $not_sent = send2WWW ('http://cabezon.gsi.dit.upm.es:80/cgi-bin/test-cgi', $mensaje, 'POST')
		}

# TODO : utilizar smsclient (muy sencillo, ojo a los mensajes devueltos) 
# de forma que se pudiera instalar con un modem


if ( $not_sent ) 
{
    print localtime()." El mensaje no ha podido ser enviado.\n";
}
else 
{ 
    print localtime()." Mensaje enviado.\n" if $opt_v;
}

return $not_set;

}


# -----------------------------------------------------------------------
# Subrutinas utilizadas
# send2Mail : envia un mensaje a una dirección de correo utilizando
#	el programa mail
# send2WWW : envía un mensaje a través de una pasarela web

sub send2Mail ()
{
#TODO: Perl debe tener formas de enviar correo internas mejores
# Enviar los datos via mail a la dirección indicada
    my ($address, $subject, $text) = @_;
    if ( $opt_p )
    {
	print localtime()." Se enviaría el mensaje \"$text\" con asunto \"$subject\" a la dirección de correo $address\n";
	return 1;
    } 
# TODO: La sintaxis del mail y el programa a utilizar 
# depende del sistema, usar autoconf o ver el TODO anterior
    my $MAIL_PROGRAM="/usr/bin/mail";
    print localtime()." Ejecutando $MAIL_PROGRAM $address.\n" if $opt_v;
    open (MAIL,"|$MAIL_PROGRAM $address -s \"$subject\"") || die ("No puedo enviar correo: $!");
#print MAIL "From: $PROGRAM_NAME/$VERSION\n\n";
#print MAIL "Subject: msg from $PROGRAM_NAME/$VERSION\n\n";
    print MAIL "$text\n";
    close MAIL or die ("Error cerrando el correo : $!");
    
    return 0;
}


sub send2WWW () 
{
# Enviar los datos dados a la dirección indicada
    my ($address, $referer, $text, $method) = @_;
    if ( $opt_p ) 
    {
	print localtime()." Se enviaría la petición \"$text\" al servidor $address (método: $method)\n" ;
	return 1;
    }
    if ( ! $method =~ /^GET|POST/ )
    {
	print STDERR "Método no soportado : $method\n";
	return 1;
    }
    if ( $method =~/GET/ )
    { 
	$URL = new URI::URL "${address}${text}";
    }
    if ( $method =~/POST/ )
    { 
	$URL = new URI::URL "$address";
    }
# Crear agente de usuario que procese la llamada
    my $ua= new LWP::UserAgent;
    $ua->agent("$PROGRAM_NAME/$VERSION");
# El tiempo de espera debería ser configurable
    $ua->timeout(20);
# Preparar y enviar la petición
    my $request= new HTTP::Request "$method", $URL;
    $request->push_header ('Accept' => 'text/html, text/plain, image/*, */*;q=0.01');
    $request->push_header ('Accept-Encoding' => 'gzip, compress');
    $request->push_header ('Accept-Language' => 'en');
    $request->push_header ('Accept-Charset' => 'ISO-8859-1');
    $request->push_header ('Negotiate' => 'trans');
    $address =~ /^http\:\/\/(.*?)\//;
    $host = $1;
    $request->push_header ('Host' => $host);
    $request->push_header ('Referer' => $referer);
    
    if ( $method =~ /POST/ )
    {
# Fijamos el Content-Length
	$length = length $text;
	$request->push_header ('Content-Length' => $length);
	$request->content ($text);
	$request->push_header ('Content-Type' => 'application/x-www-form-urlencoded');
    }
    print localtime()." Enviando la petición:\n" if $opt_d;
    print $request->as_string if $opt_d;
# Contactar el servidor remoto y recibir respuesta
    $response=$ua->request($request);
    if ( $response->is_error  == 1 )
    { 
	print STDERR "Error accediendo a $address:\n";
	print STDERR $response->error_as_HTML();
    }
    else 
    {
	print localtime()." La respuesta recibida ha sido:\n" if $opt_v;
	print $response->content if $opt_v;
    }
    
    return $response->is_error;
}
