Amulet pl src
From AMule Project FAQ
aMulet.pl source
#!/usr/bin/perl -w
#
# file aMulet.pl
# Copyright by AnimAlf
#
# This lines are under the GNU General Public License.
# http://www.gnu.org/copyleft/gpl.html
#
# aMulet - la t final en catalán le indica diminutivo
# También se traduce como amuleto
use strict;
my $binaMuled = 'amuled -f';
my $apppid = "$ENV{HOME}/.tx2z.pid";
my $logMode = "warning"; # debug warning msg
my $verbose = 1; # true false
if (!defined($ENV{'DISPLAY'})){
print &appRel . "\nATENCIÓN: Este script necesita ser ejecutado bajo las X Window\n";
exit -1;
}
eval "use Gtk2::TrayIcon;";
if ($@) {
print &appRel;
print "\n\nATENCIÓN: Este script necesita el módulo Gtk2::TrayIcon\n\n";
print "Puede instalarlo a través de CPAN del siguiente modo:\n\n";
print "\t\tperl -MCPAN -e shell\n";
print "\t\tinstall Gtk2::TrayIcon\n\n";
print "bye\n";
exit -1;
}
my $modUniCode;
eval "use Unicode::MapUTF8 qw(from_utf8);";
$modUniCode = !$@;
my $config = {};
my @appList = ( 'aMuleGui', 'wxCas', 'aLinkCreator');
# Los procesos hijo envían esta señal al padre cuando terminan y ésta
# debe ser atendida, si no se quedan zombies hasta que termine el padre.
$SIG{CHLD} = \&finalHijo;
# Si se recibe cualquier señal que pueda provocar la interrupción del
# normal funcionamiento, entonces nos encargamos de finalizar correctamente.
$SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{INT} = \&finalizar;
# Iniciando Gtk2
Gtk2->init;
# Comprobaciones iniciales. Cargar configuración.
if (!&inicializar){
logsys ("msg", &appRel ." ha abortado el arranque.");
unlink $apppid or die "No puedo eliminar el archivo de bloqueo";
exit -1;
}
logsys ("msg", &appRel ." iniciado");
# Formas Gtk2
my $menu = Gtk2::Menu->new();
my $menu_opciones = Gtk2::MenuItem->new("opciones");
my $menu_aLinkCreator = Gtk2::MenuItem->new("aLinkCreator");
my $menu_wxCas = Gtk2::MenuItem->new("wxCas");
my $menu_aMuleGui = Gtk2::MenuItem->new("aMuleGui");
my $menu_verLog = Gtk2::MenuItem->new("aMule log");
my $menuSalir = Gtk2::MenuItem->new("Salir");
my $pic;
eval {$pic = Gtk2::Gdk::Pixbuf->new_from_file ($config->{'iconPath'});};
if ($@){
my @aMulet_xpm = ('18 24 17 1', ' c None', '. c #312A28', '+ c #524842',
'@ c #D42238', '# c #835128', '$ c #985A20', '% c #6A6B6A',
'& c #AA7B50', '* c #EC5867', '= c #BF7B3F', '- c #C9792F',
'; c #898989', '> c #E39854', ', c #CB9D83', '" c #A9AAAA',
') c #CDCBC9', '! c #F4F5F3', ' ',
' $ ',
' !> ',
' #! )$$ ',
' ## #-$ ',
' )##$ -,# ',
' .+##)$,) ',
' ...$,!" ',
' ".$=-$" ',
' ;==-!= ',
' " >! " ',
' ; !& ; ',
' " !)))" ',
' """"""! ',
' %!.""""); ',
' ;))";;;"%;;) ',
' ">-)";;;;"->"" ',
' )-=$,;;%@,->$) ',
' ;%--#=>>**+%%; ',
' +....&=>>>>#!))! ',
'%"-=##$>>>>=&$--;;',
'+)-=##&=>>>=#=->)+',
'%;;=$+.+>>++$->,;%', ' " . ');
$pic = Gtk2::Gdk::Pixbuf->new_from_xpm_data (@aMulet_xpm);
logsys ("warning", "Error al cargar el icono: " . $config->{'iconPath'});
logsys ("msg", "Se procede a cargar el icono interno.");
}
my $img= Gtk2::Image->new_from_pixbuf($pic->scale_simple(18, 24, "tiles"));
my $tray= Gtk2::TrayIcon->new("trayicon");
my $paraEvent = Gtk2::EventBox->new;
my $trayTooltip = Gtk2::Tooltips->new;
my $SeparadorMenu1 = Gtk2::SeparatorMenuItem->new;
my $SeparadorMenu2 = Gtk2::SeparatorMenuItem->new;
my $SeparadorMenu3 = Gtk2::SeparatorMenuItem->new;
$menu->append($menu_verLog);
$menu->append($SeparadorMenu1);
$menu->append($menu_opciones);
$menu->append($SeparadorMenu2);
$menu->append($menu_aLinkCreator);
$menu->append($menu_wxCas);
$menu->append($menu_aMuleGui);
$menu->append($SeparadorMenu3);
$menu->append($menuSalir);
$paraEvent->add($img);
$tray->add($paraEvent);
&statusText;
# Tratamiento de señales
logsys ("debug", "Asignación de señales");
$tray->signal_connect ('button-press-event' => \&ClickOnIcon);
$menu_opciones->signal_connect('activate' => \&opcionesGui);
$menu_verLog->signal_connect('activate' => \&visorTexto);
$menu_aLinkCreator->signal_connect('activate' => sub {&extAppStatus('aLinkCreator')});
$menu_wxCas->signal_connect('activate' => sub {&extAppStatus('wxCas')});
$menu_aMuleGui->signal_connect('activate' => sub {&extAppStatus('aMuleGui')});
$menuSalir->signal_connect('activate' => \&finalizar);
Glib::Timeout->add($config->{'signOnTime'}*1000, \&statusText) if $config->{'signOn'};
# show sobre los witgets para que sean visibles
logsys ("debug", "Show sobre los witgets");
$menu->show_all;
$tray->show_all;
&popUpsAct;
# iniciando bucle de mensajes
logsys ("debug", "Inicio del bucle de mensajes");
Gtk2->main;
# Fin. Aquí termina el flujo.
#############
# Funciones #
#############
# statusText Establece el texto del toolTip
sub statusText{
my $tmpStr = &appRel ." - Click derecho para opciones";
if ($config->{'signOn'}){
&onlineInfo;
# my $tmpStr;
if ($config->{'ConectStatus'}){
if ($config->{'typeId'}eq"H"){$tmpStr = "[ID alta]"}
elsif ($config->{'typeId'}eq"L"){$tmpStr = "[ID baja]"}
else {$tmpStr = "[Conectando]"}
$tmpStr .= " Down:" . $config->{'downSpeed'};
$tmpStr .= " kb/s Up:" . $config->{'upSpeed'} ." Kb/s ";
if ($config->{'kadStatus'}==2) {$tmpStr .= "[kad ok]";
} elsif ($config->{'kadStatus'}==1) {$tmpStr .= "[kad firewalled]";
} else {$tmpStr .= "[kad off]"};
} else {$tmpStr = &appRel . " [aMuled No Conectado]"}
}
$trayTooltip->set_tip($tray, $tmpStr);
$tray->send_message($config->{'signOnTime'}*1000, "[AnimAlf dice] No entiendo");
}
# signatureOn Comprueba OnlineSignature en amule.conf
sub readSignatureConf {
$config->{'signOn'} = 0;
$config->{'signOnTime'} = 0;
if (-f $config->{'aMuleDir'} . "/amule.conf"){
if ( open( CONFIGFILE, $config->{'aMuleDir'} . "/amule.conf" ) ) {
while (<CONFIGFILE>) {
if ( $_ =~ /^OnlineSignature=(.+)/ ) { $config->{'signOn'} = $1 }
if ( $_ =~ /^OnlineSignatureUpdate=(.+)/ ) { $config->{'signOnTime'} = $1 }
}
close CONFIGFILE;
}
}
}
# onlineInfo Recoge la información de amulesig.dat
sub onlineInfo {
if ( open( SIGNFILE, $config->{'aMuleDir'} . "/amulesig.dat" ) ) {
my @signFile;
while (<SIGNFILE>) {
$_ =~ /(.+)\n$/; push (@signFile, $1)
}
close SIGNFILE;
$config->{'ConectStatus'} = $signFile[0];
$config->{'nameServ'} = $signFile[1];
$config->{'ipServ'} = $signFile[2];
$config->{'portServ'} = $signFile[3];
$config->{'typeId'} = $signFile[4];
$config->{'kadStatus'} = $signFile[5];
$config->{'downSpeed'} = $signFile[6];
$config->{'upSpeed'} = $signFile[7];
$config->{'colaCli'} = $signFile[8];
$config->{'filesShared'} = $signFile[9];
$config->{'nickName'} = $signFile[10];
$config->{'totalDown'} = $signFile[11];
$config->{'totalUp'} = $signFile[12];
$config->{'aMuleVer'} = $signFile[13];
$config->{'SessionDown'} = $signFile[14];
$config->{'SessionUp'} = $signFile[15];
$config->{'TimeRun'} = $signFile[16];
}
}
# finalHijo atender la señal de los hijos (cuando terminan la mandan)
sub finalHijo {
$SIG{CHLD} = \&finalHijo;
my $pid = wait;
return unless $config->{$pid}; # El system() realiza un fork() también.
logsys ("msg", "Acaba de finalizar: " . $config->{$pid} .
" [" . $config->{$config->{$pid} . 'Pid'} . "]");
undef $config->{$config->{$pid} . 'Pid'};
undef $config->{$pid};
}
# finalizar correctamente y eliminar bloqueo
sub finalizar {
$SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{INT} = \&finalizar;
logsys ("msg", "Finalizando ...");
#Finalizar el bucle de mensajes
Gtk2->main_quit;
#Comprobar que no quede ninguna aplicación hijo en funcionamiento
#y si existe eliminarlas antes de finalizar no vayan a quedar zombies.
logsys ("msg", "Finalizando posibles hijos");
# Ahora la señal de retorno del hijo la trataremos aquí.
$SIG{CHLD} = 'DEFAULT';
foreach my $app (@appList) {
if (defined $config->{$app . "Pid"}){
logsys ("msg", "[$app] está en marcha. Finalizándolo ...");
kill ('SIGTERM', $config->{$app . "Pid"});
waitpid($config->{$app . "Pid"}, 0);
}
}
logsys ("msg", "No quedan procesos hijo de " . &appRel . " en el sistema");
#TODO Si archivo de bloqueo es usado para log volcar a otro sitio.
logsys ("warning", "TODO: volcar archivo log a log final [si se le ordena]");
logsys ("msg", "Terminada la ejecución");
logsys ("msg", "bye ;-)\n\n".&appRel."\n");
# borrar archivo de bloqueo
unlink $apppid or die "No puedo eliminar el archivo de bloqueo $apppid";
}
# flushChars transforma utf8 a iso-8859-1
sub flushChars {
my ($tmpStr) = @_;
$tmpStr =~ s/([\200-\377]+)/from_utf8({ -string => $1, -charset => 'ISO-8859-1'})/eg
if $modUniCode;
return $tmpStr;
}
#logsys Mini sistema de logs.
sub logsys {
my ($mode, $text) = @_;
my $tmpStr;
if (open LOG, ">>$apppid") {
if (($logMode eq "debug" && ($mode eq "debug" or $mode eq "warning")) ||
($logMode eq "warning" && ($mode eq "warning" or $mode eq "msg")) ||
($logMode eq "msg" && $mode eq "msg")){
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime (time);
$year += 1900; $mon ++;
$tmpStr="[" . uc($mode) . "] " . sprintf("%02d",$mday) . "-" .
sprintf("%02d",$mon) . "-$year " . sprintf("%02d",$hour) . ":" .
sprintf("%02d",$min) . ":" . sprintf("%02d",$sec) . " $text\n";
print LOG $tmpStr; print $tmpStr if $verbose;
}
close LOG;
}
}
# ClickOnIcon se lanzará tras un click en el TrayIcon.
# Para diferenciar el botón del ratón que se pulsó.
sub ClickOnIcon {
logsys ("debug", "sub: ClickOnIcon start");
my ($widget, $event) = @_;
return 1 if $event->button == 2;
$menu->popup(undef, undef, undef, undef, $event->button,$event->time) if $event->button == 3;
&extAppStatus($config->{'appOnClick'}) if $event->button == 1;
}
# extAppStatus lanzará una instancia de la aplicación si no existe
sub extAppStatus {
logsys ("debug", "sub: extAppStatus start");
my ($refApp) = @_;
$config->{ $refApp . 'Pid'} = fork()
unless ($config->{ $refApp . 'Pid'}); # Crea un proceso hijo
die "error al hacer fork: $!" if !defined($config->{$refApp . 'Pid'});
if ( $config->{$refApp . 'Pid'} == 0) { # Si se trata del proceso hijo
logsys ("msg", "Iniciando proceso hijo con [$refApp]");
if ($config->{$refApp . 'Ok'}) {
$SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{INT} = 'DEFAULT';
logsys ("warning", "Redirección de STDOUT para $refApp a $apppid");
open STDOUT, ">>$apppid";
exec ($config->{$refApp . 'App'}) ||
die "ATENCIÓN: Falló la ejecución de $refApp";
} else {exit -1}
} else { # Circuito del proceso padre
logsys ("msg", "Circuito del proceso padre [hijo=>$refApp pid:"
. $config->{$refApp . 'Pid'} . "]");
# Asigno una clave en la configuración con el valor de la pid con el padre
$config->{$config->{$refApp . 'Pid'}} = $refApp
unless $config->{$config->{$refApp . 'Pid'}};
# a ejecutar por el proceso padre
# TODO: Enviar setFocus a la aplicación
#
}
}
# appRel nombre y versión del script
sub appRel {
$0=~/.*\/(.*)$/;
my $fileRun = $1;
$fileRun = $0 unless $fileRun;
$fileRun = "aMulet.pl [$1]" if $fileRun ne 'aMulet.pl';
return $fileRun . " v.1.2 beta";
}
# popUpsAct des/activar apartados del menú
sub popUpsAct {
$menu_aLinkCreator->set_sensitive($config->{'aLinkCreatorOk'});
$menu_wxCas->set_sensitive($config->{'wxCasOk'});
$menu_aMuleGui->set_sensitive($config->{'aMuleGuiOk'});
}
# pathsVerify comprobar la ruta de las aplicaciones
sub pathsVerify{
foreach my $app (@appList) {
$config->{$app . 'Ok'} = (-x $config->{$app . 'App'});
}
}
# inicializar comprobaciones iniciales
sub inicializar {
my $tmpStr;
my $runDaemon;
# Comprobar si ya estamos en marcha
if (-f $apppid){
my $appVerify=0;
# Comprobar si realmente la aplicación está en marcha.
if (open(APPPID, $apppid)){
my $line;
while ($line = <APPPID>) {
chop($line); last;
}
close(APPPID);
$appVerify=&isRunProcess($line);
}
if ($appVerify){
$tmpStr = "<b>" .appRel . "</b> ya está funcionando!\n\n";
$SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{INT} = 'DEFAULT';
&showMessage( 'error', flushChars($tmpStr), 'ok');
exit -1;
} else {unlink $apppid}
}
# Iniciar Bloqueo
logsys ("msg", "Iniciando archivo de bloqueo");
if (open LOG, ">$apppid"){print LOG "$$\n"}
# Cargar la configuración
logsys ("msg", "Cargando la configuración");
&loadConfig;
readSignatureConf;
# Comprobar el estado del aMule como servicio
if ($config->{'aMuledOn'}){
logsys ("msg", "Iniciando la verificación de la existencia de amuled");
if (open(PROCESOS,"ps -A |")){
while (<PROCESOS>){
$runDaemon = 1 if ($_ =~ /amuled/);
}
close PROCESOS;
}
if (!$runDaemon) { $runDaemon = 1;
logsys ("msg", "No se detecta. Iniciando amuled ...");
if (open(AMULED,"$binaMuled |")){
my $aMuleRun;
while (<AMULED>){
logsys ("msg", $_);
logsys ("msg", "ATENCIÓN: Cambie la orden [$binaMuled] bajo su responsabilidad") if $_ =~ /binary requires/;
undef $runDaemon if $_ =~ /binary requires/;
$aMuleRun = 1 if $_ =~ /Raising current running instance/;
}
close AMULED;
if ($aMuleRun){
logsys ("msg", "*"x56 );
logsys ("msg", "*"x5 ." Se ha detectado que el aMule está en marcha " ."*"x6 );
logsys ("msg", "*"x56 );
logsys ("msg", "aMulet.pl se diseñó pensando en las herramientas remotas" );
logsys ("msg", "*"x56 );
logsys ("msg", "* FUNCIONARÍA, pero no veo la necesidad de ello. STOP!!" );
logsys ("msg", "*"x56 );
undef $runDaemon;
};
logsys ("msg", "El amuled ha sido puesto en marcha.") if $runDaemon;
} else {
undef $runDaemon;
logsys ("msg", "No se ha podido ejecutar el amuled!");
logsys ("msg", "Se puede indicar en la configuración que se salte este paso");
$tmpStr = "<u><b>No se ha podido ejecutar aMuled</b></u>.\n\n";
$tmpStr .= "¿Desactivo la opción de arrancar el amuled en la configuración?\n\n";
$tmpStr .= "Desactive esta opción si el aMuled está residente en otra máquina de su red.";
$tmpStr .= "\n\nNo he detectado el aMuleGui." unless $config->{'aMuleGuiOk'};
$tmpStr .= "\nDeberá indicar donde está situado éste en la configuración" unless $config->{'aMuleGuiOk'};
my $confirmacion= &showMessage( 'question', flushChars($tmpStr), 'yes-no');
if ($confirmacion eq 'yes'){
$config->{'aMuledOn'}=0;
&saveConfig;
$runDaemon = 1;
};
}
} else {logsys ("msg", "El aMuled ha sido detectado :))");}
} else {
$runDaemon = 1;
logsys ("msg", "ATENCIÓN No se detectará ni arrancará el aMuled");
logsys ("msg", " Se puede modificar esto en la configuración");
}
# Comprobar que la aplicación que arranca tras el click en el icono existe.
# Esto no afectará al retorno de esta función.
if ($runDaemon){
logsys ("msg", "Verificando la aplicación que responde al click del icono.");
if (!$config->{$config->{'appOnClick'} . 'Ok'}){
$tmpStr = "Debe indicar en la configuración dónde residen el ejecutable\n";
$tmpStr .= "de la aplicación <b>$config->{'appOnClick'}</b> o escoger otra\n";
$tmpStr .= "aplicación que responda al click en el icono";
&showMessage( 'warning', flushChars($tmpStr), 'ok');
&opcionesGui;
}
} # TODO: Intentar mostrarlo como modal y esperar respuesta.
return $runDaemon;
}
# visorTexto Crea una ventana Gtk en la que muestra el logfile del aMule
sub visorTexto {
logsys ("debug", "sub: visorTexto start");
my ($widget, $event) = @_;
logsys ("debug", "Deshabilitando la llamada en el menú");
$widget->set_sensitive(0);
my $visorTextWin = Gtk2::Window->new("toplevel");
my $vbox = Gtk2::VBox->new;
my $scrolledwindow = Gtk2::ScrolledWindow->new;
my $textBuffer = Gtk2::TextBuffer->new;
my $ok = Gtk2::Button->new_from_stock("gtk-close");
my $textView = Gtk2::TextView->new_with_buffer($textBuffer);
my $LineaLog;
$visorTextWin->set_title('Visor de Texto');
$visorTextWin->set_position('center');
$visorTextWin->set_default_size(640, 300);
logsys ("debug", "Leyendo " . $config->{'aMuleDir'} . "/logfile");
open (LOGFILE, $config->{'aMuleDir'} . "/logfile") || logsys ("warning", $config->{'aMuleDir'} . "/logfile: $!");
while (<LOGFILE>) {$LineaLog .= $_;}
close LOGFILE;
$textView->set_editable(0);
$textView->set_cursor_visible(0);
$textBuffer->set_text($LineaLog);
$scrolledwindow->set_policy('automatic', 'automatic');
$scrolledwindow->add($textView);
$vbox->add($scrolledwindow );
$vbox->pack_end($ok, 0, 0, 3);
$visorTextWin->add($vbox);
$ok->signal_connect("clicked", sub { $visorTextWin->destroy; } );
$visorTextWin->signal_connect('destroy' => sub { $widget->set_sensitive(1); });
logsys ("msg", "Mostrando la ventana de logs");
$visorTextWin->show_all;
}
# isRunProcess comprobará si un proceso está en ejecución
sub isRunProcess {
my ($proceso) = @_;
my $runDaemon = 0;
if (open(PROCESOS,"ps -A |")){
while (<PROCESOS>){$runDaemon = 1 if $_ =~ /^$proceso\s/;}
close PROCESOS;
}
return $runDaemon;
}
sub infoOnLine {
my $tmpStr = '';
&onlineInfo if $config->{'signOn'};
if ($config->{'signOn'} && $config->{'ConectStatus'}==1){
$tmpStr = "\n\n<b>" . $config->{'nickName'} . "</b> con <b>aMule</b> [<i>";
$tmpStr .= $config->{'aMuleVer'} . "</i>]\n";
$tmpStr .= "está conectado al puerto <b>" . $config->{'portServ'};
$tmpStr .= "</b> de <b>" . $config->{'nameServ'} . "</b>\ncon <b>ID ";
$tmpStr .= $config->{'typeId'}eq"H"?"alta</b>":"baja</b>";
$tmpStr .= " y la <b>red kad ";
if ($config->{'kadStatus'}==2) {$tmpStr .= "bien conectada</b>\n";
} elsif ($config->{'kadStatus'}==1) {$tmpStr .= "en firewalled</b>\n";
} else {$tmpStr .= "desconectada</b>\n"};
$tmpStr .= "lleva ";
my $tmpStr2 = $config->{'TimeRun'} % 60 . " segundos";
my $tiempo = sprintf("%d",$config->{'TimeRun'} / 60);
$tmpStr2 = $tiempo % 60 . " minutos y $tmpStr2" if $tiempo;
$tiempo = sprintf("%d",$tiempo / 60) if $tiempo;
$tmpStr2 = $tiempo % 24 . " horas $tmpStr2" if $tiempo;
$tiempo = sprintf("%d",$tiempo / 24) if $tiempo;
$tmpStr2 = $tiempo . " dias $tmpStr2" if $tiempo;
$tmpStr .= $tmpStr2 . " conectado\n";
$tmpStr .= "y en este tiempo ha descargado: <b>";
$tmpStr .= sprintf("%.2f",$config->{'SessionDown'}/1048576) . " Mb</b>\n";
$tmpStr .= "con lo que tiene un total descagado de ";
$tmpStr .= sprintf("%.2f",$config->{'totalDown'}/1048576) . " Mb\n";
$tmpStr .= "Además comparte <b>" . $config->{'filesShared'} . "</b> archivos y en esta sesión\n";
$tmpStr .= "se han subido <b>" . sprintf("%.2f",$config->{'SessionUp'}/1048576);
$tmpStr .= " Mb</b> obteniendo un\ntotal de " . sprintf("%.2f",$config->{'totalUp'}/1048576);
$tmpStr .= " Mb subidos a la Red,\nen cola tiene ahora mismo ";
$tmpStr .= $config->{'colaCli'} . " clientes";
}
return flushChars($tmpStr);
}
# opcionesGui muestra la ventana de opciones
sub opcionesGui {
my ($widget, $event) = @_;
logsys ("debug", "Deshabilitando la llamada en el menú");
$widget->set_sensitive(0) if defined $widget;
my $guiOpciones = Gtk2::Window->new;
my $vboxPrincipal = Gtk2::VBox->new;
my $notebook = Gtk2::Notebook->new;
my $select_aMuleGui = Gtk2::RadioButton->new('appOnClick', 'aMuleGui');
my @grupo = $select_aMuleGui->get_group;
my $select_alc = Gtk2::RadioButton->new_with_label(@grupo, 'aLinkCreator');
my $select_wxcas = Gtk2::RadioButton->new_with_label(@grupo, 'wxCas');
my $check_aMuled_on = new Gtk2::CheckButton->new(flushChars('Arrancar aMule como servicio al principio (si no lo está)'));
my $vBoxTabRutas = Gtk2::VBox->new;
my $vBoxTabAbout = Gtk2::VBox->new;
my $hboxPrincipal = Gtk2::HBox->new;
my $hBoxTabRutas1 = Gtk2::HBox->new;
my $hBoxTabRutas2 = Gtk2::HBox->new;
my $hBoxTabRutas3 = Gtk2::HBox->new(1);
my $hseparator1 = Gtk2::HSeparator->new;
my $hseparator2 = Gtk2::HSeparator->new;
my $hseparator3 = Gtk2::HSeparator->new;
my $labelTabRutas = Gtk2::Label->new('General');
my $labelTabAbout = Gtk2::Label->new('About');
my $labelTabRut1 = Gtk2::Label->new('Relacionado con el Servicio amuled');
my $labelTabRut2 = Gtk2::Label->new('aMule Home Dir');
my $labelTabRut3 = Gtk2::Label->new('Ruta a las aplicaciones');
my $labelTabRut4 = Gtk2::Label->new('aMuleGui: ');
my $labelTabRut5 = Gtk2::Label->new('wxCas: ');
my $labelTabRut6 = Gtk2::Label->new('aLinkCreator: ');
my $labelTabRut7 = Gtk2::Label->new(flushChars('Icono que se mostrará en la barra'));
my $labelTabRut8 = Gtk2::Label->new('Icono:');
my $labelTabRut9 = Gtk2::Label->new(flushChars('¿Qué aplicación arrancará tras hacer click en el icono?'));
my $labelAbout1 = Gtk2::Label->new('aMulet.pl');
my $labelAbout2 = Gtk2::Label->new('by AnimAlf - AnimAlf@engendro.sytes.net');
my $labelAbout3 = Gtk2::Label->new('una idea de tx2z en http://forum.amule.org');
my $labelAbout4 = Gtk2::Label->new('Distribuido bajo la licencia GPL');
my $labelAbout5 = Gtk2::Label->new('http://www.gnu.org/copyleft/gpl.html');
my $labelAbout6 = Gtk2::Label->new;
my $edit_home_aMule = Gtk2::Entry->new;
my $edit_aMuleGui_path = Gtk2::Entry->new;
my $edit_wxcas_path = Gtk2::Entry->new;
my $edit_alc_path = Gtk2::Entry->new;
my $edit_icon_path = Gtk2::Entry->new;
my $btnOk = Gtk2::Button->new_from_stock("gtk-apply");
my $btnCancel = Gtk2::Button->new_from_stock("gtk-cancel");
my $btnRutas1 = Gtk2::Button->new('...');
my $btnRutas2 = Gtk2::Button->new('...');
my $btnRutas3 = Gtk2::Button->new('...');
my $btnRutas4 = Gtk2::Button->new('...');
my $btnRutas5 = Gtk2::Button->new('Selecciona');
my $tableTabRutas = Gtk2::Table->new(3, 3, 0 );
# Posicionando en la ventana principal
$guiOpciones->add($vboxPrincipal);
# Posicionando en el notebook (contenedor de pestañas)
$vboxPrincipal->add($notebook);
# primera pestaña
$notebook->append_page($vBoxTabRutas, $labelTabRutas);
$vBoxTabRutas->pack_start($labelTabRut1, 0, 0, 3);
$vBoxTabRutas->pack_start($hBoxTabRutas1, 0, 0, 3);
$hBoxTabRutas1->pack_start($labelTabRut2, 0, 0, 3);
$hBoxTabRutas1->add($edit_home_aMule);
$hBoxTabRutas1->pack_end($btnRutas1, 0, 0, 3);
$vBoxTabRutas->pack_start($check_aMuled_on, 0, 0, 3);
$vBoxTabRutas->pack_start($hseparator2, 0, 0, 3);
$vBoxTabRutas->pack_start($labelTabRut3, 0, 0, 3);
$vBoxTabRutas->pack_start($tableTabRutas, 0, 0, 3);
$tableTabRutas->attach($labelTabRut4, 0, 1, 0, 1, ['fill'], [], 0, 0 );
$tableTabRutas->attach($edit_aMuleGui_path, 1, 2, 0, 1, ['expand', 'fill'], [], 0, 0 );
$tableTabRutas->attach($btnRutas2, 2, 3, 0, 1, ['fill'], [], 0, 0 );
$tableTabRutas->attach($labelTabRut5, 0, 1, 1, 2, ['fill'], [], 0, 0 );
$tableTabRutas->attach($edit_wxcas_path, 1, 2, 1, 2, ['expand', 'fill'], [], 0, 0 );
$tableTabRutas->attach($btnRutas3, 2, 3, 1, 2, ['fill'], [], 0, 0 );
$tableTabRutas->attach($labelTabRut6, 0, 1, 2, 3, ['fill'], [], 0, 0 );
$tableTabRutas->attach($edit_alc_path, 1, 2, 2, 3, ['expand', 'fill'], [], 0, 0 );
$tableTabRutas->attach($btnRutas4, 2, 3, 2, 3, ['fill'], [], 0, 0 );
$vBoxTabRutas->pack_start($hseparator1, 0, 0, 3);
$vBoxTabRutas->pack_start($labelTabRut9, 0, 0, 3);
$vBoxTabRutas->pack_start($hBoxTabRutas3, 0, 0, 3);
$hBoxTabRutas3->pack_start($select_aMuleGui, 0, 0, 3);
$hBoxTabRutas3->pack_start($select_alc, 0, 0, 3);
$hBoxTabRutas3->pack_start($select_wxcas, 0, 0, 3);
$vBoxTabRutas->pack_end($hBoxTabRutas2, 0, 0, 3);
$hBoxTabRutas2->pack_start($labelTabRut8, 0, 0, 3);
$hBoxTabRutas2->add($edit_icon_path);
$hBoxTabRutas2->pack_end($btnRutas5, 0, 0, 3);
$vBoxTabRutas->pack_end($labelTabRut7, 0, 0, 3);
$vBoxTabRutas->pack_end($hseparator3, 0, 0, 3);
# Segunda pestaña
$notebook->append_page($vBoxTabAbout, $labelTabAbout);
$vBoxTabAbout->pack_start($labelAbout1, 0, 0, 3);
$vBoxTabAbout->pack_start($labelAbout2, 0, 0, 3);
$vBoxTabAbout->pack_start($labelAbout3, 0, 0, 3);
$vBoxTabAbout->pack_start($labelAbout4, 0, 0, 3);
$vBoxTabAbout->pack_start($labelAbout5, 0, 0, 3);
$vBoxTabAbout->pack_start($labelAbout6, 0, 0, 3);
# Posicionando en la parte inferior de la ventana principal
$vboxPrincipal->pack_end($hboxPrincipal, 0, 0, 3);
$hboxPrincipal->pack_start($btnOk, 0, 0, 3);
$hboxPrincipal->pack_end($btnCancel, 0, 0, 3);
$labelAbout1->set_markup('<span foreground="DarkRed" size="x-large"><b>' . appRel . ' </b></span>');
#TODO: Intentar conseguir una UrlLabel, fácil con gnome-open (pero y si no existe gnome?)
#http://forum.amule.org/thread.php?threadid=9751
$labelAbout3->set_markup('<span>Una idea de <b>tx2z</b> en http://forum.amule.org</span>');
#Añado un mini resumen de la información disponible en amulesig.dat
$labelAbout6->set_markup(infoOnLine);
if ($config->{'signOn'}){
Glib::Timeout->add($config->{'signOnTime'}*1000, sub {
$labelAbout6->set_markup(infoOnLine);
$tray->send_message($config->{'signOnTime'}*1000, "[AnimAlf dice] No entiendo");});
}
# Propiedades de la ventana principal
$guiOpciones->set_title('Opciones aMulet.pl');
$guiOpciones->set_position('center');
#TODO: Intentar que actuase como una ventana modal, como el showMessage
# y el punto de la llamada esperase la respuesta ok-cancel
logsys ("msg", "Mostrando la ventana de opciones");
logsys ("warning", "*"x36) unless $widget;
logsys ("warning", "TODO: Que sea modal tipo showMessage") unless $widget;
logsys ("warning", "*"x36) unless $widget;
# Propiedades del notebook
$notebook->set_tab_pos('top');
$notebook->set_show_tabs (1);
$notebook->set_show_border(1);
$notebook->set_scrollable (0);
$notebook->set_tab_hborder(2);
$notebook->set_tab_vborder(2);
# alineando de algunas etiquetas
$labelTabRut4->set_alignment(1,0.5);
$labelTabRut5->set_alignment(1,0.5);
$labelTabRut6->set_alignment(1,0.5);
# Asignando la configuración.
$edit_home_aMule->set_text($config->{'aMuleDir'});
$edit_aMuleGui_path->set_text($config->{'aMuleGuiApp'});
$edit_wxcas_path->set_text($config->{'wxCasApp'});
$edit_alc_path->set_text($config->{'aLinkCreatorApp'});
$edit_icon_path->set_text($config->{'iconPath'});
$check_aMuled_on->set_active($config->{'aMuledOn'});
$select_wxcas->set_active($config->{'appOnClick'} eq 'wxCas');
$select_alc->set_active($config->{'appOnClick'} eq 'aLinkCreator');
$select_aMuleGui->set_active($config->{'appOnClick'} eq 'aMuleGui');
$select_wxcas->set_sensitive($config->{'wxCasOk'});
$select_alc->set_sensitive($config->{'aLinkCreatorOk'});
$select_aMuleGui->set_sensitive($config->{'aMuleGuiOk'});
# Lo mostramos todo
$guiOpciones->show_all;
# La asignación de señales
$btnOk->signal_connect("clicked", sub {
my ($tmpStr, $tmpStr1);
$tmpStr1 = 'wxCas' if $select_wxcas->get_active;
$tmpStr1 = 'aLinkCreator' if $select_alc->get_active;
$tmpStr1 = 'aMuleGui' if $select_aMuleGui->get_active;
$tmpStr .= $edit_home_aMule->get_text . ": No es un directorio\n"
if !(-d $edit_home_aMule->get_text);
$tmpStr .= $edit_aMuleGui_path->get_text . ": <b>No es un ejecutable</b> (o no existe)\n"
if !(-x $edit_aMuleGui_path->get_text);
$tmpStr .= $edit_wxcas_path->get_text . ": <b>No es un ejecutable</b> (o no existe)\n"
if !(-x $edit_wxcas_path->get_text);
$tmpStr .= $edit_alc_path->get_text . ": <b>No es un ejecutable</b> (o no existe)\n"
if !(-x $edit_alc_path->get_text);
$tmpStr .= $edit_icon_path->get_text . ": <b>No parece que exista</b>\n"
if !(-e $edit_icon_path->get_text);
if (defined $tmpStr){
$tmpStr = "<b>Se ha detectado lo siguiente:</b>\n\n$tmpStr\n\n" . flushChars("¿Desea continuar de todos modos?");
my $confirmacion= &showMessage( 'question', $tmpStr, 'yes-no');
return if ($confirmacion eq 'no');
}
$config->{'appOnClick'} = 'wxCas' if $select_wxcas->get_active;
$config->{'appOnClick'} = 'aLinkCreator' if $select_alc->get_active;
$config->{'appOnClick'} = 'aMuleGui' if $select_aMuleGui->get_active;
$config->{'aMuleDir'} = $edit_home_aMule->get_text;
$config->{'aMuleGuiApp'} = $edit_aMuleGui_path->get_text;
$config->{'wxCasApp'} = $edit_wxcas_path->get_text;
$config->{'aLinkCreatorApp'} = $edit_alc_path->get_text;
&showMessage( 'info', flushChars("El icono cambiará cuando reinicie la aplicación."), 'ok')
if $config->{'iconPath'} ne $edit_icon_path->get_text;
$config->{'iconPath'} = $edit_icon_path->get_text;
$config->{'aMuledOn'} = $check_aMuled_on->get_active;
&saveConfig; pathsVerify; popUpsAct; readSignatureConf;
$guiOpciones->destroy;
}
);
$btnCancel->signal_connect("clicked", sub { $guiOpciones->destroy; } );
$guiOpciones->signal_connect('destroy' => sub {$widget->set_sensitive(1) if defined $widget;});
$btnRutas1->signal_connect('clicked' => sub { dialogOpen($edit_home_aMule,
'Seleccione el directorio home de aMule', 'select-folder'); });
$btnRutas2->signal_connect('clicked' => sub { dialogOpen($edit_aMuleGui_path,
flushChars('Seleccione la aplicación aMuleGui'), 'open'); });
$btnRutas3->signal_connect('clicked' => sub { dialogOpen($edit_wxcas_path,
flushChars('Seleccione la aplicación wxCas'), 'open'); });
$btnRutas4->signal_connect('clicked' => sub { dialogOpen($edit_alc_path,
flushChars('Seleccione la aplicación aLinCreator'), 'open'); });
$btnRutas5->signal_connect('clicked' => sub { dialogOpen($edit_icon_path,
flushChars('Seleccione el icono que utilizará aMulet'), 'open'); });
}
# loadConfig carga la configuración o la crea si no existe
sub loadConfig {
if ( open( CONFIGFILE, "$ENV{HOME}/.aMule/amulet.rc" ) ) {
while (<CONFIGFILE>) {
if ( $_ =~ /(\w+)\s=\s(.+)/ ) { $config->{$1} = $2 }
}
close CONFIGFILE;
} else {
# es la primera vez.
mkdir "$ENV{HOME}/.aMule" unless (-d "$ENV{HOME}/.aMule");
$config = { # Por defecto
'aMuleDir' => "$ENV{'HOME'}/.aMule",
'aMuleGuiApp' => 'amulegui',
'wxCasApp' => 'wxcas',
'aLinkCreatorApp' => 'alc',
'iconPath' => '/usr/share/pixmaps/amule.xpm',
'appOnClick' => 'aMuleGui',
'aMuledOn' => 1
};
foreach my $app (@appList) {
$config->{$app . 'App'} = which($config->{$app . 'App'});
}
pathsVerify;
&saveConfig;
}
pathsVerify;
}
# saveConfig guarda la configuración en un archivo
sub saveConfig {
my @keyList = ('aMuleDir', 'aMuleGuiApp', 'wxCasApp',
'aLinkCreatorApp', 'iconPath', 'appOnClick', 'aMuledOn');
if ( open( CONFIGFILE, '>', "$ENV{HOME}/.aMule/amulet.rc" ) ) {
foreach my $key (@keyList) {
print CONFIGFILE "$key = $config->{$key}\n" if $config->{$key} ne '';
}
close CONFIGFILE;
}else {logSys("warning", "No se puede escribir en el archivo de configuración!");}
};
# showMessage Muestra una ventana con un mensaje, y espera respuesta.
sub showMessage {
#$icon info warning error question
#$type none ok close cancel yes-no ok-cancel
my ($icon,$text,$type) = @_;
my $dialog = Gtk2::MessageDialog->new_with_markup (undef,
[qw/modal destroy-with-parent/], $icon, $type, sprintf "$text");
my $retval = $dialog->run;
$dialog->destroy;
return $retval;
}
# which Devuelve el path completo a la aplicación.
sub which {
my $appFile = shift;
foreach (split(':', $ENV{PATH})) {
my $tmpStr = "$_/$appFile";
if (-x $tmpStr) {
$appFile = $tmpStr;
last;
}
}
return $appFile;
}
# dialogOpen ventana de selección de archivos o directorios y escribe
# el resultado en en el entry que debe ser el primer parámetro.
sub dialogOpen {
# $widget debe ser un entry
# $type open save select-folder create-folder
my($widget,$caption,$type) =@_;
my $chooserDialog = Gtk2::FileChooserDialog->new ($caption, undef, $type,
'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok');
my $filename = $chooserDialog->get_filename if 'ok' eq $chooserDialog->run;
$widget->set_text ($filename) if defined $filename;
$chooserDialog->destroy;
return;
}