first commit

This commit is contained in:
2024-06-03 18:43:35 +02:00
parent 2da01a3f6e
commit f501d519af
883 changed files with 71550 additions and 2 deletions

View File

@ -0,0 +1,31 @@
FROM python:3.11
#cette image permet d'avoir l'env python ainsi que le mode "reload on change", pratique quand on modifie les sources *.py
# maj des packages dispo
RUN apt-get update
#ldap pour le pip install python-ldap car apt-get python-ldap marche po
RUN apt-get install -y libsasl2-dev python3-dev libldap2-dev libssl-dev ldap-utils
#pour l'api soap sympa', perl est déjà installé mais il faut les modules suivant
RUN cpan App::cpanminus
RUN cpanm SOAP::Lite XML::LibXML MIME::EncWords Text::LineFold Class::Singleton Locale::Messages
#installer le truc de génération de mot de mdp
RUN apt-get -y install apg
#installer mmctl pour mattermost
RUN mkdir -p /mm/ && cd /mm/ && \
curl -vfsSL -O https://releases.mattermost.com/mmctl/v9.7.1/linux_amd64.tar && \
tar -xf linux_amd64.tar
#l'api Kaz
RUN mkdir /usr/src/app/
COPY . /usr/src/app/
WORKDIR /usr/src/app/
EXPOSE 5000
#les modules python à installer lors du build
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

View File

@ -0,0 +1,75 @@
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2018 The Sympa Community. See the AUTHORS.md file at the
# top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# 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, see <http://www.gnu.org/licenses/>.
package Sympa::Constants;
use strict;
use constant VERSION => '--VERSION--';
use constant USER => '--USER--';
use constant GROUP => '--GROUP--';
use constant CONFIG => '--CONFIG--';
use constant WWSCONFIG => '--WWSCONFIG--';
use constant SENDMAIL_ALIASES => '--SENDMAIL_ALIASES--';
use constant PIDDIR => '--piddir--';
use constant EXPLDIR => '--expldir--';
use constant SPOOLDIR => '--spooldir--';
use constant SYSCONFDIR => '--sysconfdir--';
use constant LOCALEDIR => '--localedir--';
use constant LIBEXECDIR => '--libexecdir--';
use constant SBINDIR => '--sbindir--';
use constant SCRIPTDIR => '--scriptdir--';
use constant MODULEDIR => '--modulesdir--';
use constant DEFAULTDIR => '--defaultdir--';
use constant ARCDIR => '--arcdir--';
use constant BOUNCEDIR => '--bouncedir--';
use constant EXECCGIDIR => '--execcgidir--';
use constant STATICDIR => '--staticdir--';
use constant CSSDIR => '--cssdir--';
use constant PICTURESDIR => '--picturesdir--';
use constant EMAIL_LEN => 100;
use constant FAMILY_LEN => 50;
use constant LIST_LEN => 50;
use constant ROBOT_LEN => 80;
1;
__END__
=encoding utf-8
=head1 NAME
Sympa::Constants - Definition of constants
=head1 DESCRIPTION
This module keeps definition of constants used by Sympa software.
=cut

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,128 @@
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2017, 2021, 2022, 2023 The Sympa Community. See the
# AUTHORS.md file at the top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# 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, see <http://www.gnu.org/licenses/>.
package Sympa::Regexps;
use strict;
use warnings;
# domain name.
use constant domain => qr'[-\w]+(?:[.][-\w]+)+';
# These are relaxed variants of the syntax for mailbox described in RFC 5322.
# See also RFC 5322, 3.2.3 & 3.4.1 for details on format.
use constant email =>
qr{(?:[A-Za-z0-9!\#\$%\&'*+\-/=?^_`{|}~.]+|"(?:\\.|[^\\"])*")\@[-\w]+(?:[.][-\w]+)+};
# This is older definition used by 6.2.65b and earlier.
#use constant addrspec => qr{(?:[-&+'./\w=]+|".*")\@[-\w]+(?:[.][-\w]+)+};
# This is the same as above except that it gave some groups, then regexp
# using it should also be changed. By this reason it has been deprecated.
#use constant email => qr'([\w\-\_\.\/\+\=\'\&]+|\".*\")\@[\w\-]+(\.[\w\-]+)+';
use constant family_name => qr'[a-z0-9][a-z0-9\-\.\+_]*';
## Allow \s for template names
use constant template_name => qr'[a-zA-Z0-9][a-zA-Z0-9\-\.\+_\s]*';
#FIXME: Not matching with IPv6 address.
use constant host => qr'[\w\.\-]+';
use constant hostport => qr{(?:
[-.\w]+ (?::\d+)?
| [:0-9a-f]*:[:0-9a-f]*:[:0-9a-f]*
| \[ [:0-9a-f]*:[:0-9a-f]*:[:0-9a-f]* \] (?::\d+)?
)}ix;
use constant html_date =>
qr'[0-9]{4}[0-9]*-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])';
use constant ipv6 => qr'[:0-9a-f]*:[:0-9a-f]*:[:0-9a-f]*'i;
#FIXME: Cannot contain IPv6 address.
use constant multiple_host_with_port =>
'[\w\.\-]+(:\d+)?(,[\w\.\-]+(:\d+)?)*';
#FIXME: Cannot contain IPv6 address.
use constant multiple_host_or_url =>
qr'([-\w]+://.+|[-.\w]+(:\d+)?)(,([-\w]+://.+|[-.\w]+(:\d+)?))*';
use constant listname => qr'[a-z0-9][a-z0-9\-\.\+_]*';
use constant ldap_attrdesc => qr'\w[-\w]*(?:;[-\w]+)*'; # RFC2251, 4.1.5
# "value" defined in RFC 2045, 5.1.
use constant rfc2045_parameter_value =>
qr'[^\s\x00-\x1F\x7F-\xFF()<>\@,;:\\/\[\]?=\"]+';
use constant sql_query => qr'(SELECT|select).*';
# "scenario" was deprecated. Use "scenario_name".
# "scenario_config" is used for compatibility to earlier list config files.
use constant scenario_config => qr'[-.,\w]+';
use constant scenario_name => qr'[-.\w]+';
use constant task => qr'\w+';
use constant datasource => qr'[\w-]+';
use constant uid => qr'[\w\-\.\+]+';
use constant time => qr'[012]?[0-9](?:\:[0-5][0-9])?';
use constant time_range => __PACKAGE__->time . '-' . __PACKAGE__->time;
use constant time_ranges => time_range() . '(?:\s+' . time_range() . ')*';
use constant re => qr{
(?:
Antw # Dutch
| ATB # Welsh
| ATB \. # Latvian
| AW # German
| Odp # Polish
| R # Italian
| Re (?: \s* \( \d+ \) | \s* \[ \d+ \] | \*{1,2} \d+ | \^ \d+ )?
| REF # French
| RES # Portuguese
| Rif # Italian
| SV # Scandinavian
| V\x{00E1} # Magyar, "VA"
| VS # Finnish
| YNT # Turkish
| \x{05D4}\x{05E9}\x{05D1} # Hebrew, "hashev"
| \x{0391}\x{03A0} # Greek, "AP"
| \x{03A3}\x{03A7}\x{0395}\x{03A4} # Greek, "SChET"
| \x{041D}\x{0410} # some Slavic in Cyrillic, "na"
| \x{56DE}\x{590D} # Simp. Chinese, "huifu"
| \x{56DE}\x{8986} # Trad. Chinese, "huifu"
)
\s* [:\x{FF1A}]
}ix;
1;
__END__
=encoding utf-8
=head1 NAME
Sympa::Regexps - Definition of regular expressions
=head1 DESCRIPTION
This module keeps definition of regular expressions used by Sympa software.
=cut

View File

@ -0,0 +1,506 @@
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2018 The Sympa Community. See the AUTHORS.md file at the
# top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# 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, see <http://www.gnu.org/licenses/>.
package Sympa::Tools::Data;
use strict;
use warnings;
use Encode qw();
use English qw(-no_match_vars);
use POSIX qw();
use XML::LibXML qw();
BEGIN { eval 'use Clone qw()'; }
use Sympa::Tools::Text;
## This applies recursively to a data structure
## The transformation subroutine is passed as a ref
sub recursive_transformation {
my ($var, $subref) = @_;
return unless (ref($var));
if (ref($var) eq 'ARRAY') {
foreach my $index (0 .. $#{$var}) {
if (ref($var->[$index])) {
recursive_transformation($var->[$index], $subref);
} else {
$var->[$index] = &{$subref}($var->[$index]);
}
}
} elsif (ref($var) eq 'HASH') {
foreach my $key (keys %{$var}) {
if (ref($var->{$key})) {
recursive_transformation($var->{$key}, $subref);
} else {
$var->{$key} = &{$subref}($var->{$key});
}
}
}
return;
}
## Dump a variable's content
sub dump_var {
my ($var, $level, $fd) = @_;
return undef unless ($fd);
if (ref($var)) {
if (ref($var) eq 'ARRAY') {
foreach my $index (0 .. $#{$var}) {
print $fd "\t" x $level . $index . "\n";
dump_var($var->[$index], $level + 1, $fd);
}
} elsif (ref($var) eq 'HASH'
|| ref($var) eq 'Sympa::Scenario'
|| ref($var) eq 'Sympa::List'
|| ref($var) eq 'CGI::Fast') {
foreach my $key (sort keys %{$var}) {
print $fd "\t" x $level . '_' . $key . '_' . "\n";
dump_var($var->{$key}, $level + 1, $fd);
}
} else {
printf $fd "\t" x $level . "'%s'" . "\n", ref($var);
}
} else {
if (defined $var) {
print $fd "\t" x $level . "'$var'" . "\n";
} else {
print $fd "\t" x $level . "UNDEF\n";
}
}
}
## Dump a variable's content
sub dump_html_var {
my ($var) = shift;
my $html = '';
if (ref($var)) {
if (ref($var) eq 'ARRAY') {
$html .= '<ul>';
foreach my $index (0 .. $#{$var}) {
$html .= '<li> ' . $index . ':';
$html .= dump_html_var($var->[$index]);
$html .= '</li>';
}
$html .= '</ul>';
} elsif (ref($var) eq 'HASH'
|| ref($var) eq 'Sympa::Scenario'
|| ref($var) eq 'Sympa::List') {
$html .= '<ul>';
foreach my $key (sort keys %{$var}) {
$html .= '<li>' . $key . '=';
$html .= dump_html_var($var->{$key});
$html .= '</li>';
}
$html .= '</ul>';
} else {
$html .= 'EEEEEEEEEEEEEEEEEEEEE' . ref($var);
}
} else {
if (defined $var) {
$html .= Sympa::Tools::Text::encode_html($var);
} else {
$html .= 'UNDEF';
}
}
return $html;
}
# Duplicates a complex variable (faster).
# CAUTION: This duplicates blessed elements even if they are
# singleton/multiton; this breaks subroutine references.
sub clone_var {
return Clone::clone($_[0]) if $Clone::VERSION;
goto &dup_var; # '&' needed
}
## Duplictate a complex variable
sub dup_var {
my ($var) = @_;
if (ref($var)) {
if (ref($var) eq 'ARRAY') {
my $new_var = [];
foreach my $index (0 .. $#{$var}) {
$new_var->[$index] = dup_var($var->[$index]);
}
return $new_var;
} elsif (ref($var) eq 'HASH') {
my $new_var = {};
foreach my $key (sort keys %{$var}) {
$new_var->{$key} = dup_var($var->{$key});
}
return $new_var;
}
}
return $var;
}
####################################################
# get_array_from_splitted_string
####################################################
# return an array made on a string splited by ','.
# It removes spaces.
#
#
# IN : -$string (+): string to split
#
# OUT : -ref(ARRAY)
#
######################################################
# Note: This is used only by Sympa::List.
sub get_array_from_splitted_string {
my ($string) = @_;
my @array;
foreach my $word (split /,/, $string) {
$word =~ s/^\s+//;
$word =~ s/\s+$//;
push @array, $word;
}
return \@array;
}
####################################################
# diff_on_arrays
####################################################
# Makes set operation on arrays (seen as set, with no double) :
# - deleted : A \ B
# - added : B \ A
# - intersection : A /\ B
# - union : A \/ B
#
# IN : -$setA : ref(ARRAY) - set
# -$setB : ref(ARRAY) - set
#
# OUT : -ref(HASH) with keys :
# deleted, added, intersection, union
#
#######################################################
sub diff_on_arrays {
my ($setA, $setB) = @_;
my $result = {
'intersection' => [],
'union' => [],
'added' => [],
'deleted' => []
};
my %deleted;
my %added;
my %intersection;
my %union;
my %hashA;
my %hashB;
foreach my $eltA (@$setA) {
$hashA{$eltA} = 1;
$deleted{$eltA} = 1;
$union{$eltA} = 1;
}
foreach my $eltB (@$setB) {
$hashB{$eltB} = 1;
$added{$eltB} = 1;
if ($hashA{$eltB}) {
$intersection{$eltB} = 1;
$deleted{$eltB} = 0;
} else {
$union{$eltB} = 1;
}
}
foreach my $eltA (@$setA) {
if ($hashB{$eltA}) {
$added{$eltA} = 0;
}
}
foreach my $elt (keys %deleted) {
next unless $elt;
push @{$result->{'deleted'}}, $elt if ($deleted{$elt});
}
foreach my $elt (keys %added) {
next unless $elt;
push @{$result->{'added'}}, $elt if ($added{$elt});
}
foreach my $elt (keys %intersection) {
next unless $elt;
push @{$result->{'intersection'}}, $elt if ($intersection{$elt});
}
foreach my $elt (keys %union) {
next unless $elt;
push @{$result->{'union'}}, $elt if ($union{$elt});
}
return $result;
}
####################################################
# is_in_array
####################################################
# Test if a value is on an array
#
# IN : -$setA : ref(ARRAY) - set
# -$value : a serached value
#
# OUT : boolean
#######################################################
sub is_in_array {
my $set = shift;
die 'missing parameter "$value"' unless @_;
my $value = shift;
if (defined $value) {
foreach my $elt (@{$set || []}) {
next unless defined $elt;
return 1 if $elt eq $value;
}
} else {
foreach my $elt (@{$set || []}) {
return 1 unless defined $elt;
}
}
return undef;
}
=over
=item smart_eq ( $a, $b )
I<Function>.
Check if two strings are identical.
Parameters:
=over
=item $a, $b
Operands.
If both of them are undefined, they are equal.
If only one of them is undefined, the are not equal.
If C<$b> is a L<Regexp> object and it matches to C<$a>, they are equal.
Otherwise, they are compared as strings.
=back
Returns:
If arguments matched, true value. Otherwise false value.
=back
=cut
sub smart_eq {
die 'missing argument' if scalar @_ < 2;
my ($a, $b) = @_;
if (defined $a and defined $b) {
if (ref $b eq 'Regexp') {
return 1 if $a =~ $b;
} else {
return 1 if $a eq $b;
}
} elsif (!defined $a and !defined $b) {
return 1;
}
return undef;
}
## convert a string formated as var1="value1";var2="value2"; into a hash.
## Used when extracting from session table some session properties or when
## extracting users preference from user table
## Current encoding is NOT compatible with encoding of values with '"'
##
sub string_2_hash {
my $data = shift;
my %hash;
pos($data) = 0;
while ($data =~ /\G;?(\w+)\=\"((\\[\"\\]|[^\"])*)\"(?=(;|\z))/g) {
my ($var, $val) = ($1, $2);
$val =~ s/\\([\"\\])/$1/g;
$hash{$var} = $val;
}
return (%hash);
}
## convert a hash into a string formated as var1="value1";var2="value2"; into
## a hash
sub hash_2_string {
my $refhash = shift;
return undef unless ref $refhash eq 'HASH';
my $data_string;
foreach my $var (keys %$refhash) {
next unless length $var;
my $val = $refhash->{$var};
$val = '' unless defined $val;
$val =~ s/([\"\\])/\\$1/g;
$data_string .= ';' . $var . '="' . $val . '"';
}
return ($data_string);
}
## compare 2 scalars, string/numeric independant
sub smart_lessthan {
my ($stra, $strb) = @_;
$stra =~ s/^\s+//;
$stra =~ s/\s+$//;
$strb =~ s/^\s+//;
$strb =~ s/\s+$//;
$ERRNO = 0;
my ($numa, $unparsed) = POSIX::strtod($stra);
my $numb;
$numb = POSIX::strtod($strb)
unless ($ERRNO || $unparsed != 0);
if (($stra eq '') || ($strb eq '') || ($unparsed != 0) || $ERRNO) {
return $stra lt $strb;
} else {
return $stra < $strb;
}
}
=over
=item sort_uniq ( [ \&comp ], @items )
Returns sorted array of unique elements in the list.
Parameters:
=over
=item \&comp
Optional subroutine reference to compare each pairs of elements.
It should take two arguments and return negative, zero or positive result.
=item @items
Items to be sorted.
=back
This function was added on Sympa 6.2.16.
=back
=cut
sub sort_uniq {
my $comp;
if (ref $_[0] eq 'CODE') {
$comp = shift;
}
my %items;
@items{@_} = ();
if ($comp) {
return sort { $comp->($a, $b) } keys %items;
} else {
return sort keys %items;
}
}
# Create a custom attribute from an XML description
# IN : A string, XML formed data as stored in database
# OUT : HASH data storing custome attributes.
# Old name: Sympa::List::parseCustomAttribute().
sub decode_custom_attribute {
my $xmldoc = shift;
return undef unless defined $xmldoc and length $xmldoc;
my $parser = XML::LibXML->new();
my $tree;
## We should use eval to parse to prevent the program to crash if it fails
if (ref($xmldoc) eq 'GLOB') {
$tree = eval { $parser->parse_fh($xmldoc) };
} else {
$tree = eval { $parser->parse_string($xmldoc) };
}
return undef unless defined $tree;
my $doc = $tree->getDocumentElement;
my @custom_attr = $doc->getChildrenByTagName('custom_attribute');
my %ca;
foreach my $ca (@custom_attr) {
my $id = Encode::encode_utf8($ca->getAttribute('id'));
my $value = Encode::encode_utf8($ca->getElementsByTagName('value'));
$ca{$id} = {value => $value};
}
return \%ca;
}
# Create an XML Custom attribute to be stored into data base.
# IN : HASH data storing custome attributes
# OUT : string, XML formed data to be stored in database
# Old name: Sympa::List::createXMLCustomAttribute().
sub encode_custom_attribute {
my $custom_attr = shift;
return
'<?xml version="1.0" encoding="UTF-8" ?><custom_attributes></custom_attributes>'
if (not defined $custom_attr);
my $XMLstr = '<?xml version="1.0" encoding="UTF-8" ?><custom_attributes>';
foreach my $k (sort keys %{$custom_attr}) {
my $value = $custom_attr->{$k}{value};
$value = '' unless defined $value;
$XMLstr .=
"<custom_attribute id=\"$k\"><value>"
. Sympa::Tools::Text::encode_html($value, '\000-\037')
. "</value></custom_attribute>";
}
$XMLstr .= "</custom_attributes>";
$XMLstr =~ s/\s*\n\s*/ /g;
return $XMLstr;
}
1;

View File

@ -0,0 +1,942 @@
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2018, 2020 The Sympa Community. See the AUTHORS.md
# file at the top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# 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, see <http://www.gnu.org/licenses/>.
package Sympa::Tools::Text;
use strict;
use warnings;
use Encode qw();
use English qw(-no_match_vars);
use Encode::MIME::Header; # 'MIME-Q' encoding.
use HTML::Entities qw();
use MIME::EncWords;
use Text::LineFold;
use Unicode::GCString;
use URI::Escape qw();
use if ($] < 5.016), qw(Unicode::CaseFold fc);
use if (5.016 <= $]), qw(feature fc);
BEGIN { eval 'use Unicode::Normalize qw()'; }
BEGIN { eval 'use Unicode::UTF8 qw()'; }
use Sympa::Language;
use Sympa::Regexps;
# Old name: tools::addrencode().
sub addrencode {
my $addr = shift;
my $phrase = (shift || '');
my $charset = (shift || 'utf8');
my $comment = (shift || '');
return undef unless $addr =~ /\S/;
if ($phrase =~ /[^\s\x21-\x7E]/) {
$phrase = MIME::EncWords::encode_mimewords(
Encode::decode('utf8', $phrase),
'Encoding' => 'A',
'Charset' => $charset,
'Replacement' => 'FALLBACK',
'Field' => 'Resent-Sender', # almost longest
'Minimal' => 'DISPNAME', # needs MIME::EncWords >= 1.012.
);
} elsif ($phrase =~ /\S/) {
$phrase =~ s/([\\\"])/\\$1/g;
$phrase = '"' . $phrase . '"';
}
if ($comment =~ /[^\s\x21-\x27\x2A-\x5B\x5D-\x7E]/) {
$comment = MIME::EncWords::encode_mimewords(
Encode::decode('utf8', $comment),
'Encoding' => 'A',
'Charset' => $charset,
'Replacement' => 'FALLBACK',
'Minimal' => 'DISPNAME',
);
} elsif ($comment =~ /\S/) {
$comment =~ s/([\\\"])/\\$1/g;
}
return
($phrase =~ /\S/ ? "$phrase " : '')
. ($comment =~ /\S/ ? "($comment) " : '')
. "<$addr>";
}
# Old names: tools::clean_email(), tools::get_canonical_email().
sub canonic_email {
my $email = shift;
return undef unless defined $email;
# Remove leading and trailing white spaces.
$email =~ s/\A\s+//;
$email =~ s/\s+\z//;
# Lower-case.
$email =~ tr/A-Z/a-z/;
return (length $email) ? $email : undef;
}
# Old name: tools::clean_msg_id().
sub canonic_message_id {
my $msg_id = shift;
return $msg_id unless defined $msg_id;
chomp $msg_id;
if ($msg_id =~ /\<(.+)\>/) {
$msg_id = $1;
}
return $msg_id;
}
sub canonic_text {
my $text = shift;
return undef unless defined $text;
# Normalize text. See also discussion on
# https://listes.renater.fr/sympa/arc/sympa-developpers/2018-03/thrd1.html
#
# N.B.: Corresponding modules are optional by now, and should be
# mandatory in the future.
my $utext;
if (Encode::is_utf8($text)) {
$utext = $text;
} elsif ($Unicode::UTF8::VERSION) {
no warnings 'utf8';
$utext = Unicode::UTF8::decode_utf8($text);
} else {
$utext = Encode::decode_utf8($text);
}
if ($Unicode::Normalize::VERSION) {
$utext = Unicode::Normalize::normalize('NFC', $utext);
}
# Remove DOS linefeeds (^M) that cause problems with Outlook 98, AOL,
# and EIMS:
$utext =~ s/\r\n|\r/\n/g;
if (Encode::is_utf8($text)) {
return $utext;
} else {
return Encode::encode_utf8($utext);
}
}
sub slurp {
my $path = shift;
my $ifh;
return undef unless open $ifh, '<', $path;
my $text = do { local $RS; <$ifh> };
close $ifh;
return canonic_text($text);
}
sub wrap_text {
my $text = shift;
my $init = shift;
my $subs = shift;
my $cols = shift;
$init //= '';
$subs //= '';
$cols //= 78;
return $text unless $cols;
my $email_re = Sympa::Regexps::email();
my $linefold = Text::LineFold->new(
Language => Sympa::Language->instance->get_lang,
Prep => 'NONBREAKURI',
prep => [$email_re, sub { shift; @_ }],
ColumnsMax => $cols,
Format => sub {
shift;
my $event = shift;
my $str = shift;
if ($event =~ /^eo/) { return "\n"; }
if ($event =~ /^so[tp]/) { return $init . $str; }
if ($event eq 'sol') { return $subs . $str; }
undef;
},
);
my $t = Encode::is_utf8($text) ? $text : Encode::decode_utf8($text);
my $ret = '';
while (1000 < length $t) {
my $s = substr $t, 0, 1000;
$ret .= $linefold->break_partial($s);
$t = substr $t, 1000;
}
$ret .= $linefold->break_partial($t) if length $t;
$ret .= $linefold->break_partial(undef);
return Encode::is_utf8($text) ? $ret : Encode::encode_utf8($ret);
}
sub decode_filesystem_safe {
my $str = shift;
return '' unless defined $str and length $str;
$str = Encode::encode_utf8($str) if Encode::is_utf8($str);
# On case-insensitive filesystem "_XX" along with "_xx" should be decoded.
$str =~ s/_([0-9A-Fa-f]{2})/chr hex "0x$1"/eg;
return $str;
}
sub decode_html {
my $str = shift;
Encode::encode_utf8(
HTML::Entities::decode_entities(Encode::decode_utf8($str)));
}
sub encode_filesystem_safe {
my $str = shift;
return '' unless defined $str and length $str;
$str = Encode::encode_utf8($str) if Encode::is_utf8($str);
$str =~ s/([^-+.0-9\@A-Za-z])/sprintf '_%02x', ord $1/eg;
return $str;
}
sub encode_html {
my $str = shift;
my $additional_unsafe = shift || '';
HTML::Entities::encode_entities($str, '<>&"' . $additional_unsafe);
}
sub encode_uri {
my $str = shift;
my %options = @_;
# Note: URI-1.35 (URI::Escape 3.28) or later is required.
return Encode::encode_utf8(
URI::Escape::uri_escape_utf8(
Encode::decode_utf8($str),
'^-A-Za-z0-9._~' . (exists $options{omit} ? $options{omit} : '')
)
);
}
# Old name: tools::escape_chars().
sub escape_chars {
my $s = shift;
my $except = shift; ## Exceptions
my $ord_except = ord $except if defined $except;
## Escape chars
## !"#$%&'()+,:;<=>?[] AND accented chars
## escape % first
foreach my $i (
0x25,
0x20 .. 0x24,
0x26 .. 0x2c,
0x3a .. 0x3f,
0x5b, 0x5d,
0x80 .. 0x9f,
0xa0 .. 0xff
) {
next if defined $ord_except and $i == $ord_except;
my $hex_i = sprintf "%lx", $i;
$s =~ s/\x$hex_i/%$hex_i/g;
}
## Special traetment for '/'
$s =~ s/\//%a5/g unless defined $except and $except eq '/';
return $s;
}
# Old name: tt2::escape_url().
# DEPRECATED. Use Sympa::Tools::Text::escape_uri() or
# Sympa::Tools::Text::mailtourl().
#sub escape_url;
sub foldcase {
my $str = shift;
return '' unless defined $str and length $str;
# Perl 5.16.0 and later have built-in fc(). Earlier uses Unicode::CaseFold.
return Encode::encode_utf8(fc(Encode::decode_utf8($str)));
}
my %legacy_charsets = (
'ar' => [qw(iso-8859-6)],
'bs' => [qw(iso-8859-2)],
'cs' => [qw(iso-8859-2)],
'eo' => [qw(iso-8859-3)],
'et' => [qw(iso-8859-4)],
'he' => [qw(iso-8859-8)],
'hr' => [qw(iso-8859-2)],
'hu' => [qw(iso-8859-2)],
'ja' => [qw(euc-jp cp932 MacJapanese)],
'kl' => [qw(iso-8859-4)],
'ko' => [qw(cp949)],
'lt' => [qw(iso-8859-4)],
'lv' => [qw(iso-8859-4)],
'mt' => [qw(iso-8859-3)],
'pl' => [qw(iso-8859-2)],
'ro' => [qw(iso-8859-2)],
'ru' => [qw(koi8-r cp1251)], # cp866? MacCyrillic?
'sk' => [qw(iso-8859-2)],
'sl' => [qw(iso-8859-2)],
'th' => [qw(iso-8859-11 cp874 MacThai)],
'tr' => [qw(iso-8859-9)],
'uk' => [qw(koi8-u)], # MacUkrainian?
'zh-CN' => [qw(euc-cn)],
'zh-TW' => [qw(big5-eten)],
);
sub guessed_to_utf8 {
my $text = shift;
my @langs = @_;
return Encode::encode_utf8($text) if Encode::is_utf8($text);
return $text
unless defined $text
and length $text
and $text =~ /[^\x00-\x7F]/;
my $utf8;
if ($Unicode::UTF8::VERSION) {
$utf8 =
eval { Unicode::UTF8::decode_utf8($text, Encode::FB_CROAK()) };
}
unless (defined $utf8) {
foreach my $charset (map { $_ ? @$_ : () } @legacy_charsets{@langs}) {
$utf8 =
eval { Encode::decode($charset, $text, Encode::FB_CROAK()) };
last if defined $utf8;
}
}
unless (defined $utf8) {
$utf8 = Encode::decode('iso-8859-1', $text);
}
# Apply NFC: e.g. for modified-NFD by Mac OS X.
$utf8 = Unicode::Normalize::normalize('NFC', $utf8)
if $Unicode::Normalize::VERSION;
return Encode::encode_utf8($utf8);
}
sub mailtourl {
my $text = shift;
my %options = @_;
my $dtext =
(not defined $text) ? ''
: $options{decode_html} ? Sympa::Tools::Text::decode_html($text)
: $text;
$dtext =~ s/\A\s+//;
$dtext =~ s/\s+\z//;
$dtext =~ s/(?:\r\n|\r|\n)(?=[ \t])//g;
$dtext =~ s/\r\n|\r|\n/ /g;
# The ``@'' in email address should not be encoded because some MUAs
# aren't able to decode ``%40'' in e-mail address of mailto: URL.
# Contrary, ``@'' in query component should be encoded because some
# MUAs take it for a delimiter to separate URL from the rest.
my ($format, $utext, $qsep);
if ($dtext =~ /[()<>\[\]:;,\"\s]/) {
# Use "to" header if source text includes any of RFC 5322
# "specials", minus ``@'' and ``\'', plus whitespaces.
$format = 'mailto:?to=%s%s';
$utext = Sympa::Tools::Text::encode_uri($dtext);
$qsep = '&';
} else {
$format = 'mailto:%s%s';
$utext = Sympa::Tools::Text::encode_uri($dtext, omit => '@');
$qsep = '?';
}
my $qstring = _url_query_string(
$options{query},
decode_html => $options{decode_html},
leadchar => $qsep,
sepchar => '&',
trim_values => 1,
);
return sprintf $format, $utext, $qstring;
}
sub _url_query_string {
my $query = shift;
my %options = @_;
unless (ref $query eq 'HASH' and %$query) {
return '';
} else {
my $decode_html = $options{decode_html};
my $trim_values = $options{trim_values};
return ($options{leadchar} || '?') . join(
($options{sepchar} || ';'),
map {
my ($dkey, $dval) = map {
(not defined $_) ? ''
: $decode_html ? Sympa::Tools::Text::decode_html($_)
: $_;
} ($_, $query->{$_});
if ($trim_values and lc $dkey ne 'body') {
$dval =~ s/\A\s+//;
$dval =~ s/\s+\z//;
$dval =~ s/(?:\r\n|\r|\n)(?=[ \t])//g;
$dval =~ s/\r\n|\r|\n/ /g;
}
sprintf '%s=%s',
Sympa::Tools::Text::encode_uri($dkey),
Sympa::Tools::Text::encode_uri($dval);
} sort keys %$query
);
}
}
sub pad {
my $str = shift;
my $width = shift;
return $str unless $width and defined $str;
my $ustr = Encode::is_utf8($str) ? $str : Encode::decode_utf8($str);
my $cols = Unicode::GCString->new($ustr)->columns;
unless ($cols < abs $width) {
return $str;
} elsif ($width < 0) {
return $str . (' ' x (-$width - $cols));
} else {
return (' ' x ($width - $cols)) . $str;
}
}
# Old name: tools::qdecode_filename().
sub qdecode_filename {
my $filename = shift;
## We don't use MIME::Words here because it does not encode properly
## Unicode
## Check if string is already Q-encoded first
#if ($filename =~ /\=\?UTF-8\?/) {
$filename = Encode::encode_utf8(Encode::decode('MIME-Q', $filename));
#}
return $filename;
}
# Old name: tools::qencode_filename().
sub qencode_filename {
my $filename = shift;
## We don't use MIME::Words here because it does not encode properly
## Unicode
## Check if string is already Q-encoded first
## Also check if the string contains 8bit chars
unless ($filename =~ /\=\?UTF-8\?/
|| $filename =~ /^[\x00-\x7f]*$/) {
## Don't encode elements such as .desc. or .url or .moderate
## or .extension
my $part = $filename;
my ($leading, $trailing);
$leading = $1 if ($part =~ s/^(\.desc\.)//); ## leading .desc
$trailing = $1 if ($part =~ s/((\.\w+)+)$//); ## trailing .xx
my $encoded_part = MIME::EncWords::encode_mimewords(
$part,
Charset => 'utf8',
Encoding => 'q',
MaxLineLen => 1000,
Minimal => 'NO'
);
$filename = $leading . $encoded_part . $trailing;
}
return $filename;
}
# Old name: tools::unescape_chars().
sub unescape_chars {
my $s = shift;
$s =~ s/%a5/\//g; ## Special traetment for '/'
foreach my $i (0x20 .. 0x2c, 0x3a .. 0x3f, 0x5b, 0x5d, 0x80 .. 0x9f,
0xa0 .. 0xff) {
my $hex_i = sprintf "%lx", $i;
my $hex_s = sprintf "%c", $i;
$s =~ s/%$hex_i/$hex_s/g;
}
return $s;
}
# Old name: tools::valid_email().
sub valid_email {
my $email = shift;
my $email_re = Sympa::Regexps::email();
return undef unless $email =~ /^${email_re}$/;
# Forbidden characters.
return undef if $email =~ /[\|\$\*\?\!]/;
return 1;
}
sub weburl {
my $base = shift;
my $paths = shift;
my %options = @_;
my @paths = map {
Sympa::Tools::Text::encode_uri(
(not defined $_) ? ''
: $options{decode_html} ? Sympa::Tools::Text::decode_html($_)
: $_
);
} @{$paths || []};
my $qstring = _url_query_string(
$options{query},
decode_html => $options{decode_html},
sepchar => '&',
);
my $fstring;
my $fragment = $options{fragment};
if (defined $fragment) {
$fstring = '#'
. Sympa::Tools::Text::encode_uri(
$options{decode_html}
? Sympa::Tools::Text::decode_html($fragment)
: $fragment
);
} else {
$fstring = '';
}
return sprintf '%s%s%s', join('/', grep { defined $_ } ($base, @paths)),
$qstring, $fstring;
}
1;
__END__
=encoding utf-8
=head1 NAME
Sympa::Tools::Text - Text-related functions
=head1 DESCRIPTION
This package provides some text-related functions.
=head2 Functions
=over
=item addrencode ( $addr, [ $phrase, [ $charset, [ $comment ] ] ] )
Returns formatted (and encoded) name-addr as RFC5322 3.4.
=item canonic_email ( $email )
I<Function>.
Returns canonical form of e-mail address.
Leading and trailing white spaces are removed.
Latin letters without accents are lower-cased.
For malformed inputs returns C<undef>.
=item canonic_message_id ( $message_id )
Returns canonical form of message ID without trailing or leading whitespaces
or C<E<lt>>, C<E<gt>>.
=item canonic_text ( $text )
Canonicalizes text.
C<$text> should be a binary string encoded by UTF-8 character set or
a Unicode string.
Forbidden sequences in binary string will be replaced by
U+FFFD REPLACEMENT CHARACTERs, and Normalization Form C (NFC) will be applied.
=item decode_filesystem_safe ( $str )
I<Function>.
Decodes a string encoded by encode_filesystem_safe().
Parameter:
=over
=item $str
String to be decoded.
=back
Returns:
Decoded string, stripped C<utf8> flag if any.
=item decode_html ( $str )
I<Function>.
Decodes HTML entities in a string encoded by UTF-8 or a Unicode string.
Parameter:
=over
=item $str
String to be decoded.
=back
Returns:
Decoded string, stripped C<utf8> flag if any.
=item encode_filesystem_safe ( $str )
I<Function>.
Encodes a string $str to be suitable for filesystem.
Parameter:
=over
=item $str
String to be encoded.
=back
Returns:
Encoded string, stripped C<utf8> flag if any.
All bytes except C<'-'>, C<'+'>, C<'.'>, C<'@'>
and alphanumeric characters are encoded to sequences C<'_'> followed by
two hexdigits.
Note that C<'/'> will also be encoded.
=item encode_html ( $str, [ $additional_unsafe ] )
I<Function>.
Encodes characters in a string $str to HTML entities.
By default
C<'E<lt>'>, C<'E<gt>'>, C<'E<amp>'> and C<'E<quot>'> are encoded.
Parameter:
=over
=item $str
String to be encoded.
=item $additional_unsafe
Character or range of characters additionally encoded as entity references.
This optional parameter was introduced on Sympa 6.2.37b.3.
=back
Returns:
Encoded string, I<not> stripping utf8 flag if any.
=item encode_uri ( $str, [ omit => $chars ] )
I<Function>.
Encodes potentially unsafe characters in the string using "percent" encoding
suitable for URIs.
Parameters:
=over
=item $str
String to be encoded.
=item omit =E<gt> $chars
By default, all characters except those defined as "unreserved" in RFC 3986
are encoded, that is, C<[^-A-Za-z0-9._~]>.
If this parameter is given, it will prevent encoding additional characters.
=back
Returns:
Encoded string, stripped C<utf8> flag if any.
=item escape_chars ( $str )
Escape weird characters.
ToDo: This should be obsoleted in the future release: Would be better to use
L</encode_filesystem_safe>.
=item escape_url ( $str )
DEPRECATED.
Would be better to use L</"encode_uri"> or L</"mailtourl">.
=item foldcase ( $str )
I<Function>.
Returns "fold-case" string suitable for case-insensitive match.
For example, a code below looks for a needle in haystack not regarding case,
even if they are non-ASCII UTF-8 strings.
$haystack = Sympa::Tools::Text::foldcase($HayStack);
$needle = Sympa::Tools::Text::foldcase($NeedLe);
if (index $haystack, $needle >= 0) {
...
}
Parameter:
=over
=item $str
A string.
=back
=item guessed_to_utf8( $text, [ lang, ... ] )
I<Function>.
Guesses text charset considering language context
and returns the text reencoded by UTF-8.
Parameters:
=over
=item $text
Text to be reencoded.
=item lang, ...
Language tag(s) which may be given by L<Sympa::Language/"implicated_langs">.
=back
Returns:
Reencoded text.
If any charsets could not be guessed, C<iso-8859-1> will be used
as the last resort, just because it covers full range of 8-bit.
=item mailtourl ( $email, [ decode_html =E<gt> 1 ],
[ query =E<gt> {key =E<gt> val, ...} ] )
I<Function>.
Constructs a C<mailto:> URL for given e-mail.
Parameters:
=over
=item $email
E-mail address.
=item decode_html =E<gt> 1
If set, arguments are assumed to include HTML entities.
=item query =E<gt> {key =E<gt> val, ...}
Optional query.
=back
Returns:
Constructed URL.
=item pad ( $str, $width )
Pads space a string so that result will not be narrower than given width.
Parameters:
=over
=item $str
A string.
=item $width
If $width is false value or width of $str is not less than $width,
does nothing.
If $width is less than C<0>, pads right.
Otherwise, pads left.
=back
Returns:
Padded string.
=item qdecode_filename ( $filename )
Q-Decodes web file name.
ToDo:
This should be obsoleted in the future release: Would be better to use
L</decode_filesystem_safe>.
=item qencode_filename ( $filename )
Q-Encodes web file name.
ToDo:
This should be obsoleted in the future release: Would be better to use
L</encode_filesystem_safe>.
=item slurp ( $file )
Get entire content of the file.
Normalization by canonic_text() is applied.
C<$file> is the path to text file.
=item unescape_chars ( $str )
Unescape weird characters.
ToDo: This should be obsoleted in the future release: Would be better to use
L</decode_filesystem_safe>.
=item valid_email ( $string )
Basic check of an email address.
=item weburl ( $base, \@paths, [ decode_html =E<gt> 1 ],
[ fragment =E<gt> $fragment ], [ query =E<gt> \%query ] )
Constructs a C<http:> or C<https:> URL under given base URI.
Parameters:
=over
=item $base
Base URI.
=item \@paths
Additional path components.
=item decode_html =E<gt> 1
If set, arguments are assumed to include HTML entities.
Exception is $base:
It is assumed not to include entities.
=item fragment =E<gt> $fragment
Optional fragment.
=item query =E<gt> \%query
Optional query.
=back
Returns:
A URI.
=item wrap_text ( $text, [ $init_tab, [ $subsequent_tab, [ $cols ] ] ] )
I<Function>.
Returns line-wrapped text.
Parameters:
=over
=item $text
The text to be folded.
=item $init_tab
Indentation prepended to the first line of paragraph.
Default is C<''>, no indentation.
=item $subsequent_tab
Indentation prepended to each subsequent line of folded paragraph.
Default is C<''>, no indentation.
=item $cols
Max number of columns of folded text.
Default is C<78>.
=back
=back
=head1 HISTORY
L<Sympa::Tools::Text> appeared on Sympa 6.2a.41.
decode_filesystem_safe() and encode_filesystem_safe() were added
on Sympa 6.2.10.
decode_html(), encode_html(), encode_uri() and mailtourl()
were added on Sympa 6.2.14, and escape_url() was deprecated.
guessed_to_utf8() and pad() were added on Sympa 6.2.17.
canonic_text() and slurp() were added on Sympa 6.2.53b.
=cut

View File

@ -0,0 +1,327 @@
#!/usr/bin/perl
# -*- indent-tabs-mode: nil; -*-
# vim:ft=perl:et:sw=4
# $Id$
# Sympa - SYsteme de Multi-Postage Automatique
#
# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
#
# 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, see <http://www.gnu.org/licenses/>.
use lib '/usr/share/sympa/lib';
use strict;
use warnings;
use Getopt::Long;
use HTTP::Cookies;
#use SOAP::Lite +trace;
use SOAP::Lite;
use Sympa::Tools::Data;
my ($reponse, @ret, $val, %fault);
my $usage =
"$0 is a perl soap client for Sympa for TEST ONLY. Use it to illustrate how to
code access to features of Sympa soap server. Authentication can be done via
user/password or user cookie or as a trusted remote application
Usage: $0 <with the following options:>
--soap_url=<soap sympa server url>
--service=<a sympa service>
--trusted_application=<app name>
--trusted_application_password=<password>
--proxy_vars=<id=value,id2=value2>
--service_parameters=<value1,value2,value3>
OR usage: $0 <with the following options:>
--soap_url=<soap sympa server url>
--user_email=<email>
--user_password=<password>
--session_id=<sessionid>
--service=<a sympa service>
--service_parameters=<value1,value2,value3>
OR usage: $0 <with the following options:>
--soap_url=<soap sympa server url>
--cookie=<sympauser cookie string>
Example:
$0 --soap_url=<soap sympa server url> --cookie=sympauser=someone\@cru.fr
";
my %options;
unless (
GetOptions(
\%main::options, 'soap_url=s',
'service=s', 'trusted_application=s',
'trusted_application_password=s', 'user_email=s',
'user_password=s', 'cookie=s',
'proxy_vars=s', 'service_parameters=s',
'session_id=s'
)
) {
printf "";
}
my $soap_url = $main::options{'soap_url'};
unless (defined $soap_url) {
printf "error : missing soap_url parameter\n";
printf $usage;
exit 1;
}
my $user_email = $main::options{'user_email'};
my $user_password = $main::options{'user_password'};
my $session_id = $main::options{'session_id'};
my $trusted_application = $main::options{'trusted_application'};
my $trusted_application_password =
$main::options{'trusted_application_password'};
my $proxy_vars = $main::options{'proxy_vars'};
my $service = $main::options{'service'};
my $service_parameters = $main::options{'service_parameters'};
my $cookie = $main::options{'cookie'};
if (defined $trusted_application) {
unless (defined $trusted_application_password) {
printf "error : missing trusted_application_password parameter\n";
printf $usage;
exit 1;
}
unless (defined $service) {
printf "error : missing service parameter\n";
printf $usage;
exit 1;
}
unless (defined $proxy_vars) {
printf "error : missing proxy_vars parameter\n";
printf $usage;
exit 1;
}
play_soap_as_trusted($soap_url, $trusted_application,
$trusted_application_password, $service, $proxy_vars,
$service_parameters);
} elsif ($service eq 'getUserEmailByCookie') {
play_soap(
soap_url => $soap_url,
session_id => $session_id,
service => $service
);
} elsif (defined $cookie) {
printf "error : get_email_cookie\n";
get_email($soap_url, $cookie);
exit 1;
} else {
unless (defined $session_id
|| (defined $user_email && defined $user_password)) {
printf
"error : missing session_id OR user_email+user_passwors parameters\n";
printf $usage;
exit 1;
}
play_soap(
soap_url => $soap_url,
user_email => $user_email,
user_password => $user_password,
session_id => $session_id,
service => $service,
service_parameters => $service_parameters
);
}
sub play_soap_as_trusted {
my $soap_url = shift;
my $trusted_application = shift;
my $trusted_application_password = shift;
my $service = shift;
my $proxy_vars = shift;
my $service_parameters = shift;
my $soap = SOAP::Lite->new();
$soap->uri('urn:sympasoap');
$soap->proxy($soap_url);
my @parameters;
if (defined $service_parameters) {
@parameters = split /,/, $service_parameters;
} else {
@parameters = ();
}
my $p = join(',', @parameters);
printf
"calling authenticateRemoteAppAndRun( $trusted_application, $trusted_application_password, $proxy_vars,$service,$p)\n";
my $reponse =
$soap->authenticateRemoteAppAndRun($trusted_application,
$trusted_application_password, $proxy_vars, $service, \@parameters);
print_result($reponse);
}
sub get_email {
my $soap_url = shift;
my $cookie = shift;
my ($service, $reponse, @ret, $val, %fault);
## Cookies management
# my $uri = URI->new($soap_url);
# my $cookies = HTTP::Cookies->new(ignore_discard => 1,
# file => '/tmp/my_cookies' );
# $cookies->load();
printf "cookie : %s\n", $cookie;
my $soap = SOAP::Lite->new();
#$soap->on_debug(sub{print@_});
$soap->uri('urn:sympasoap');
$soap->proxy($soap_url);
#, cookie_jar =>$cookies);
print "\n\ngetEmailUserByCookie....\n";
$reponse = $soap->getUserEmailByCookie($cookie);
print_result($reponse);
exit;
}
sub play_soap {
my %param = @_;
my $soap_url = $param{'soap_url'};
my $user_email = $param{'user_email'};
my $user_password = $param{'user_password'};
my $session_id = $param{'session_id'};
my $service = $param{'service'};
my $service_parameters = $param{'service_parameters'};
my ($reponse, @ret, $val, %fault);
## Cookies management
# my $uri = URI->new($soap_url);
my $cookies = HTTP::Cookies->new(
ignore_discard => 1,
file => '/tmp/my_cookies'
);
$cookies->load();
printf "cookie : %s\n", $cookies->as_string();
my @parameters;
@parameters = split(/,/, $service_parameters)
if (defined $service_parameters);
my $p = join(',', @parameters);
foreach my $tmpParam (@parameters) {
printf "param: %s\n", $tmpParam;
}
# Change to the path of Sympa.wsdl
#$service = SOAP::Lite->service($soap_url);
#$reponse = $service->login($user_email,$user_password);
#my $soap = SOAP::Lite->service($soap_url);
my $soap = SOAP::Lite->new() || die;
#$soap->on_debug(sub{print@_});
$soap->uri('urn:sympasoap');
$soap->proxy($soap_url, cookie_jar => $cookies);
## Do the login unless a session_id is provided
if ($session_id) {
print "Using Session_id $session_id\n";
} else {
print "LOGIN....\n";
#$reponse = $soap->casLogin($soap_url);
$reponse = $soap->login($user_email, $user_password);
$cookies->save;
print_result($reponse);
$session_id = $reponse->result;
}
## Don't use authenticateAndRun for lists command
## Split parameters
if ($service_parameters && $service_parameters ne '') {
@parameters = split /,/, $service_parameters;
}
if ($service eq 'lists') {
printf "\n\nlists....\n";
$reponse = $soap->lists();
} elsif ($service eq 'subscribe') {
printf "\n\n$service....\n";
$reponse = $soap->subscribe(@parameters);
} elsif ($service eq 'signoff') {
printf "\n\n$service....\n";
$reponse = $soap->signoff(@parameters);
} elsif ($service eq 'add') {
printf "\n\n$service....\n";
$reponse = $soap->add(@parameters);
} elsif ($service eq 'del') {
printf "\n\n$service....\n";
$reponse = $soap->del(@parameters);
} elsif ($service eq 'getUserEmailByCookie') {
printf "\n\n$service....\n";
$reponse = $soap->getUserEmailByCookie($session_id);
} else {
printf "\n\nAuthenticateAndRun service=%s;(session_id=%s)....\n",
$service, $session_id;
$reponse =
$soap->authenticateAndRun($user_email, $session_id, $service,
\@parameters);
}
print_result($reponse);
}
sub print_result {
my $r = shift;
# If we get a fault
if (defined $r && $r->fault) {
print "Soap error :\n";
my %fault = %{$r->fault};
foreach $val (keys %fault) {
print "$val = $fault{$val}\n";
}
} else {
if (ref($r->result) =~ /^ARRAY/) {
#printf "R: $r->result\n";
@ret = @{$r->result};
} elsif (ref $r->result) {
print "Pb " . ($r->result) . "\n";
return undef;
} else {
@ret = $r->result;
}
Sympa::Tools::Data::dump_var(\@ret, 0, \*STDOUT);
}
return 1;
}

1851
dockers/apikaz/source/app.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<!-- silence is golden -->

View File

@ -0,0 +1,9 @@
flask
flask-restful
flask-mail
requests
flasgger
passlib
unidecode
email-validator
python-ldap

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,82 @@
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.email-content {
background-color: #f0f0f0; /* Light gray background */
margin: 20px auto;
padding: 20px;
border: 1px solid #dddddd;
max-width: 600px;
width: 90%; /* This makes the content take 90% width of its container */
text-align: left; /* Remove text justification */
}
header {
background-color: #E16969;
color: white;
text-align: center;
height: 50px; /* Fixed height for header */
line-height: 50px; /* Vertically center the text */
width: 100%; /* Make header full width */
}
footer {
background-color: #E16969;
color: white;
text-align: center;
height: 50px; /* Fixed height for footer */
line-height: 50px; /* Vertically center the text */
width: 100%; /* Make footer full width */
}
.header-container {
position: relative; /* Pour positionner le logo et le texte dans le header */
height: 50px; /* Hauteur maximale du header */
}
.logo {
position: absolute; /* Pour positionner le logo */
max-height: 100%; /* Taille maximale du logo égale à la hauteur du header */
top: 0; /* Aligner le logo en haut */
left: 0; /* Aligner le logo à gauche */
margin-right: 10px; /* Marge à droite du logo */
}
.header-container h1, .footer-container p {
margin: 0;
font-size: 24px;
}
.footer-container p {
font-size: 12px;
}
.footer-container a {
color: #FFFFFF; /* White color for links in footer */
text-decoration: none;
}
.footer-container a:hover {
text-decoration: underline; /* Optional: add underline on hover */
}
a {
color: #E16969; /* Same color as header/footer background for all other links */
text-decoration: none;
}
a:hover {
text-decoration: underline; /* Optional: add underline on hover */
}
h2 {
color: #E16969;
}
p {
line-height: 1.6;
}

View File

@ -0,0 +1,9 @@
<footer>
<div class="footer-container">
<p>
&copy; {{ now().year }} Kaz. Ici, on prend soin de vos données et on ne les vend pas !
<br>
<a href="https://kaz.bzh">https://kaz.bzh</a>
</p>
</div>
</footer>

View File

@ -0,0 +1,6 @@
<header>
<div class="header-container">
<img class="logo" src="https://kaz-cloud.kaz.bzh/apps/theming/image/logo?v=33" alt="KAZ Logo">
<h1>Kaz : Le numérique sobre, libre, éthique et local</h1>
</div>
</header>

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email d'inscription'</title>
<style>
{% include 'email.css' %}
</style>
</head>
<body>
{% include 'email_header.html' %}
<div class="email-content">
<p>
Bonjour {{NOM}}!<br><br>
Bienvenue chez KAZ!<br><br>
Vous disposez de :
<ul>
<li>une messagerie classique : <a href={{URL_WEBMAIL}}>{{URL_WEBMAIL}}</a></li>
<li>une messagerie instantanée pour discuter au sein d'équipes : <a href={{URL_AGORA}}>{{URL_AGORA}}</a></li>
</ul>
Votre email et identifiant pour ces services : {{EMAIL_SOUHAITE}}<br>
Le mot de passe : <b>{{PASSWORD}}</b><br><br>
Pour changer votre mot de passe de messagerie, c'est ici: <a href={{URL_MDP}}>{{URL_MDP}}</a><br>
Si vous avez perdu votre mot de passe, c'est ici: <a href={{URL_MDP}}/?action=sendtoken>{{URL_MDP}}/?action=sendtoken</a><br><br>
Vous pouvez accéder à votre messagerie classique:
<ul>
<li>soit depuis votre webmail : <a href={{URL_WEBMAIL}}>{{URL_WEBMAIL}}</a></li>
<li>soit depuis votre bureau virtuel : <a href={{URL_CLOUD}}>{{URL_CLOUD}}</a></li>
<li>soit depuis un client de messagerie comme thunderbird<br>
</ul>
</p>
{% if ADMIN_ORGA == '1' %}
<p>
En tant qu'association/famille/société. Vous avez la possibilité d'ouvrir, quand vous le voulez, des services kaz, il vous suffit de nous le demander.<br><br>
Pourquoi n'ouvrons-nous pas tous les services tout de suite ? parce que nous aimons la sobriété et que nous préservons notre espace disque ;)<br>
A quoi sert d'avoir un site web si on ne l'utilise pas, n'est-ce pas ?<br><br>
Par retour de mail, dites-nous de quoi vous avez besoin tout de suite entre:
<ul>
<li>une comptabilité : un service de gestion adhérents/clients</li>
<li>un site web de type WordPress</li>
<li>un cloud : bureau virtuel pour stocker des fichiers/calendriers/contacts et partager avec vos connaissances</li>
</ul>
Une fois que vous aurez répondu à ce mail, votre demande sera traitée manuellement.
</p>
{% endif %}
<p>
Vous avez quelques docs intéressantes sur le wiki de kaz:
<ul>
<li>Migrer son site internet wordpress vers kaz : <a href="https://wiki.kaz.bzh/wordpress/start#migrer_son_site_wordpress_vers_kaz">https://wiki.kaz.bzh/wordpress/start#migrer_son_site_wordpress_vers_kaz</a></li>
<li>Migrer sa messagerie vers kaz : <a href="https://wiki.kaz.bzh/messagerie/gmail/start">https://wiki.kaz.bzh/messagerie/gmail/start</a></li>
<li>Démarrer simplement avec son cloud : <a href="https://wiki.kaz.bzh/nextcloud/start">https://wiki.kaz.bzh/messagerie/gmail/start</a></li>
</ul>
Votre quota est de {{QUOTA}}GB. Si vous souhaitez plus de place pour vos fichiers ou la messagerie, faites-nous signe !<br><br>
Pour accéder à la messagerie instantanée et communiquer avec les membres de votre équipe ou ceux de kaz : <a href={{URL_AGORA}}/login>{{URL_AGORA}}/login</a><br>
</p>
{% if ADMIN_ORGA == '1' %}
<p>
Comme administrateur de votre organisation, vous pouvez créer des listes de diffusion en vous rendant sur <a href={{URL_LISTE}}>{{URL_LISTE}}</a><br>
</p>
{% endif %}
<p>
Enfin, vous disposez de tous les autres services KAZ où l'authentification n'est pas nécessaire : <a href={{URL_SITE}}>{{URL_SITE}}</a><br><br>
En cas de soucis, n'hésitez pas à poser vos questions sur le canal 'Une question ? un soucis' de l'agora dispo ici : <a href={{URL_AGORA}}>{{URL_AGORA}}</a><br><br>
Si vous avez besoin d'accompagnement pour votre site, votre cloud, votre compta, votre migration de messagerie,...<br>nous proposons des formations mensuelles gratuites. Si vous souhaitez être accompagné par un professionnel, nous pouvons vous donner une liste de pros, référencés par KAZ.<br><br>
À bientôt 😉<br><br>
La collégiale de KAZ.<br>
</p>
</div> <!-- <div class="email-content"> -->
{% include 'email_footer.html' %}
</body>
</html>