1# -*- indent-tabs-mode: nil; -*-
2# vim:ft=perl:et:sw=4
3# $Id$
4
5# Sympa - SYsteme de Multi-Postage Automatique
6#
7# Copyright 2017, 2018 The Sympa Community. See the AUTHORS.md file at the
8# top-level directory of this distribution and at
9# <https://github.com/sympa-community/sympa.git>.
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
24package Sympa::Aliases;
25
26use strict;
27use warnings;
28use English qw(-no_match_vars);
29
30use Conf;
31use Sympa::Constants;
32use Sympa::List;
33use Sympa::Log;
34use Sympa::Regexps;
35
36my $log = Sympa::Log->instance;
37
38# Sympa::Aliases is the proxy class of subclasses.
39# The constructor may be overridden by _new() method.
40sub new {
41    my $class   = shift;
42    my $type    = shift;
43    my %options = @_;
44
45    return undef unless $type;
46
47    # Special cases:
48    # - To disable aliases management, specify "none" as $type.
49    # - "External" module is used for full path to program.
50    # - However, "Template" module is used instead of obsoleted program
51    #   alias_manager.pl.
52    return $class->_new if $type eq 'none';
53
54    if ($type eq Sympa::Constants::SBINDIR() . '/alias_manager.pl') {
55        $type = 'Sympa::Aliases::Template';
56    } elsif (0 == index $type, '/' and -x $type) {
57        $options{program} = $type;
58        $type = 'Sympa::Aliases::External';
59    }
60
61    # Returns appropriate subclasses.
62    if ($type !~ /[^\w:]/) {
63        $type = sprintf 'Sympa::Aliases::%s', $type unless $type =~ /::/;
64        unless (eval sprintf('require %s', $type)
65            and $type->isa('Sympa::Aliases')) {
66            $log->syslog(
67                'err', 'Unable to use %s module: %s',
68                $type, $EVAL_ERROR || 'Not a Sympa::Aliases class'
69            );
70            return undef;
71        }
72        return $type->_new(%options);
73    }
74
75    return undef;
76}
77
78sub _new {
79    my $class   = shift;
80    my %options = @_;
81
82    return bless {%options} => $class;
83}
84
85sub check {0}
86
87sub add {0}
88
89sub del {0}
90
91# Check listname.
92sub check_new_listname {
93    my $listname = shift;
94    my $robot_id = shift;
95
96    unless (defined $listname and length $listname) {
97        $log->syslog('err', 'No listname');
98        return ('user', 'listname_needed');
99    }
100
101    $listname = lc $listname;
102
103    my $listname_re = Sympa::Regexps::listname();
104    unless (defined $listname
105        and $listname =~ /^$listname_re$/i
106        and length $listname <= Sympa::Constants::LIST_LEN()) {
107        $log->syslog('err', 'Incorrect listname %s', $listname);
108        return ('user', 'incorrect_listname', {bad_listname => $listname});
109    }
110
111    my $regx = Conf::get_robot_conf($robot_id, 'list_check_regexp');
112    if ($regx) {
113        if ($listname =~ /^(\S+)-($regx)$/) {
114            $log->syslog('err',
115                'Incorrect listname %s matches one of service aliases',
116                $listname);
117            return ('user', 'listname_matches_aliases',
118                {new_listname => $listname});
119        }
120    }
121
122    # Avoid "sympa", "listmaster", "bounce" and "bounce+XXX".
123    if (   $listname eq Conf::get_robot_conf($robot_id, 'email')
124        or $listname eq Conf::get_robot_conf($robot_id, 'listmaster_email')
125        or $listname eq Conf::get_robot_conf($robot_id, 'bounce_email_prefix')
126        or 0 == index(
127            $listname,
128            Conf::get_robot_conf($robot_id, 'bounce_email_prefix') . '+'
129        )
130    ) {
131        $log->syslog('err',
132            'Incorrect listname %s matches one of service aliases',
133            $listname);
134        return ('user', 'listname_matches_aliases',
135            {new_listname => $listname});
136    }
137
138    # Check listname on SMTP server.
139    my $aliases =
140        Sympa::Aliases->new(Conf::get_robot_conf($robot_id, 'alias_manager'));
141    my $res = $aliases->check($listname, $robot_id) if $aliases;
142    unless (defined $res) {
143        $log->syslog('err', 'Can\'t check list %.128s on %s',
144            $listname, $robot_id);
145        return ('intern');
146    }
147
148    # Check this listname doesn't exist already.
149    if ($res or Sympa::List->new($listname, $robot_id, {'just_try' => 1})) {
150        $log->syslog('err',
151            'Could not create list %s: list on %s already exist',
152            $listname, $robot_id);
153        return ('user', 'list_already_exists', {new_listname => $listname});
154    }
155
156    return;
157}
158
1591;
160__END__
161
162=encoding utf-8
163
164=head1 NAME
165
166Sympa::Aliases - Base class for alias management
167
168=head1 SYNOPSIS
169
170  package Sympa::Aliases::FOO;
171
172  use base qw(Sympa::Aliases);
173
174  sub check { ... }
175  sub add { ... }
176  sub del { ... }
177
178  1;
179
180=head1 DESCRIPTION
181
182This module is the base class for subclasses to manage list aliases of Sympa.
183
184=head2 Methods
185
186=over
187
188=item new ( $type, [ key =E<gt> value, ... ] )
189
190I<Constructor>.
191Creates new instance of L<Sympa::Aliases>.
192
193Returns one of appropriate subclasses according to $type:
194
195=over
196
197=item C<'none'>
198
199No aliases management.
200
201=item Full path to executable
202
203Use external program to manage aliases.
204See L<Sympa::Aliases::External>.
205
206=item Name of subclass
207
208Use a subclass C<Sympa::Aliases::I<name>> to manage aliases.
209
210=back
211
212For invalid types returns C<undef>.
213
214Note:
215For compatibility to the earlier versions of Sympa,
216if a string C<SBINDIR/alias_manager.pl> was given as $type,
217L<Sympa::Aliases::Template> subclass will be used.
218
219Optional C<I<key> =E<gt> I<value>> pairs are included in the instance as
220hash entries.
221
222=item check ($listname, $robot_id)
223
224I<Instance method>, I<overridable>.
225Checks if the addresses of requested list exist already.
226
227Parameters:
228
229=over
230
231=item $listname
232
233Name of the list.
234Mandatory.
235
236=item $robot_id
237
238List's robot.
239
240=back
241
242Returns:
243
244True value if one of addresses exists.
245C<0> if none found.
246C<undef> if something wrong happened.
247
248By default, this method always returns C<0>.
249
250=item add ($list)
251
252I<Instance method>, I<overridable>.
253Installs aliases for the list $list.
254
255Parameters:
256
257=over
258
259=item $list
260
261An instance of L<Sympa::List>.
262
263=back
264
265Returns:
266
267C<1> if installation succeeded.
268C<0> if there were no aliases to be installed.
269C<undef> if not applicable.
270
271By default, this method always returns C<0>.
272
273=item del ($list)
274
275I<Instance method>, I<overridable>.
276Removes aliases for the list $list.
277
278Parameters:
279
280=over
281
282=item $list
283
284An instance of L<Sympa::List>.
285
286=back
287
288Returns:
289
290C<1> if removal succeeded.
291C<0> if there were no aliases to be removed.
292C<undef> if not applicable.
293
294By default, this method always returns C<0>.
295
296=back
297
298=head2 Function
299
300=over
301
302=item check_new_listname ( $listname, $robot )
303
304I<Function>.
305Checks if a new listname is allowed.
306
307TBD.
308
309Parameteres:
310
311=over
312
313=item $listname
314
315A list name to be checked.
316
317=item $robot
318
319Robot context.
320
321=back
322
323Returns:
324
325If check fails, an array including information of errors.
326If it succeeds, empty array.
327
328B<Note>:
329This should be used to check name of list to be created.
330Names of existing lists may not necessarily pass checks by this function.
331
332This function was added on Sympa 6.2.37b.2.
333
334=back
335
336=head1 SEE ALSO
337
338L<Sympa::Aliases::CheckSMTP>,
339L<Sympa::Aliases::External>,
340L<Sympa::Aliases::Template>.
341
342=head1 HISTORY
343
344F<alias_manager.pl> as a program to automate alias management appeared on
345Sympa 3.1b.13.
346
347L<Sympa::Aliases> module as an OO-based class appeared on Sympa 6.2.23b,
348and it obsoleted F<alias_manager.pl>.
349
350=cut 
351