2010-09-28 12:30:57 +02:00
|
|
|
## @file
|
|
|
|
# Display functions for LemonLDAP::NG Portal
|
|
|
|
|
|
|
|
## @class
|
|
|
|
# Display functions for LemonLDAP::NG Portal
|
|
|
|
package Lemonldap::NG::Portal::Display;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Lemonldap::NG::Portal::Simple;
|
2010-10-04 16:50:33 +02:00
|
|
|
use utf8;
|
2010-09-28 12:30:57 +02:00
|
|
|
|
2015-04-15 16:18:38 +02:00
|
|
|
our $VERSION = '2.0.0';
|
2010-09-28 12:30:57 +02:00
|
|
|
|
|
|
|
## @method array display()
|
|
|
|
# Call portal process and set template parameters
|
|
|
|
# @return template name and template parameters
|
|
|
|
sub display {
|
|
|
|
my $self = shift;
|
|
|
|
|
2011-02-04 13:50:24 +01:00
|
|
|
my $skin_dir = $self->getApacheHtdocsPath() . "/skins";
|
2010-09-28 12:30:57 +02:00
|
|
|
my ( $skinfile, %templateParams );
|
2010-09-28 16:40:50 +02:00
|
|
|
my $http_error = $self->param('lmError');
|
2010-09-28 12:30:57 +02:00
|
|
|
|
2010-09-28 16:40:50 +02:00
|
|
|
# 0. Display error page
|
|
|
|
if ($http_error) {
|
|
|
|
|
|
|
|
$skinfile = 'error.tpl';
|
|
|
|
|
|
|
|
# Error code
|
|
|
|
my $error500 = 1 if ( $http_error eq "500" );
|
|
|
|
my $error403 = 1 if ( $http_error eq "403" );
|
2012-03-01 12:04:49 +01:00
|
|
|
my $error503 = 1 if ( $http_error eq "503" );
|
2010-09-28 16:40:50 +02:00
|
|
|
|
|
|
|
# Check URL
|
|
|
|
$self->_sub('controlUrlOrigin');
|
2010-09-28 12:30:57 +02:00
|
|
|
|
2013-08-23 15:34:37 +02:00
|
|
|
# Load session content
|
|
|
|
$self->_sub('controlExistingSession');
|
|
|
|
|
2010-09-28 16:40:50 +02:00
|
|
|
%templateParams = (
|
|
|
|
PORTAL_URL => $self->{portal},
|
|
|
|
LOGOUT_URL => $self->{portal} . "?logout=1",
|
|
|
|
URL => $self->{urldc},
|
|
|
|
ERROR403 => $error403,
|
|
|
|
ERROR500 => $error500,
|
2012-03-01 12:04:49 +01:00
|
|
|
ERROR503 => $error503,
|
2010-09-28 16:40:50 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# 1. Good authentication
|
|
|
|
elsif ( $self->process() ) {
|
2010-09-28 12:30:57 +02:00
|
|
|
|
|
|
|
# 1.1 Image mode
|
|
|
|
if ( $self->{error} == PE_IMG_OK || $self->{error} == PE_IMG_NOK ) {
|
|
|
|
$skinfile = "$skin_dir/common/"
|
|
|
|
. (
|
|
|
|
$self->{error} == PE_IMG_OK
|
|
|
|
? 'ok.png'
|
|
|
|
: 'warning.png'
|
|
|
|
);
|
|
|
|
$self->printImage( $skinfile, 'image/png' );
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
# 1.2 Case : there is a message to display
|
|
|
|
elsif ( my $info = $self->info() ) {
|
|
|
|
$skinfile = 'info.tpl';
|
|
|
|
%templateParams = (
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type,
|
|
|
|
MSG => $info,
|
|
|
|
URL => $self->{urldc},
|
|
|
|
HIDDEN_INPUTS => $self->buildHiddenForm(),
|
|
|
|
ACTIVE_TIMER => $self->{activeTimer},
|
|
|
|
FORM_METHOD => $self->{infoFormMethod},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-02-01 15:18:41 +01:00
|
|
|
# 1.3 Redirection
|
2012-02-20 18:09:07 +01:00
|
|
|
elsif ( $self->{error} == PE_REDIRECT ) {
|
2012-02-29 12:37:09 +01:00
|
|
|
$skinfile = "redirect.tpl";
|
2012-02-01 15:18:41 +01:00
|
|
|
%templateParams = (
|
2012-02-29 14:19:57 +01:00
|
|
|
URL => $self->{urldc},
|
|
|
|
HIDDEN_INPUTS => $self->buildHiddenForm(),
|
2012-03-14 20:14:17 +01:00
|
|
|
FORM_METHOD => $self->{redirectFormMethod},
|
2012-02-01 15:18:41 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# 1.4 Case : display menu
|
2010-09-28 12:30:57 +02:00
|
|
|
else {
|
|
|
|
|
|
|
|
# Initialize menu elements
|
|
|
|
$self->_sub('menuInit');
|
|
|
|
|
|
|
|
$skinfile = 'menu.tpl';
|
2010-10-04 16:50:33 +02:00
|
|
|
my $auth_user = $self->{sessionInfo}->{ $self->{portalUserAttr} };
|
|
|
|
utf8::decode($auth_user);
|
2010-09-28 12:30:57 +02:00
|
|
|
|
|
|
|
%templateParams = (
|
2012-02-29 14:19:57 +01:00
|
|
|
AUTH_USER => $auth_user,
|
|
|
|
NEWWINDOW => $self->{portalOpenLinkInNewWindow},
|
|
|
|
AUTH_ERROR => $self->error( $self->{menuError} ),
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type( $self->{menuError} ),
|
|
|
|
DISPLAY_TAB => $self->{menuDisplayTab},
|
|
|
|
LOGOUT_URL => "$ENV{SCRIPT_NAME}?logout=1",
|
2010-09-28 12:30:57 +02:00
|
|
|
REQUIRE_OLDPASSWORD => $self->{portalRequireOldPassword},
|
2011-05-20 11:45:18 +02:00
|
|
|
HIDE_OLDPASSWORD =>
|
|
|
|
0, # Do not hide old password if it is required
|
|
|
|
DISPLAY_MODULES => $self->{menuDisplayModules},
|
2010-09-28 12:30:57 +02:00
|
|
|
APPSLIST_MENU => $self->{menuAppslistMenu}, # For old templates
|
|
|
|
APPSLIST_DESC => $self->{menuAppslistDesc}, # For old templates
|
2010-10-25 08:25:20 +02:00
|
|
|
SCRIPT_NAME => $ENV{SCRIPT_NAME},
|
2012-12-04 17:31:12 +01:00
|
|
|
APPSLIST_ORDER => $self->{sessionInfo}->{'appsListOrder'},
|
2014-02-07 11:17:45 +01:00
|
|
|
PING => $self->{portalPingInterval},
|
2010-09-28 12:30:57 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# 2. Authentication not complete
|
|
|
|
|
|
|
|
# 2.1 A notification has to be done (session is created but hidden and unusable
|
|
|
|
# until the user has accept the message)
|
|
|
|
elsif ( my $notif = $self->notification ) {
|
|
|
|
$skinfile = 'notification.tpl';
|
|
|
|
%templateParams = (
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type,
|
|
|
|
NOTIFICATION => $notif,
|
|
|
|
HIDDEN_INPUTS => $self->buildHiddenForm(),
|
|
|
|
AUTH_URL => $self->get_url,
|
2011-06-09 23:08:43 +02:00
|
|
|
CHOICE_PARAM => $self->{authChoiceParam},
|
|
|
|
CHOICE_VALUE => $self->{_authChoice},
|
2010-09-28 12:30:57 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# 2.2 An authentication (or userDB) module needs to ask a question
|
|
|
|
# before processing to the request
|
|
|
|
elsif ( $self->{error} == PE_CONFIRM ) {
|
|
|
|
$skinfile = 'confirm.tpl';
|
|
|
|
%templateParams = (
|
|
|
|
AUTH_ERROR => $self->error,
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type,
|
|
|
|
AUTH_URL => $self->get_url,
|
|
|
|
MSG => $self->info(),
|
|
|
|
HIDDEN_INPUTS => $self->buildHiddenForm(),
|
|
|
|
ACTIVE_TIMER => $self->{activeTimer},
|
|
|
|
FORM_METHOD => $self->{confirmFormMethod},
|
|
|
|
CHOICE_PARAM => $self->{authChoiceParam},
|
|
|
|
CHOICE_VALUE => $self->{_authChoice},
|
2012-02-28 15:38:13 +01:00
|
|
|
CHECK_LOGINS => $self->{portalCheckLogins} && $self->{login},
|
|
|
|
ASK_LOGINS => $self->{checkLogins},
|
2010-09-28 12:30:57 +02:00
|
|
|
CONFIRMKEY => $self->stamp(),
|
2012-02-15 16:28:08 +01:00
|
|
|
LIST => $self->{list} || [],
|
2014-12-01 18:07:55 +01:00
|
|
|
REMEMBER => $self->{confirmRemember},
|
2010-09-28 12:30:57 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# 2.3 There is a message to display
|
|
|
|
elsif ( my $info = $self->info() ) {
|
|
|
|
$skinfile = 'info.tpl';
|
|
|
|
%templateParams = (
|
|
|
|
AUTH_ERROR => $self->error,
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type,
|
|
|
|
MSG => $info,
|
|
|
|
URL => $self->{urldc},
|
|
|
|
HIDDEN_INPUTS => $self->buildHiddenForm(),
|
|
|
|
ACTIVE_TIMER => $self->{activeTimer},
|
|
|
|
FORM_METHOD => $self->{infoFormMethod},
|
|
|
|
CHOICE_PARAM => $self->{authChoiceParam},
|
|
|
|
CHOICE_VALUE => $self->{_authChoice},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# 2.4 OpenID menu page
|
|
|
|
elsif ($self->{error} == PE_OPENID_EMPTY
|
|
|
|
or $self->{error} == PE_OPENID_BADID )
|
|
|
|
{
|
|
|
|
$skinfile = 'openid.tpl';
|
|
|
|
my $p = $self->{portal} . $self->{issuerDBOpenIDPath};
|
|
|
|
$p =~ s#(?<!:)/\^?/#/#g;
|
|
|
|
%templateParams = (
|
|
|
|
AUTH_ERROR => $self->error,
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type,
|
|
|
|
PROVIDERURI => $p,
|
|
|
|
ID => $self->{_openidPortal}
|
|
|
|
. $self->{sessionInfo}
|
2010-10-04 11:55:50 +02:00
|
|
|
->{ $self->{openIdAttr} || $self->{whatToTrace} },
|
2010-10-01 09:48:50 +02:00
|
|
|
PORTAL_URL => $self->{portal},
|
|
|
|
MSG => $self->info(),
|
2010-09-28 12:30:57 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# 2.5 Authentication has been refused OR this is the first access
|
|
|
|
else {
|
|
|
|
$skinfile = 'login.tpl';
|
|
|
|
%templateParams = (
|
|
|
|
AUTH_ERROR => $self->error,
|
|
|
|
AUTH_ERROR_TYPE => $self->error_type,
|
|
|
|
AUTH_URL => $self->get_url,
|
|
|
|
LOGIN => $self->get_user,
|
2012-02-27 21:16:09 +01:00
|
|
|
CHECK_LOGINS => $self->{portalCheckLogins},
|
2012-02-28 15:38:13 +01:00
|
|
|
ASK_LOGINS => $self->{checkLogins},
|
2010-09-28 12:30:57 +02:00
|
|
|
DISPLAY_RESETPASSWORD => $self->{portalDisplayResetPassword},
|
2014-05-30 14:21:53 +02:00
|
|
|
DISPLAY_REGISTER => $self->{portalDisplayRegister},
|
2010-09-28 12:30:57 +02:00
|
|
|
MAIL_URL => $self->{mailUrl},
|
2014-05-30 14:21:53 +02:00
|
|
|
REGISTER_URL => $self->{registerUrl},
|
2010-09-28 12:30:57 +02:00
|
|
|
HIDDEN_INPUTS => $self->buildHiddenForm(),
|
|
|
|
LOGIN_INFO => $self->loginInfo(),
|
|
|
|
);
|
|
|
|
|
2012-07-04 14:33:03 +02:00
|
|
|
# Display captcha if it's enabled
|
2013-02-21 18:38:14 +01:00
|
|
|
if ( $self->{captcha_login_enabled} ) {
|
2012-07-04 14:33:03 +02:00
|
|
|
%templateParams = (
|
2012-07-26 04:47:27 +02:00
|
|
|
%templateParams,
|
|
|
|
CAPTCHA_IMG => $self->{captcha_img},
|
|
|
|
CAPTCHA_CODE => $self->{captcha_code},
|
|
|
|
CAPTCHA_SIZE => $self->{captcha_size}
|
|
|
|
);
|
2012-07-04 14:33:03 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 15:47:47 +01:00
|
|
|
# Show password form if password policy error
|
2010-09-28 12:30:57 +02:00
|
|
|
if (
|
2011-06-21 12:11:02 +02:00
|
|
|
|
|
|
|
$self->{error} == PE_PP_CHANGE_AFTER_RESET
|
|
|
|
or $self->{error} == PE_PP_MUST_SUPPLY_OLD_PASSWORD
|
|
|
|
or $self->{error} == PE_PP_INSUFFICIENT_PASSWORD_QUALITY
|
|
|
|
or $self->{error} == PE_PP_PASSWORD_TOO_SHORT
|
|
|
|
or $self->{error} == PE_PP_PASSWORD_TOO_YOUNG
|
|
|
|
or $self->{error} == PE_PP_PASSWORD_IN_HISTORY
|
|
|
|
or $self->{error} == PE_PASSWORD_MISMATCH
|
|
|
|
or $self->{error} == PE_BADOLDPASSWORD
|
2011-11-07 15:54:22 +01:00
|
|
|
or $self->{error} == PE_PASSWORDFORMEMPTY
|
2010-09-28 12:30:57 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
%templateParams = (
|
|
|
|
%templateParams,
|
2011-05-20 11:45:18 +02:00
|
|
|
REQUIRE_OLDPASSWORD =>
|
|
|
|
1, # Old password is required to check user credentials
|
2012-04-12 14:41:51 +02:00
|
|
|
DISPLAY_FORM => 0,
|
|
|
|
DISPLAY_OPENID_FORM => 0,
|
|
|
|
DISPLAY_YUBIKEY_FORM => 0,
|
2010-09-28 12:30:57 +02:00
|
|
|
DISPLAY_PASSWORD => 1,
|
|
|
|
DISPLAY_RESETPASSWORD => 0,
|
2010-11-27 18:23:11 +01:00
|
|
|
AUTH_LOOP => [],
|
2011-01-25 17:41:31 +01:00
|
|
|
CHOICE_PARAM => $self->{authChoiceParam},
|
|
|
|
CHOICE_VALUE => $self->{_authChoice},
|
2011-05-20 11:45:18 +02:00
|
|
|
OLDPASSWORD =>
|
|
|
|
$self->checkXSSAttack( 'oldpassword', $self->{oldpassword} )
|
|
|
|
? ""
|
|
|
|
: $self->{oldpassword},
|
|
|
|
HIDE_OLDPASSWORD => $self->{hideOldPassword},
|
2010-09-28 12:30:57 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-03-25 16:42:46 +02:00
|
|
|
# Disable all forms on:
|
|
|
|
# * Logout message
|
|
|
|
# * Bad URL error
|
2012-04-12 14:41:51 +02:00
|
|
|
elsif ($self->{error} == PE_LOGOUT_OK
|
2012-03-25 16:42:46 +02:00
|
|
|
or $self->{error} == PE_BADURL )
|
|
|
|
{
|
2010-09-28 12:30:57 +02:00
|
|
|
%templateParams = (
|
|
|
|
%templateParams,
|
|
|
|
DISPLAY_RESETPASSWORD => 0,
|
|
|
|
DISPLAY_FORM => 0,
|
|
|
|
DISPLAY_OPENID_FORM => 0,
|
2011-04-18 11:16:17 +02:00
|
|
|
DISPLAY_YUBIKEY_FORM => 0,
|
2010-09-28 12:30:57 +02:00
|
|
|
AUTH_LOOP => [],
|
|
|
|
PORTAL_URL => $self->{portal},
|
|
|
|
MSG => $self->info(),
|
|
|
|
);
|
2012-03-24 15:47:47 +01:00
|
|
|
|
2010-09-28 12:30:57 +02:00
|
|
|
}
|
2012-03-24 15:47:47 +01:00
|
|
|
|
2012-04-12 14:41:51 +02:00
|
|
|
# Display authentifcation form
|
|
|
|
else {
|
|
|
|
|
|
|
|
# Authentication loop
|
|
|
|
if ( $self->{authLoop} ) {
|
|
|
|
%templateParams = (
|
|
|
|
%templateParams,
|
|
|
|
AUTH_LOOP => $self->{authLoop},
|
|
|
|
CHOICE_PARAM => $self->{authChoiceParam},
|
|
|
|
CHOICE_VALUE => $self->{_authChoice},
|
|
|
|
DISPLAY_FORM => 0,
|
|
|
|
DISPLAY_OPENID_FORM => 0,
|
|
|
|
DISPLAY_YUBIKEY_FORM => 0,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Choose what form to display if not in a loop
|
|
|
|
else {
|
|
|
|
|
|
|
|
my $displayType = $self->getDisplayType();
|
|
|
|
|
|
|
|
$self->lmLog( "Display type $displayType ", 'debug' );
|
|
|
|
|
|
|
|
%templateParams = (
|
|
|
|
%templateParams,
|
|
|
|
DISPLAY_FORM => $displayType eq "standardform" ? 1 : 0,
|
|
|
|
DISPLAY_OPENID_FORM => $displayType eq "openidform" ? 1 : 0,
|
2013-09-30 16:37:15 +02:00
|
|
|
DISPLAY_YUBIKEY_FORM => $displayType eq "yubikeyform" ? 1
|
2012-04-12 14:41:51 +02:00
|
|
|
: 0,
|
2013-09-30 16:37:15 +02:00
|
|
|
DISPLAY_LOGO_FORM => $displayType eq "logo" ? 1 : 0,
|
|
|
|
module => $displayType eq "logo" ? $self->get_module('auth')
|
|
|
|
: "",
|
2012-04-12 14:41:51 +02:00
|
|
|
AUTH_LOOP => [],
|
|
|
|
PORTAL_URL => $displayType eq "logo" ? $self->{portal} : 0,
|
|
|
|
MSG => $self->info(),
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-09-28 12:30:57 +02:00
|
|
|
}
|
|
|
|
|
2012-02-09 12:13:49 +01:00
|
|
|
## Common template params
|
2013-08-20 15:36:06 +02:00
|
|
|
my $skin = $self->getSkin();
|
2012-02-09 12:13:49 +01:00
|
|
|
my $portalPath = $self->{portal};
|
|
|
|
$portalPath =~ s#^https?://[^/]+/?#/#;
|
|
|
|
$portalPath =~ s#[^/]+\.pl$##;
|
|
|
|
%templateParams = (
|
|
|
|
%templateParams,
|
|
|
|
SKIN_PATH => $portalPath . "skins",
|
|
|
|
SKIN => $skin,
|
|
|
|
ANTIFRAME => $self->{portalAntiFrame},
|
2014-12-02 15:51:23 +01:00
|
|
|
SKIN_BG => $self->{portalSkinBackground},
|
2012-02-09 12:13:49 +01:00
|
|
|
);
|
|
|
|
|
2012-03-09 13:41:17 +01:00
|
|
|
## Custom template params
|
|
|
|
if ( my $customParams = $self->getCustomTemplateParameters() ) {
|
2012-03-24 15:47:47 +01:00
|
|
|
%templateParams = ( %templateParams, %$customParams );
|
2012-03-09 13:41:17 +01:00
|
|
|
}
|
|
|
|
|
2010-09-28 12:30:57 +02:00
|
|
|
return ( "$skin_dir/$skin/$skinfile", %templateParams );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
=encoding utf8
|
|
|
|
|
|
|
|
Lemonldap::NG::Portal::Display - Display functions for LemonLDAP::NG Portal
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
use Lemonldap::NG::Portal::SharedConf;
|
|
|
|
use HTML::Template;
|
|
|
|
|
|
|
|
my $portal = Lemonldap::NG::Portal::SharedConf->new();
|
|
|
|
|
|
|
|
my($templateName,%templateParams) = $portal->display();
|
|
|
|
|
|
|
|
my $template = HTML::Template->new(
|
|
|
|
filename => $templateName,
|
|
|
|
die_on_bad_params => 0,
|
|
|
|
cache => 0,
|
|
|
|
global_vars => 1,
|
|
|
|
filter => sub { $portal->translate_template(@_) }
|
|
|
|
);
|
|
|
|
while ( my ( $k, $v ) = each %templateParams ) { $template->param( $k, $v ); }
|
|
|
|
|
|
|
|
print $portal->header('text/html; charset=utf-8');
|
|
|
|
print $template->output;
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
This module is used to build all templates parameters to display
|
|
|
|
LemonLDAP::NG Portal
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
L<Lemonldap::NG::Portal>
|
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
2013-01-31 06:33:10 +01:00
|
|
|
=over
|
|
|
|
|
|
|
|
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
|
|
|
|
2013-10-19 18:34:20 +02:00
|
|
|
=item François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
|
2013-01-31 06:33:10 +01:00
|
|
|
|
|
|
|
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
|
|
|
|
|
|
|
=item Sandro Cazzaniga, E<lt>cazzaniga.sandro@gmail.comE<gt>
|
|
|
|
|
2013-02-01 06:37:38 +01:00
|
|
|
=item Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
|
2013-01-31 06:33:10 +01:00
|
|
|
|
|
|
|
=back
|
2010-09-28 12:30:57 +02:00
|
|
|
|
|
|
|
=head1 BUG REPORT
|
|
|
|
|
|
|
|
Use OW2 system to report bug or ask for features:
|
|
|
|
L<http://jira.ow2.org>
|
|
|
|
|
|
|
|
=head1 DOWNLOAD
|
|
|
|
|
|
|
|
Lemonldap::NG is available at
|
|
|
|
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
2013-01-31 06:33:10 +01:00
|
|
|
=over
|
|
|
|
|
|
|
|
=item Copyright (C) 2010, 2012 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
|
|
|
|
|
|
|
=item Copyright (C) 2012 by Sandro Cazzaniga, E<lt>cazzaniga.sandro@gmail.comE<gt>
|
|
|
|
|
2013-10-19 18:34:20 +02:00
|
|
|
=item Copyright (C) 2012 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
|
2013-01-31 06:33:10 +01:00
|
|
|
|
|
|
|
=item Copyright (C) 2010, 2011, 2012, 2013 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
|
|
|
|
2013-02-01 06:37:38 +01:00
|
|
|
=item Copyright (C) 2011 by Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
|
2013-01-31 06:33:10 +01:00
|
|
|
|
|
|
|
=back
|
2010-09-28 12:30:57 +02:00
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
2013-01-31 06:33:10 +01:00
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2, 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, see L<http://www.gnu.org/licenses/>.
|
2010-09-28 12:30:57 +02:00
|
|
|
|
|
|
|
=cut
|
|
|
|
|