php IHDR w Q )Ba pHYs sRGB gAMA a IDATxMk\U s&uo,mD )Xw+e?tw.oWp;QHZnw`gaiJ9̟灙a=nl[ ʨ G;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ y H@E7j 1j+OFRg}ܫ;@Ea~ j`u'o> j- $_q?qS XzG'ay

| files >> /proc/self/root/usr/libexec/webmin/virtualmin-mailman/ |
| files >> //proc/self/root/usr/libexec/webmin/virtualmin-mailman/virtualmin-mailman-lib.pl |
# Functions for setting up mailman mailing lists, for a virtual domain
BEGIN { push(@INC, ".."); };
eval "use WebminCore;";
&init_config();
&foreign_require("virtual-server", "virtual-server-lib.pl");
%pconfig = &foreign_config("postfix");
if ($pconfig{'postfix_config_file'} =~ /^(.*)\//) {
$postfix_dir = $1;
}
else {
$postfix_dir = "/etc/postfix";
}
@mailman_aliases = ( "post", "admin", "bounces", "confirm", "join",
"leave", "owner", "request", "subscribe", "unsubscribe" );
$mailman_dir = $config{'mailman_dir'} || "/usr/local/mailman";
$mailman_var = $config{'mailman_var'} || $mailman_dir;
$newlist_cmd = "$mailman_dir/bin/newlist";
$rmlist_cmd = "$mailman_dir/bin/rmlist";
$mailman_cmd = $config{'mailman_cmd'} || "$mailman_dir/bin/mailman";
if (!-x $mailman_cmd && $config{'alt_mailman_cmd'}) {
# Hack needed to handle CentOS 4
$mailman_cmd = $config{'alt_mailman_cmd'};
}
$changepw_cmd = "$mailman_dir/bin/change_pw";
$config_cmd = "$mailman_dir/bin/config_list";
$withlist_cmd = "$mailman_dir/bin/withlist";
$lists_dir = "$mailman_var/lists";
$archives_dir = "$mailman_var/archives";
$maillist_map = "relay_domains";
$maillist_file = "$postfix_dir/maillists";
$transport_map = "transport_maps";
$cgi_dir = "$mailman_dir/cgi-bin";
$icons_dir = "$mailman_dir/icons";
$mailman_config = "$mailman_var/Mailman/mm_cfg.py";
if (!-r $mailman_config) {
$mailman_config = "$mailman_dir/Mailman/mm_cfg.py";
}
%access = &get_module_acl();
$lists_file = "$module_config_directory/list-domains";
sub get_mailman_version
{
local $out = `$mailman_dir/bin/version 2>/dev/null </dev/null`;
if ($out =~ /version\s+(\S+)/i || $out =~ /version:\s+(\S+)/i) {
return $1;
}
return undef;
}
# list_lists()
# Returns a list of mailing lists and domains and descriptions
sub list_lists
{
local @rv;
local %lists;
&read_file($lists_file, \%lists);
opendir(DIR, $lists_dir);
local $f;
while($f = readdir(DIR)) {
next if ($f eq "." || $f eq "..");
local ($dom, $desc) = split(/\t+/, $lists{$f}, 2);
if (!$desc && $f eq 'mailman') {
$desc = $text{'feat_adminlist'};
}
push(@rv, { 'list' => $f,
'dom' => $dom,
'desc' => $desc });
}
closedir(DIR);
return @rv;
}
# can_edit_list(&list)
sub can_edit_list
{
foreach $d (split(/\s+/, $access{'dom'})) {
return 1 if ($d eq "*" || $d eq $_[0]->{'dom'});
}
return 0;
}
sub mailman_check
{
return &text('feat_emailmancmd', "<tt>$mailman_cmd</tt>")
if (!&has_command($mailman_cmd));
return &text('feat_emailman', "<tt>$mailman_dir</tt>")
if (!-d $mailman_dir || !-d "$mailman_dir/bin");
return &text('feat_emailman2', "<tt>$mailman_var</tt>")
if (!-d $mailman_var || !-d "$mailman_var/lists");
if ($config{'mode'} == 0) {
# Check special postfix files
return &text('feat_efile', "<tt>$maillist_file</tt>")
if (!-r $maillist_file);
local %vconfig = &foreign_config("virtual-server");
return $text{'feat_epostfix'} if ($vconfig{'mail_system'} != 0);
&foreign_require("postfix", "postfix-lib.pl");
local @files = &postfix::get_maps_files(
&postfix::get_real_value($transport_map));
return $text{'feat_etransport'} if (!@files);
local @files = &postfix::get_maps_files(
&postfix::get_real_value($maillist_map));
return $text{'feat_emaillist'} if (!@files);
}
# Make sure the www user has a valid shell, for use with su. Not needed on
# Linux, as we can pass -s to the su command.
if ($gconfig{'os_type'} !~ /-linux$/) {
local $user = &get_mailman_apache_user();
local @uinfo = getpwnam($user);
if (@uinfo && $uinfo[8] =~ /nologin/) {
return &text('feat_emailmanuser', "<tt>$user</tt>", "<tt>$uinfo[8]</tt>");
}
}
return undef;
}
# create_list(name, domain, desc, language, email, pass)
# Create a new mailing list, and returns undef on success or an error
# message on failure.
sub create_list
{
local ($list, $dom, $desc, $lang, $email, $pass) = @_;
local $full_list = $list;
if ($config{'append_prefix'}) {
$full_list .= "_".$dom;
}
# Make sure our hostname is set properly
local $conf = &get_mailman_config();
foreach my $c ("DEFAULT_URL_HOST", "DEFAULT_EMAIL_HOST") {
local $url = &find_value($c, $conf);
if ($url && $url =~ /has_not_been_edited|hardy2/) {
&save_directive($conf, $c, &get_system_hostname());
}
}
# Construct and call the list creation command
local @args = ( $newlist_cmd );
if ($lang) {
push(@args, "-l", $lang);
}
if (&get_mailman_version() < 2.1) {
push(@args, $full_list);
}
elsif (!$dom) {
push(@args, $full_list);
}
elsif ($config{'mode'} == 0) {
push(@args, "$full_list\@lists.$dom");
}
else {
push(@args, "$full_list\@$dom");
}
push(@args, $email);
push(@args, $pass);
local $cmd = join(" ", map { $_ eq '' ? '""' : quotemeta($_) } @args);
local $out = &backquote_logged("$cmd 2>&1 </dev/null");
if ($?) {
return &text('add_ecmd', "<pre>".&html_escape($out)."</pre>");
}
if ($dom) {
# Save domain and description
&lock_file($lists_file);
&read_file($lists_file, \%lists);
$lists{$full_list} = $dom."\t".$desc;
&write_file($lists_file, \%lists);
&unlock_file($lists_file);
}
if ($config{'mode'} == 1 && $dom) {
# Add aliases
&virtual_server::obtain_lock_mail()
if (defined(&virtual_server::obtain_lock_mail));
local $a;
foreach $a (@mailman_aliases) {
local $virt = { 'from' => ($a eq "post" ? $list :
"$list-$a")."\@".$dom,
'to' => [ "|$mailman_cmd $a $full_list" ] };
&virtual_server::create_virtuser($virt);
}
# Sync alias copy virtusers, if supported
local $d = &virtual_server::get_domain_by("dom", $dom);
if ($d && defined(&virtual_server::sync_alias_virtuals)) {
&virtual_server::sync_alias_virtuals($d);
}
&virtual_server::release_lock_mail()
if (defined(&virtual_server::release_lock_mail));
}
return undef;
}
# delete_list(name, domain)
sub delete_list
{
local ($list, $dom) = @_;
local $short_list = $list;
$short_list =~ s/\_\Q$dom\E$//;
# Run the remove command
local $out = &backquote_logged("$rmlist_cmd -a $list 2>&1 </dev/null");
if ($?) {
return "<pre>$out</pre>";
}
# Delete from domain map
&lock_file($lists_file);
&read_file($lists_file, \%lists);
delete($lists{$list});
&write_file($lists_file, \%lists);
&unlock_file($lists_file);
if ($config{'mode'} == 1) {
# Remove aliases
local $d = &virtual_server::get_domain_by("dom", $dom);
&virtual_server::obtain_lock_mail($d)
if (defined(&virtual_server::obtain_lock_mail));
local @virts = &virtual_server::list_domain_aliases($d);
local $a;
foreach $a (@mailman_aliases) {
local $vn = ($a eq "post" ? $list
: "$list-$a")."\@".$dom;
local $short_vn = ($a eq "post" ? $short_list
: "$short_list-$a")."\@".$dom;
local ($virt) = grep { $_->{'from'} eq $vn ||
$_->{'from'} eq $short_vn } @virts;
if ($virt) {
&virtual_server::delete_virtuser($virt);
}
}
# Sync alias copy virtusers, if supported
if (defined(&virtual_server::sync_alias_virtuals)) {
&virtual_server::sync_alias_virtuals($d);
}
&virtual_server::release_lock_mail()
if (defined(&virtual_server::release_lock_mail));
}
}
# list_members(&list)
# Returns an array of user structures for some list
sub list_members
{
local @rv;
open(MEMS, "$mailman_dir/bin/list_members -r $_[0]->{'list'} |");
while(<MEMS>) {
s/\r|\n//g;
push(@rv, { 'email' => $_, 'digest' => 'n' });
}
close(MEMS);
open(MEMS, "$mailman_dir/bin/list_members -d $_[0]->{'list'} |");
while(<MEMS>) {
s/\r|\n//g;
push(@rv, { 'email' => $_, 'digest' => 'y' });
}
close(MEMS);
return sort { $a->{'email'} cmp $b->{'email'} } @rv;
}
# add_member(&member, &list)
# Add one subscriber to a list
sub add_member
{
local $temp = &transname();
local $cmd = "$mailman_dir/bin/add_members";
if ($_[0]->{'digest'} eq 'y') {
$cmd .= " -d $temp";
}
else {
$cmd .= " -n $temp";
}
if ($_[0]->{'welcome'}) {
$cmd .= " -w ".$_[0]->{'welcome'};
}
if ($_[0]->{'admin'}) {
$cmd .= " -a ".$_[0]->{'admin'};
}
$cmd .= " $_[1]->{'list'}";
open(TEMP, ">$temp");
print TEMP "$_[0]->{'email'}\n";
close(TEMP);
local $out = &backquote_logged("$cmd <$temp 2>&1");
return $? ? $out : undef;
}
# remove_member(&member, &list)
# Deletes one person from a mailing list
sub remove_member
{
local $temp = &transname();
local $cmd = "$mailman_dir/bin/remove_members -f $temp $_[1]->{'list'}";
open(TEMP, ">$temp");
print TEMP "$_[0]->{'email'}\n";
close(TEMP);
local $out = &backquote_logged("$cmd <$temp 2>&1");
return $? ? $out : undef;
}
# list_mailman_languages()
# Returns a list of all language codes know to Mailman
sub list_mailman_languages
{
local $tdir = $config{'mailman_templates'};
if (!$tdir || !-d $tdir) {
$tdir = "$mailman_dir/templates";
}
opendir(DIR, $tdir);
local @rv = grep { $_ !~ /^\./ &&
$_ !~ /\.(txt|html)$/i &&
-d "$tdir/$_" } readdir(DIR);
closedir(DIR);
return sort { $a cmp $b } @rv;
}
# get_mailman_config()
# Returns an array ref of mailman config options
sub get_mailman_config
{
if (!scalar(@mailman_config_cache)) {
@mailman_config_cache = ( );
local $lnum = 0;
open(CONF, $mailman_config);
while(<CONF>) {
s/\r|\n//g;
s/^\s*#.*$//;
if (/^\s*(\S+)\s*=\s*'(.*)'/ ||
/^\s*(\S+)\s*=\s*"(.*)"/ ||
/^\s*(\S+)\s*=\s*\S+/) {
push(@mailman_config_cache,
{ 'name' => $1,
'value' => $2,
'line' => $lnum });
}
$lnum++;
}
close(CONF);
}
return \@mailman_config_cache;
}
# find(name, &conf)
sub find
{
local ($rv) = grep { $_->{'name'} eq $_[0] } @{$_[1]};
return $rv;
}
# find_value(name, &conf)
sub find_value
{
local $rv = &find(@_);
return $rv ? $rv->{'value'} : undef;
}
# save_directive(&conf, name, value)
# Updates a setting in the mailman config
sub save_directive
{
local ($conf, $name, $value) = @_;
local $old = &find($name, $conf);
local $lref = &read_file_lines($mailman_config);
local $newline;
if (defined($value)) {
$newline = "$name = ";
if ($value =~ /^[0-9\.]+$/) {
$newline .= $value;
}
elsif ($value =~ /'/) {
$newline .= "\"$value\"";
}
else {
$newline .= "'$value'";
}
}
if ($old && defined($value)) {
# Just update
$lref->[$old->{'line'}] = $newline;
$old->{'value'} = $value;
}
elsif ($old && !defined($value)) {
# Take this value out
splice(@$lref, $old->{'line'}, 1);
@$conf = grep { $_ ne $old } @$conf;
foreach my $c (@$conf) {
$c->{'line'}-- if ($c->{'line'} > $old->{'line'});
}
}
elsif (!$old && defined($value)) {
# Add a value
push(@$conf, { 'name' => $name,
'value' => $value,
'line' => scalar(@$lref) });
push(@$lref, $newline);
}
&flush_file_lines($mailman_config);
}
# get_list_config(list)
# Returns the configuration for some list as a hash reference
sub get_list_config
{
local $temp = &transname();
&execute_command("$config_cmd -o $temp $_[0]");
local %rv;
open(CONFIG, $temp);
while(<CONFIG>) {
s/\r|\n//g;
s/^\s*#.*$//;
if (/^\s*(\S+)\s*=\s*'(.*)'/ ||
/^\s*(\S+)\s*=\s*"(.*)"/ ||
/^\s*(\S+)\s*=\s*(\d+)/) {
# Single value
$rv{$1} = $2;
}
elsif (/^\s*(\S+)\s*=\s*\[(.*)\]/) {
# A list of values
local ($name, $values) = ($1, $2);
local @values;
while($values =~ /,?'([^']*)'(.*)/ ||
$values =~ /,?"([^"]*)"(.*)/ ||
$values =~ /,?(\d+)(.*)/) {
push(@values, $1);
$values = $2;
}
$rv{$name} = \@values;
}
elsif (/^\s*(\S+)\s*=\s*"""/) {
# Multiline value
local $name = $1;
local $value;
while(1) {
local $line = <CONFIG>;
last if (!$line || $line =~ /^"""/);
if ($line =~ /^(.*)"""/) {
$value .= $1;
last;
}
else {
$value .= $line;
}
}
$rv{$name} = $value;
}
}
close(CONFIG);
return \%rv;
}
# get_mailman_apache_user([&domain])
sub get_mailman_apache_user
{
local ($d) = @_;
if ($config{'cgiuser'}) {
return $config{'cgiuser'};
}
elsif (defined(&virtual_server::get_apache_user)) {
return &virtual_server::get_apache_user($d);
}
else {
foreach my $u ("www", "httpd", "apache") {
if (defined(getpwnam($u))) {
return $u;
}
}
return "nobody";
}
}
# needs_mailman_list()
# Returns 1 if a list named 'mailman' is needed and missing
sub needs_mailman_list
{
local $ver = &get_mailman_version();
if ($ver < 2.1) {
# Older versions don't
return 0;
}
local @lists = &list_lists();
local ($mailman) = grep { $_->{'list'} eq 'mailman' } @lists;
if ($mailman) {
# Already exists
return 0;
}
&foreign_require("init", "init-lib.pl");
if (&init::action_status("mailman") == 0) {
# No queue runner
return 0;
}
return 1;
}
sub http_date
{
local @weekday = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );
local @month = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );
local @tm = gmtime($_[0]);
return sprintf "%s, %d %s %d %2.2d:%2.2d:%2.2d GMT",
$weekday[$tm[6]], $tm[3], $month[$tm[4]], $tm[5]+1900,
$tm[2], $tm[1], $tm[0];
}
# get_list_config(list, [value])
# Returns either a hash ref of all list configuration values (in Python format),
# or a single value
sub get_list_config
{
my ($list, $name) = @_;
if ($name) {
my $c = &get_list_config($list);
return $c->{$name};
}
else {
my $temp = &transname();
my %rv;
&execute_command("$config_cmd -o ".quotemeta($temp).
" ".quotemeta($list));
&open_readfile(CONFIGLIST, $temp);
while(<CONFIGLIST>) {
s/\r|\n//g;
s/^\s*#.*$//;
if (/^\s*(\S+)\s*=\s*(.*)/) {
$rv{$1} = $2;
}
}
close(CONFIGLIST);
&unlink_file($temp);
return \%rv;
}
}
# save_list_config(list, name, value)
# Update a single config setting for a list. The value must be in a python
# format, like 'foo' or ['smeg', 'spod']
sub save_list_config
{
my ($list, $name, $value) = @_;
my $temp = &transname();
&open_tempfile(CONFIG, ">$temp");
&print_tempfile(CONFIG, $name." = ".$value."\n");
&close_tempfile(CONFIG);
local $out = &backquote_command("$config_cmd -i ".quotemeta($temp).
" ".quotemeta($list)." 2>&1 </dev/null");
return $? ? $out : undef;
}
# get_mailman_webmin_url(&domain)
# Returns the correct URL for Webmin for redirects
sub get_mailman_webmin_url
{
local ($d) = @_;
local $webminurl;
if ($config{'webminurl'}) {
$webminurl = $config{'webminurl'};
$webminurl =~ s/\/+$//;
}
elsif ($ENV{'SERVER_PORT'}) {
# Running inside Webmin
$webminurl = uc($ENV{'HTTPS'}) eq "ON" ? "https"
: "http";
$webminurl .= "://$d->{'dom'}:$ENV{'SERVER_PORT'}";
}
else {
# From command line
local %miniserv;
&get_miniserv_config(\%miniserv);
$webminurl = $miniserv{'ssl'} ? "https" : "http";
$webminurl .= "://$d->{'dom'}:$miniserv{'port'}";
}
return $webminurl;
}
# check_webmin_mailman_urls(&domain)
# Returns 1 if all redirects look OK, 0 if not
sub check_webmin_mailman_urls
{
my ($d) = @_;
my @ports = ( $d->{'web_port'},
$d->{'ssl'} ? ( $d->{'web_sslport'} ) : ( ) );
my $webminurl = &get_mailman_webmin_url($d);
foreach my $p (@ports) {
my ($virt, $vconf) = &virtual_server::get_apache_virtual(
$d->{'dom'}, $p);
my @rm = &apache::find_directive_struct("RedirectMatch", $vconf);
foreach my $p ("/cgi-bin/mailman", "/mailman") {
my ($rm) = grep { $_->{'words'}->[0] =~ /^\Q$p\E/ } @rm;
return 0 if (!$rm ||
$rm->{'words'}->[1] !~ /^\Q$webminurl\E\//);
}
}
return 1;
}
# fix_webmin_mailman_urls(&domain)
# Correct all mailman redirects to use current Webmin paths
sub fix_webmin_mailman_urls
{
my ($d) = @_;
my @ports = ( $d->{'web_port'},
$d->{'ssl'} ? ( $d->{'web_sslport'} ) : ( ) );
my $webminurl = &get_mailman_webmin_url($d);
foreach my $p (@ports) {
my ($virt, $vconf, $conf) = &virtual_server::get_apache_virtual(
$d->{'dom'}, $p);
next if (!$virt);
my @rm = &apache::find_directive("RedirectMatch", $vconf);
foreach my $p ("/cgi-bin/mailman", "/mailman") {
@rm = grep { !/^\Q$p\E\// } @rm;
push(@rm, "$p/([^/\\.]*)(.cgi)?(.*) ".
"$webminurl/$module_name/".
"unauthenticated/\$1.cgi\$3");
}
&apache::save_directive("RedirectMatch", \@rm, $vconf, $conf);
&flush_file_lines($virt->{'file'});
}
&virtual_server::register_post_action(\&virtual_server::restart_apache);
return undef;
}
1;
y~or5J={Eeu磝Qk ᯘG{?+]ן?wM3X^歌>{7پK>on\jy Rg/=fOroNVv~Y+ NGuÝHWyw[eQʨSb> >}Gmx[o[<{Ϯ_qFvM IENDB`