|
|
|
# Copyright (c) Stephan Martin <sm@sm-zone.net>
|
|
|
|
#
|
|
|
|
# $Id: GUI.pm,v 1.34 2006/07/25 20:10:54 sm Exp $
|
|
|
|
#
|
|
|
|
# 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, USA.
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
package GUI;
|
|
|
|
|
|
|
|
use POSIX;
|
|
|
|
|
|
|
|
use Gtk2::SimpleMenu;
|
|
|
|
|
|
|
|
my $false=undef;
|
|
|
|
my $true=1;
|
|
|
|
|
|
|
|
# This hash maps our internal MD names to the displayed digest names.
|
|
|
|
# Maybe it should live in a crypto-related file instead of a UI-related file?
|
|
|
|
my %md_algorithms = (
|
|
|
|
'sha256' => 'SHA-256',
|
|
|
|
'md5' => 'ins.MD5',
|
|
|
|
# n/a 'md2' => 'MD2',
|
|
|
|
# n/a 'mdc2' => 'MDC2',
|
|
|
|
'md4' => 'ins.MD4',
|
|
|
|
'ripemd160' => 'RIPEMD-160',
|
|
|
|
# 'sha' => 'SHA',
|
|
|
|
'sha1' => 'ins.SHA-1',
|
|
|
|
'sha384' => 'SHA-384',
|
|
|
|
'sha512' => 'SHA-512',
|
|
|
|
);
|
|
|
|
|
|
|
|
my %bit_lengths = (
|
|
|
|
'1024' => '1024',
|
|
|
|
'2048' => '2048',
|
|
|
|
'4096' => '4096'
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# create the main object
|
|
|
|
#
|
|
|
|
sub new {
|
|
|
|
my $that = shift;
|
|
|
|
my $class = ref($that) || $that;
|
|
|
|
|
|
|
|
my $self = {};
|
|
|
|
$self->{'init'} = shift;
|
|
|
|
|
|
|
|
bless($self, $class);
|
|
|
|
|
|
|
|
my ($section, $x, $y, $w, $h);
|
|
|
|
|
|
|
|
$self->{'version'} = '0.7.6';
|
|
|
|
|
|
|
|
$self->{'words'} = GUI::WORDS->new();
|
|
|
|
|
|
|
|
$self->{'exportdir'} = $self->{'init'}->{'exportdir'};
|
|
|
|
$self->{'basedir'} = $self->{'init'}->{'basedir'};
|
|
|
|
$self->{'tmpdir'} = $self->{'basedir'}."/tmp";
|
|
|
|
$self->{'init'}->{'tmpdir'} = $self->{'basedir'}."/tmp";
|
|
|
|
|
|
|
|
# initialize CA object
|
|
|
|
$self->{'CA'} = CA->new($self->{'init'});
|
|
|
|
|
|
|
|
# initialize OpenSSL object
|
|
|
|
$self->{'OpenSSL'} = OpenSSL->new($self->{'init'}->{'opensslbin'},
|
|
|
|
$self->{'tmpdir'});
|
|
|
|
|
|
|
|
# initialize CERT object
|
|
|
|
$self->{'CERT'} = CERT->new($self->{'OpenSSL'});
|
|
|
|
|
|
|
|
# initialize KEY object
|
|
|
|
$self->{'KEY'} = KEY->new();
|
|
|
|
|
|
|
|
# initialize REQ object
|
|
|
|
$self->{'REQ'} = REQ->new($self->{'OpenSSL'});
|
|
|
|
|
|
|
|
# initialize CONFIG object
|
|
|
|
$self->{'TCONFIG'} = TCONFIG->new();
|
|
|
|
|
|
|
|
# initialize fonts and styles
|
|
|
|
$self->{'fontfix'} = Gtk2::Pango::FontDescription->from_string(
|
|
|
|
"Courier 10"
|
|
|
|
);
|
|
|
|
|
|
|
|
# Gtk::Rc->parse_string(
|
|
|
|
#'style "default"
|
|
|
|
#{
|
|
|
|
# fontset = "-*-helvetica-medium-r-normal--11-*,-*-fixed-medium-r-normal--11-*"
|
|
|
|
#}
|
|
|
|
#widget_class "*" style "default"');
|
|
|
|
|
|
|
|
# $self->{'stylered'} = Gtk2::Style->new();
|
|
|
|
# $self->{'stylered'}->fg('normal', Gtk2::Gdk::Color->parse('red'));
|
|
|
|
|
|
|
|
# $self->{'stylegreen'} = Gtk2::Style->new();
|
|
|
|
# $self->{'stylegreen'}->fg('normal', Gtk2::Gdk::Color->parse('green'));
|
|
|
|
|
|
|
|
# initialize main window
|
|
|
|
$self->{'mw'} = Gtk2::Window->new("toplevel");
|
|
|
|
$self->{'mw'}->set_title("TinyCA2 Management $self->{'version'}");
|
|
|
|
$self->{'mw'}->set_icon_from_file("./icons/tinyca.png");
|
|
|
|
|
|
|
|
$self->{'mw'}->set_resizable(1);
|
|
|
|
$section = $self->{'init'}->{'cfg'}->{window};
|
|
|
|
if(defined($section->{x}) && defined($section->{y})) {
|
|
|
|
# save position for later use after show_all()
|
|
|
|
$self->{'posx'} = $section->{x};
|
|
|
|
$self->{'posy'} = $section->{y};
|
|
|
|
}
|
|
|
|
$w = $section->{w} // 850;
|
|
|
|
$h = $section->{h} // 600;
|
|
|
|
main::printd("Sizing window to $w,$h");
|
|
|
|
$self->{'mw'}->set_default_size($w, $h);
|
|
|
|
$self->{'mw'}->signal_connect( 'delete_event',
|
|
|
|
sub { HELPERS::exit_clean(0) });
|
|
|
|
|
|
|
|
$self->{'busycursor'} = Gtk2::Gdk::Cursor->new('watch');
|
|
|
|
$self->{'cursor'} = Gtk2::Gdk::Cursor->new('left-ptr');
|
|
|
|
$self->{'rootwin'} = Gtk2::Gdk->get_default_root_window();
|
|
|
|
|
|
|
|
# split window horizontal to add menu, toolbar and notebook
|
|
|
|
$self->{'mvb'} = Gtk2::VBox->new();
|
|
|
|
$self->{'mw'}->add($self->{'mvb'});
|
|
|
|
|
|
|
|
$self->create_menu();
|
|
|
|
$self->{'mvb'}->pack_start($self->{'menu'}->{'widget'} , 0, 0, 0);
|
|
|
|
|
|
|
|
$self->create_toolbar('startup');
|
|
|
|
$self->{'mvb'}->pack_start($self->{'toolbar'}, 0, 0, 0);
|
|
|
|
|
|
|
|
$self->create_nb();
|
|
|
|
$self->{'mvb'}->pack_start($self->{'nb'}, 1, 1, 0);
|
|
|
|
|
|
|
|
$self->create_bar();
|
|
|
|
$self->{'mvb'}->pack_start($self->{'barbox'}, 0, 0, 0);
|
|
|
|
|
|
|
|
$self->{'rootwin'}->set_cursor($self->{'cursor'});
|
|
|
|
|
|
|
|
$self;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# create/update the main frame with the notebooks
|
|
|
|
#
|
|
|
|
sub create_mframe {
|
|
|
|
my ($self, $force) = @_;
|
|
|
|
|
|
|
|
my($parsed, $calabel, $caframe, $rows, $table, @fields, $text, @childs,
|
|
|
|
$label, $cert_export, $cert_revoke, $cert_delete, $certlabel,
|
|
|
|
$certlistwin, @certtitles, @keytitles, $keylabel, $keylistwin,
|
|
|
|
$reqlistwin, @reqtitles, $reqlabel, $ind, $column, $ca, $cadir);
|
|
|
|
|
|
|
|
if ((defined($self->{'CA'}->{'actca'})) &&
|
|
|
|
($self->{'CA'}->{'actca'} ne "")) {
|
|
|
|
$ca = $self->{'CA'}->{'actca'};
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$cadir = $self->{'CA'}->{'cadir'};
|
|
|
|
|
|
|
|
$parsed = $self->{'CERT'}->parse_cert( $self, 'CA');
|
|
|
|
|
|
|
|
defined($parsed) ||
|
|
|
|
GUI::HELPERS::print_error( _("Can't read CA certificate"));
|
|
|
|
|
|
|
|
### notebooktab for ca information
|
|
|
|
if(not defined($self->{'cabox'})) {
|
|
|
|
$self->{'cabox'} = Gtk2::VBox->new(0, 0);
|
|
|
|
$calabel = GUI::HELPERS::create_label(_("CA"), 'left', 1, 0);
|
|
|
|
$self->{'nb'}->insert_page($self->{'cabox'}, $calabel, 0);
|
|
|
|
} else {
|
|
|
|
$self->{'nb'}->hide();
|
|
|
|
$self->{'nb'}->remove_page(0);
|
|
|
|
$self->{'cabox'}->destroy();
|
|
|
|
$self->{'cabox'} = Gtk2::VBox->new(0, 0);
|
|
|
|
$calabel = GUI::HELPERS::create_label(_("CA"), 'left', 1, 0);
|
|
|
|
$self->{'nb'}->insert_page($self->{'cabox'}, $calabel, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
# frame for CA informations
|
|
|
|
$self->{'cainfobox'} = GUI::X509_infobox->new();
|
|
|
|
$self->{'cainfobox'}->display($self->{'cabox'}, $parsed, 'cacert',
|
|
|
|
_("CA Information"));
|
|
|
|
|
|
|
|
### notebooktab for certificates
|
|
|
|
|
|
|
|
# delete old instance, force reinitialisation
|
|
|
|
if (defined($self->{'certbox'}) && $force) {
|
|
|
|
$self->{'certbox'}->destroy();
|
|
|
|
delete($self->{'certbox'});
|
|
|
|
$self->{'certbox'} = undef;
|
|
|
|
delete($self->{'certbrowser'}->{'OpenSSL'});
|
|
|
|
$self->{'certbrowser'}->{'OpenSSL'} = undef;
|
|
|
|
delete($self->{'certbrowser'});
|
|
|
|
$self->{'certbrowser'} = undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(not defined($self->{'certbox'})) {
|
|
|
|
$self->{'certbox'} = Gtk2::VBox->new(0, 0);
|
|
|
|
|
|
|
|
$certlabel = GUI::HELPERS::create_label(
|
|
|
|
_("Certificates"), 'left', 1, 0);
|
|
|
|
$self->{'nb'}->insert_page($self->{'certbox'}, $certlabel, 1);
|
|
|
|
|
|
|
|
if (not defined ($self->{'certbrowser'})) {
|
|
|
|
$self->{'certbrowser'}=GUI::X509_browser->new($self, 'cert');
|
|
|
|
$self->{'certbrowser'}->set_window($self->{'certbox'});
|
|
|
|
$self->{'certbrowser'}->add_list($ca,
|
|
|
|
$cadir."/certs",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
|
|
|
|
$self->{'certbrowser'}->add_info();
|
|
|
|
|
|
|
|
# create popup menu
|
|
|
|
if(not defined($self->{'certmenu'})) {
|
|
|
|
_create_cert_menu($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->{'certbrowser'}->{'x509clist'}->signal_connect(
|
|
|
|
'button_release_event',
|
|
|
|
sub { _show_popup_menu($self, 'cert', @_) });
|
|
|
|
$self->{'certbrowser'}->{'x509clist'}->signal_connect(
|
|
|
|
'button_press_event',
|
|
|
|
sub { _show_details_wrapper($self, 'cert', @_)});
|
|
|
|
|
|
|
|
# $self->{'certbrowser'}->destroy();
|
|
|
|
} else {
|
|
|
|
$self->{'certbrowser'}->update($cadir."/certs",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$self->{'certbrowser'}->update($cadir."/certs",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
### notebooktab for keys (split info and buttons)
|
|
|
|
@keytitles = (_("Common Name"),
|
|
|
|
_("eMail Address"),
|
|
|
|
_("Organizational Unit"),
|
|
|
|
_("Organization"),
|
|
|
|
_("Location"),
|
|
|
|
_("State"),
|
|
|
|
_("Country"),
|
|
|
|
_("Type"));
|
|
|
|
# delete old instance, force reinitialisation
|
|
|
|
if (defined($self->{'keybox'}) && $force) {
|
|
|
|
$self->{'keybox'}->destroy();
|
|
|
|
delete($self->{'keybox'});
|
|
|
|
$self->{'keybox'} = undef;
|
|
|
|
delete($self->{'keybrowser'}->{'OpenSSL'});
|
|
|
|
$self->{'keybrowser'}->{'OpenSSL'} = undef;
|
|
|
|
delete($self->{'keybrowser'});
|
|
|
|
$self->{'keybrowser'} = undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(not defined($self->{'keybox'})) {
|
|
|
|
$self->{'keybox'} = Gtk2::VBox->new(0, 0);
|
|
|
|
$keylabel = GUI::HELPERS::create_label( _("Keys"), 'left', 1, 0);
|
|
|
|
$self->{'nb'}->insert_page($self->{'keybox'}, $keylabel, 2);
|
|
|
|
|
|
|
|
if (not defined ($self->{'keybrowser'})) {
|
|
|
|
$self->{'keybrowser'}=GUI::X509_browser->new($self, 'key');
|
|
|
|
$self->{'keybrowser'}->set_window($self->{'keybox'});
|
|
|
|
$self->{'keybrowser'}->add_list($ca,
|
|
|
|
$cadir."/keys",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
|
|
|
|
# create popup menu
|
|
|
|
if(not defined($self->{'keymenu'})) {
|
|
|
|
_create_key_menu($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->{'keybrowser'}->{'x509clist'}->signal_connect(
|
|
|
|
'button_release_event',
|
|
|
|
sub { _show_popup_menu($self, 'key', @_) });
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$self->{'keybrowser'}->update($cadir."/keys",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# delete old instance, force reinitialisation
|
|
|
|
if (defined($self->{'reqbox'}) && $force) {
|
|
|
|
$self->{'reqbox'}->destroy();
|
|
|
|
delete($self->{'reqbox'});
|
|
|
|
$self->{'reqbox'} = undef;
|
|
|
|
delete($self->{'reqbrowser'}->{'OpenSSL'});
|
|
|
|
$self->{'reqbrowser'}->{'OpenSSL'} = undef;
|
|
|
|
delete($self->{'reqbrowser'});
|
|
|
|
$self->{'reqbrowser'} = undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
### notebooktab for requests (split info and buttons)
|
|
|
|
if(not defined($self->{'reqbox'})) {
|
|
|
|
$self->{'reqbox'} = Gtk2::VBox->new(0, 0);
|
|
|
|
$reqlabel = GUI::HELPERS::create_label(
|
|
|
|
_("Requests"), 'left', 1, 0);
|
|
|
|
$self->{'nb'}->insert_page($self->{'reqbox'}, $reqlabel, 3);
|
|
|
|
|
|
|
|
if (not defined ($self->{'reqbrowser'})) {
|
|
|
|
$self->{'reqbrowser'}=GUI::X509_browser->new($self, 'req');
|
|
|
|
$self->{'reqbrowser'}->set_window($self->{'reqbox'});
|
|
|
|
$self->{'reqbrowser'}->add_list($ca,
|
|
|
|
$cadir."/req",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
|
|
|
|
$self->{'reqbrowser'}->add_info();
|
|
|
|
|
|
|
|
# create popup menu
|
|
|
|
if(not defined($self->{'reqmenu'})) {
|
|
|
|
_create_req_menu($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->{'reqbrowser'}->{'x509clist'}->signal_connect(
|
|
|
|
'button_release_event',
|
|
|
|
sub { _show_popup_menu($self, 'req', @_) });
|
|
|
|
|
|
|
|
$self->{'reqbrowser'}->{'x509clist'}->signal_connect(
|
|
|
|
'button_press_event',
|
|
|
|
sub { _show_details_wrapper($self, 'req', @_)});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$self->{'reqbrowser'}->update($cadir."/req",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$self->{'reqbrowser'}->update($cadir."/req",
|
|
|
|
$cadir."/crl/crl.pem",
|
|
|
|
$cadir."/index.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->{'nb'}->show_all();
|
|
|
|
$self->{'nb'}->signal_connect_after('switch-page' =>
|
|
|
|
sub { _act_toolbar($self->{'nb'}, $self) });
|
|
|
|
|
|
|
|
$self->{'nb'}->set_current_page(1);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# create empty notebook, add to main window and configure
|
|
|
|
#
|
|
|
|
sub create_nb {
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
$self->{'nb'} = Gtk2::Notebook->new();
|
|
|
|
$self->{'nb'}->set_tab_pos('top');
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# create the applicationbar
|
|
|
|
#
|
|
|
|
sub create_bar {
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
$self->{'barbox'} = Gtk2::HBox->new();
|
|
|
|
$self->{'bar'} = Gtk2::Statusbar->new();
|
|
|
|
|
|
|
|
$self->{'progress'} = Gtk2::ProgressBar->new();
|
|
|
|
|
|
|
|
$self->{'barbox'}->pack_start($self->{'bar'}, 1, 1, 0);
|
|
|
|
|
|
|
|
GUI::HELPERS::set_status($self, _(" Watch out..."));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# keep toolbar in sync with notebook
|
|
|
|
#
|
|
|
|
sub _act_toolbar {
|
|
|
|
my ($nb, $self) = @_;
|
|
|
|
|
|
|
|
my $page_num = $nb->get_current_page();
|
|
|
|
|
|
|
|
my $mode = 'startup';
|
|
|
|
my $t;
|
|
|
|
|
|
|
|
if(defined($self->{'CA'}->{'actca'})) {
|
|
|
|
if ($page_num == 0) {
|
|
|
|
$mode = 'ca';
|
|
|
|
$t = _(" Actual CA: %s");
|
|
|
|
} elsif ($page_num == 1) {
|
|
|
|
$mode = 'cert';
|
|
|
|
$t = _(" Actual CA: %s - Certificates");
|
|
|
|
} elsif ($page_num == 2) {
|
|
|
|
$mode = 'key';
|
|
|
|
$t = _(" Actual CA: %s - Keys");
|
|
|
|
} elsif ($page_num == 3) {
|
|
|
|
$mode = 'req';
|
|
|
|
$t = _(" Actual CA: %s - Requests");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(defined($self->{'CA'}->{'actca'})) {
|
|
|
|
$t = sprintf($t, $self->{'CA'}->{'actca'});
|
|
|
|
GUI::HELPERS::set_status($self, $t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->create_toolbar($mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# create the toolbar
|
|
|
|
#
|
|
|
|
sub create_toolbar {
|
|
|
|
my ($self, $mode) = @_;
|
|
|
|
|
|
|
|
my ($icon, $mask, $iconw, $button, @children, $c, $ca);
|
|
|
|
|
|
|
|
$ca = $self->{'CA'}->{'actca'};
|
|
|
|
|
|
|
|
if(not defined($self->{'separator'})) {
|
|
|
|
$self->{'separator'} = Gtk2::SeparatorToolItem->new();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(defined($self->{'toolbar'})) {
|
|
|
|
@children = $self->{'toolbar'}->get_children();
|
|
|
|
|
|
|
|
for(my $i = 6; $i < @children; $i++) {
|
|
|
|
$c = $children[$i];
|
|
|
|
$c->destroy();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$self->{'toolbar'} = Gtk2::Toolbar->new();
|
|
|
|
$self->{'tooltips'} = Gtk2::Tooltips->new();
|
|
|
|
$self->{'toolbar'}->set_orientation('horizontal');
|
|
|
|
$self->{'toolbar'}->set_icon_size('small-toolbar');
|
|
|
|
|
|
|
|
## Buttons for all toolbars
|
|
|
|
$self->{'toolbar'} = Gtk2::Toolbar->new();
|
|
|
|
$self->{'toolbar'}->set_orientation('horizontal');
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-quit');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->signal_connect('clicked', sub { Gtk2->main_quit() });
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Exit TinyCA"), "");
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-open');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Open CA"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Open other CA"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->get_open_name($self)});
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-new');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("New CA"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Create new CA"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->get_ca_create($self)});
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-convert');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Import CA"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Import CA"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->get_ca_import($self)});
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-delete');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Delete CA"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Delete CA"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->get_ca_delete($self)});
|
|
|
|
|
|
|
|
$self->{'toolbar'}->insert($self->{'separator'}, -1); }
|
|
|
|
|
|
|
|
|
|
|
|
if($mode eq 'ca') {
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-find');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Details"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Show certificate details"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->show_details('CA') });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-find-and-replace');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("History"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Show history"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->show_history() });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-new');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Sub CA"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Create new sub CA"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->get_ca_create($self, undef, undef, "sub")});
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-save');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Export CA"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Export CA certificate"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->export_ca_cert($self)});
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-save');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Export CRL"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Export certificate revocation list"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->export_crl($self)});
|
|
|
|
|
|
|
|
if(-s $self->{'CA'}->{$ca}->{'dir'}."/cachain.pem") {
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-save');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Export Chain"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Export Chain"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CA'}->export_ca_chain($self)});
|
|
|
|
}
|
|
|
|
|
|
|
|
} elsif($mode eq 'cert') {
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-find');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Details"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Show certificate details"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->show_details('cert') });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-find');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("View"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("View certificate raw data"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->show_text('cert') });
|
|
|
|
|
|
|
|
if(not(defined($self->{'newcertmenu'}))) {
|
|
|
|
_create_create_cert_menu($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-new');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("New"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Create new certificate request"), "");
|
|
|
|
$button->signal_connect('clicked' =>
|
|
|
|
sub { $self->{'newcertmenu'}->popup(
|
|
|
|
undef, undef, undef, undef, 1, 0) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-save');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Export"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Export certificate"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CERT'}->get_export_cert($self) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-stop');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Revoke"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Revoke certificate"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CERT'}->get_revoke_cert($self) });
|
|
|
|
|
|
|
|
if(not defined($self->{'renewcertmenu'})) {
|
|
|
|
_create_renew_cert_menu($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-refresh');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Renew"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Renew certificate"), "");
|
|
|
|
$button->signal_connect('clicked' =>
|
|
|
|
sub { $self->{'renewcertmenu'}->popup(
|
|
|
|
undef, undef, undef, undef, 1, 0) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-delete');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Delete"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Delete certificate"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'CERT'}->get_del_cert($self) });
|
|
|
|
|
|
|
|
} elsif($mode eq 'key') {
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-revert-to-saved');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Import"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Import key"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'KEY'}->get_import_key($self) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-save');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Export"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Export key"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'KEY'}->get_export_key($self) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-delete');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Delete"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Delete key"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'KEY'}->get_del_key($self) });
|
|
|
|
|
|
|
|
} elsif($mode eq 'req') {
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-find');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Details"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Show request details"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->show_details('req') });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-find');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("View"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("View request raw data"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->show_text('req') });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-new');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("New"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("New request"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'REQ'}->get_req_create($self) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-revert-to-saved');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Import"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Import request"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'REQ'}->get_import_req($self) });
|
|
|
|
|
|
|
|
if(not(defined($self->{'reqsignmenu'}))) {
|
|
|
|
_create_sign_req_menu($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-properties');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Sign"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Sign request"), "");
|
|
|
|
$button->signal_connect('clicked' =>
|
|
|
|
sub { $self->{'reqsignmenu'}->popup(
|
|
|
|
undef, undef, undef, undef, 1, 0) });
|
|
|
|
|
|
|
|
$button = Gtk2::ToolButton->new_from_stock('gtk-delete');
|
|
|
|
$self->{'toolbar'}->insert($button, -1);
|
|
|
|
$button->set_label(_("Delete"));
|
|
|
|
$button->set_tooltip($self->{'tooltips'}, _("Delete request"), "");
|
|
|
|
$button->signal_connect('clicked', sub {
|
|
|
|
$self->{'REQ'}->get_del_req($self) });
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->{'toolbar'}->set_icon_size('small-toolbar');
|
|
|
|
|
|
|
|
$self->{'toolbar'}->show_all();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# create the menubar
|
|
|
|
#
|
|
|
|
sub create_menu {
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $menu_tree = [
|
|
|
|
_("_CA") => {
|
|
|
|
item_type => '<Branch>',
|
|
|
|
children => [
|
|
|
|
_("_Open CA") => {
|
|
|
|
callback => sub { $self->{'CA'}->get_open_name($self) },
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-open'
|
|
|
|
},
|
|
|
|
_("_New CA") => {
|
|
|
|
callback => sub { $self->{'CA'}->get_ca_create($self)},
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-new'
|
|
|
|
},
|
|
|
|
_("_Delete CA") => {
|
|
|
|
callback => sub { $self->{'CA'}->get_ca_delete($self)},
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-delete'
|
|
|
|
},
|
|
|
|
Separator => {
|
|
|
|
item_type => '<Separator>',
|
|
|
|
},
|
|
|
|
_("_Exit") => {
|
|
|
|
callback => sub { Gtk2->main_quit() },
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-close'
|
|
|
|
}
|
|
|
|
],
|
|
|
|
},
|
|
|
|
_("_Preferences") => {
|
|
|
|
item_type => '<Branch>',
|
|
|
|
children => [
|
|
|
|
_("View") => {
|
|
|
|
callback => sub { $self->show_cfg_dialog($self) },
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-info'
|
|
|
|
},
|
|
|
|
Separator => {
|
|
|
|
item_type => '<Separator>',
|
|
|
|
},
|
|
|
|
_("OpenSSL _Configuration") => {
|
|
|
|
callback => sub{ $self->{'TCONFIG'}->config_openssl($self) },
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-preferences'
|
|
|
|
}
|
|
|
|
],
|
|
|
|
},
|
|
|
|
_("_Help") => {
|
|
|
|
item_type => '<Branch>',
|
|
|
|
children => [
|
|
|
|
_("_Help") => {
|
|
|
|
callback => sub{ $self->show_help() },
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-help'
|
|
|
|
},
|
|
|
|
_("_About TinyCA") => {
|
|
|
|
callback => sub { $self->about($self) },
|
|
|
|
item_type => '<StockItem>',
|
|
|
|
extra_data => 'gtk-about'
|
|
|
|
}
|
|
|
|
],
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
$self->{'menu'} = Gtk2::SimpleMenu->new(menu_tree => $menu_tree);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# pop-up to display request/cert as TXT
|
|
|
|
#
|
|
|
|
sub show_text {
|
|
|
|
my ($self, $mode) = @_;
|
|
|
|
|
|
|
|
my($parsed, $t, $box, $label, $text, $vscrollbar, $name, $button_ok,
|
|
|
|
$status, $scrolled, $ca, $buffer);
|
|
|
|
|
|
|
|
$ca = $self->{'CA'}->{'actca'};
|
|
|
|
|
|
|
|
if($mode eq 'req') {
|
|
|
|
$name = $self->{'reqbrowser'}->selection_dn();
|
|
|
|
} elsif($mode eq 'cert') {
|
|
|
|
$name = $self->{'certbrowser'}->selection_dn();
|
|
|
|
} else {
|
|
|
|
GUI::HELPERS::print_error(
|
|
|
|
_("Invalid mode for show_text():")." ".$mode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((not defined $name) && ($mode eq 'req')) {
|
|
|
|
GUI::HELPERS::print_info(_("Please select a Request first"));
|
|
|
|
return;
|
|
|
|
}elsif((not defined $name) && ($mode eq 'cert')) {
|
|
|
|
GUI::HELPERS::print_info(_("Please select a certificate first"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if($mode eq 'cert') {
|
|
|
|
$status = $self->{'certbrowser'}->selection_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
$name = HELPERS::enc_base64($name);
|
|
|
|
|
|
|
|
if($mode eq 'req') {
|
|
|
|
$parsed = $self->{'REQ'}->parse_req( $self, $name);
|
|
|
|
} elsif($mode eq 'cert') {
|
|
|
|
$parsed = $self->{'CERT'}->parse_cert( $self, $name);
|
|
|
|
}
|
|
|
|
|
|
|
|
defined($parsed) || GUI::HELPERS::print_error(_("Can't read file"));
|
|
|
|
|
|
|
|
$t = $mode eq 'req'?_("Request"):_("Certificate");
|
|
|
|
|
|
|
|
$button_ok = Gtk2::Button->new_from_stock('gtk-ok');
|
|
|
|
$button_ok->signal_connect('clicked', sub { $box->destroy() });
|
|
|
|
$button_ok->can_default(1);
|
|
|
|
|
|
|
|
$box = GUI::HELPERS::dialog_box($t, $t, $button_ok);
|
|
|
|
|
|
|
|
$box->set_default_size(550, 440);
|
|
|
|
$button_ok->grab_default();
|
|
|
|
|
|
|
|
$scrolled = Gtk2::ScrolledWindow->new(undef, undef);
|
|
|
|
$scrolled->set_policy('automatic', 'automatic');
|
|
|
|
$scrolled->set_shadow_type('etched-in');
|
|
|
|
$box->vbox->pack_start($scrolled, 1, 1, 0);
|
|
|
|
|
|
|
|
$buffer = Gtk2::TextBuffer->new();
|
|
|
|
$buffer->set_text($parsed->{'TEXT'});
|
|
|
|
|
|
|
|
$text = Gtk2::TextView->new_with_buffer($buffer);
|
|
|
|
$text->set_editable(0);
|
|
|
|
$text->set_wrap_mode('none');
|
|
|
|
|
|
|
|
$text->modify_font($self->{'fontfix'});
|
|
|
|
|
|
|
|
$scrolled->add($text);
|
|
|
|
|
|
|
|
$box->show_all();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# completeley sick, but needed for doubleclick
|
|
|
|
#
|
|
|
|
sub _show_details_wrapper {
|
|
|
|
my ($self, $mode, $list, $event) = @_;
|
|
|
|
|
|
|
|
return(0) if($event->type() ne '2button-press');
|
|
|
|
|
|
|
|
show_details($self, $mode);
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# called on rightclick in [key|cert|reqlist]
|
|
|
|
#
|
|
|
|
sub _show_popup_menu {
|
|
|
|
my ($self, $mode, $list, $event) = @_;
|
|
|
|
|
|
|
|
my $t;
|
|
|
|
|
|
|
|
if ($event->button() == 3) {
|
|
|
|
if($mode eq 'cert') {
|
|
|
|
$self->{'certmenu'}->popup(undef, undef, undef, undef, 3, 0);
|
|
|
|
} elsif ($mode eq 'req') {
|
|
|
|
$self->{'reqmenu'}->popup(undef, undef, undef, undef, 3, 0);
|
|
|
|
} elsif ($mode eq 'key') {
|
|
|
|
$self->{'keymenu'}->popup(undef, undef, undef, undef, 3, 0);
|
|
|
|
} else {
|
|
|
|
$t = sprintf(
|
|
|
|
_("Invalid mode for _show_popup_menu(): %s"), $mode);
|
|
|
|
GUI::HELPERS::print_error($t);
|
|
|
|
}
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# show request/certificate informations and extensions
|
|
|
|
#
|
|
|
|
sub show_details {
|
|
|
|
my ($self, $mode) = @_;
|
|
|
|
|
|
|
|
my($name, $status, $parsed, $row, $ind, $label, $table, $tree, $box,
|
|
|
|
$button_ok, $t, @fields, $ca);
|
|
|
|
|
|
|
|
$ca = $self->{'CA'}->{'actca'};
|
|
|
|
|
|
|
|
if($mode eq 'req') {
|
|
|
|
$name = $self->{'reqbrowser'}->selection_dn();
|
|
|
|
} elsif($mode eq 'cert') {
|
|
|
|
$name = $self->{'certbrowser'}->selection_dn();
|
|
|
|
} elsif($mode eq 'CA') {
|
|
|
|
$name = 'CA';
|
|
|
|
} else {
|
|
|
|
GUI::HELPERS::print_error(
|
|
|
|
_("Invalid mode for show_details():")." ".$mode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((not defined $name) && ($mode eq 'req')) {
|
|
|
|
GUI::HELPERS::print_info(_("Please select a Request first"));
|
|
|
|
return;
|
|
|
|
}elsif((not defined $name) && ($mode eq 'cert')) {
|
|
|
|
GUI::HELPERS::print_info(_("Please select a Certificate first"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if($mode eq 'cert') {
|
|
|
|
$status = $self->{'certbrowser'}->selection_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
$name = HELPERS::enc_base64($name) if($name ne 'CA');
|
|
|
|
|
|
|
|
if($mode eq 'req') {
|
|
|
|
$parsed = $self->{'REQ'}->parse_req( $self, $name);
|
|
|
|
} elsif($mode eq 'cert' || $mode eq 'CA') {
|
|
|
|
$parsed = $self->{'CERT'}->parse_cert( $self, $name);
|
|
|
|
}
|
|
|
|
|
|
|
|
defined($parsed) || GUI::HELPERS::print_error(_("Can't read file"));
|
|
|
|
|
|
|
|
$t = $mode eq 'req'?_("Request Details"):_("Certificate Details");
|
|
|
|
|
|
|
|
$button_ok = Gtk2::Button->new_from_stock('gtk-ok');
|
|
|
|
$button_ok->can_default(1);
|
|
|
|
$button_ok->signal_connect('clicked', sub { $box->destroy() });
|
|
|
|
|
|
|
|
$box = GUI::HELPERS::dialog_box($t, $t, $button_ok);
|
|
|
|
$box->set_default_size(700, 400);
|
|
|
|
|
|
|
|
$button_ok->grab_default();
|
|
|
|
|
|
|
|
$mode = 'cert' if($mode eq 'CA');
|
|
|
|
|
|
|
|
$tree = $self->create_detail_tree($parsed, $mode);
|
|
|
|
$box->vbox->add($tree);
|
|
|
|
|
|
|
|
$box->show_all();
|
|
|
|
$tree->{'tree'}->columns_autosize();
|
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# pop-up to verify import
|
|
|
|
#
|
|
|
|
sub show_import_verification {
|
|
|
|
my ($self, $mode, $opts, $parsed) = @_;
|
|
|
|
|
|
|
|
my($box, $button_ok, $button_cancel, $label, $rows, $tree, $t);
|
|
|
|
|
|
|
|
$button_ok = Gtk2::Button->new_from_stock('gtk-ok');
|
|
|
|
$button_ok->can_default(1);
|
|
|
|
if($mode eq "req") {
|
|
|
|
$button_ok->signal_connect('clicked',
|
|
|
|
sub { $self->{'REQ'}->import_req($self, $opts, $parsed, $box) });
|
|
|
|
} elsif($mode eq |