1#!--PERL--
2# -*- indent-tabs-mode: nil; -*-
3# vim:ft=perl:et:sw=4
4# $Id$
5
6# Sympa - SYsteme de Multi-Postage Automatique
7#
8# Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
9# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
10# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
11# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
12# Copyright 2017, 2018, 2019 The Sympa Community. See the AUTHORS.md file at
13# the top-level directory of this distribution and at
14# <https://github.com/sympa-community/sympa.git>.
15#
16# This program is free software; you can redistribute it and/or modify
17# it under the terms of the GNU General Public License as published by
18# the Free Software Foundation; either version 2 of the License, or
19# (at your option) any later version.
20#
21# This program is distributed in the hope that it will be useful,
22# but WITHOUT ANY WARRANTY; without even the implied warranty of
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24# GNU General Public License for more details.
25#
26# You should have received a copy of the GNU General Public License
27# along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
29## Worl Wide Sympa is a front-end to Sympa Mailing Lists Manager
30## Copyright Comite Reseau des Universites
31
32## Patch 2001.07.24 by nablaphi <nablaphi@bigfoot.com>
33## Change the Getopt::Std to Getopt::Long
34
35use lib split(/:/, $ENV{SYMPALIB} || ''), '--modulesdir--';
36use strict;
37use warnings;
38use English qw(-no_match_vars);
39use Getopt::Long;
40use Pod::Usage;
41use POSIX qw();
42
43use Conf;
44use Sympa::Constants;
45use Sympa::Crash;    # Show traceback.
46use Sympa::DatabaseManager;
47use Sympa::Log;
48use Sympa::Process;
49use Sympa::Spindle::ProcessBounce;
50use Sympa::Spool::Listmaster;
51
52my $process = Sympa::Process->instance;
53$process->init(pidname => 'bounced');
54
55## Check options
56my %options;
57unless (
58    GetOptions(
59        \%main::options, 'config|f=s',   'debug|d', 'help|h',
60        'log_level=s',   'foreground|F', 'version|v',
61    )
62) {
63    pod2usage(-exitval => 1, -output => \*STDERR);
64}
65if ($main::options{'help'}) {
66    pod2usage(0);
67} elsif ($main::options{'version'}) {
68    printf "Sympa %s\n", Sympa::Constants::VERSION;
69    exit 0;
70}
71$Conf::sympa_config = $main::options{config};
72
73if ($main::options{'debug'}) {
74    $main::options{'log_level'} = 2 unless $main::options{'log_level'};
75    $main::options{'foreground'} = 1;
76}
77
78my $log = Sympa::Log->instance;
79$log->{log_to_stderr} = 'all' if $main::options{'foreground'};
80
81# Load sympa.conf
82unless (Conf::load()) {
83    die sprintf
84        "Unable to load sympa configuration, file %s has errors.\n",
85        Conf::get_sympa_conf();
86}
87
88# Check database connectivity
89unless (Sympa::DatabaseManager->instance) {
90    die sprintf
91        "Database %s defined in sympa.conf has not the right structure or is unreachable.\n",
92        $Conf::Conf{'db_name'};
93}
94
95# Put ourselves in background if not in debug mode.
96unless ($main::options{'foreground'}) {
97    $process->daemonize;
98}
99
100# Create and write the PID file.
101$process->write_pid(initial => 1);
102# If process is running in foreground, don't write STDERR to a dedicated file.
103unless ($main::options{foreground}) {
104    $process->direct_stderr_to_file;
105}
106
107if ($main::options{'log_level'}) {
108    $log->{level} = $main::options{'log_level'};
109    $log->syslog(
110        'info',
111        'Configuration file read, log level set using options: %s',
112        $main::options{'log_level'}
113    );
114} else {
115    $log->{level} = $Conf::Conf{'log_level'};
116    $log->syslog(
117        'info',
118        'Configuration file read, default log level %s',
119        $Conf::Conf{'log_level'}
120    );
121}
122
123my $log_facility = $Conf::Conf{'log_facility'} || $Conf::Conf{'syslog'};
124$log->openlog($log_facility, $Conf::Conf{'log_socket_type'});
125
126## Set the User ID & Group ID for the process
127$GID = $EGID = (getgrnam(Sympa::Constants::GROUP))[2];
128$UID = $EUID = (getpwnam(Sympa::Constants::USER))[2];
129
130## Required on FreeBSD to change ALL IDs
131## (effective UID + real UID + saved UID)
132POSIX::setuid((getpwnam(Sympa::Constants::USER))[2]);
133POSIX::setgid((getgrnam(Sympa::Constants::GROUP))[2]);
134
135## Check if the UID has correctly been set (useful on OS X)
136unless (($GID == (getgrnam(Sympa::Constants::GROUP))[2])
137    && ($UID == (getpwnam(Sympa::Constants::USER))[2])) {
138    die
139        "Failed to change process user ID and group ID. Note that on some OS Perl scripts can't change their real UID. In such circumstances Sympa should be run via sudo.\n";
140}
141
142## Sets the UMASK
143umask(oct($Conf::Conf{'umask'}));
144
145## Change to list root
146unless (chdir($Conf::Conf{'home'})) {
147    die sprintf "Unable to change directory to %s: %s", $Conf::Conf{'home'},
148        $!;
149}
150
151$log->syslog('notice', 'Bounced %s Started', Sympa::Constants::VERSION());
152
153my $spindle = Sympa::Spindle::ProcessBounce->new;
154
155## Catch signals, in order to exit cleanly, whenever possible.
156$SIG{'TERM'} = 'sigterm';
157$SIG{'INT'}  = 'sigterm';
158
159while (not $spindle->{finish}) {
160    $spindle->spin;
161    last if $spindle->{finish};
162
163    # If the spool was empty, sleep for a while.
164    sleep $Conf::Conf{'sleep'};
165}
166
167# Purge grouped notifications
168Sympa::Spool::Listmaster->instance->flush(purge => 1);
169
170$log->syslog('notice', 'Bounced exited normally due to signal');
171$process->remove_pid(final => 1);
172
173exit(0);
174
175# When we catch signal, just change the value of the loop variable.
176sub sigterm {
177    my ($sig) = @_;
178    $log->syslog('notice',
179        'Signal %s received, still processing current task', $sig);
180    $spindle->{finish} = $sig;
181}
182
183## copy the bounce to the appropriate filename
184# Moved: Use Sympa::Tracking::store().
185#sub store_bounce;
186
187# Moved to Sympa::Spindle::ProcessBounce::_twist().
188#sub process_message;
189
190# Old name: Bounce::rfc1891().
191# Moved to Sympa::Spindle::ProcessBounce::_parse_dsn().
192#sub _parse_dsn;
193
194# Moved to Sympa::Spindle::ProcessBounce::_parse_multipart_report().
195#sub _parse_multipart_report;
196
197# Moved to Sympa::Spindle::ProcessBounce::_decode_utf_8_addr_xtext().
198#sub _decode_utf_8_addr_xtext;
199
200# Moved to %Sympa::Spindle::ProcessBounce::equiv.
201#my %equiv;
202
203# Old name: Bounce::corrige().
204# Moved to Sympa::Spindle::ProcessBounce::_corrige().
205#sub _corrige;
206
207# Old name: Bounce::anabounce().
208# Moved to Sympa::Spindle::ProcessBounce::_anabounce().
209#sub _anabounce;
210
211# Moved to Sympa::Spindle::ProcessBounce::_canonicalize_status().
212#sub _canonicalize_status;
213
214# Moved: Now a subroutine of Sympa::Tracking::store().
215#sub _update_subscriber_bounce_history;
216
217# If bounce can't be handled correctly, saves it to the "bad" subdirectory of
218# the bounce spool.
219#DEPRECATED.  Use Sympa::Spool::Bounce::quarantine().
220# sub quarantine;
221
222#DEPRECATED.  Use Sympa::Spool::Bounce::remove().
223# sub remove;
224
225__END__
226
227=encoding utf-8
228
229=head1 NAME
230
231bounced, bounced.pl - Mailing List Bounce Processing Daemon for Sympa
232
233=head1 SYNOPSIS
234
235C<bounced.pl> S<[ C<--foreground> ]> S<[ C<--debug> ]>
236
237=head1 DESCRIPTION
238
239Bounced is a program which scans permanently the bounce spool and
240processes bounces (non-delivery messages), looking or bad addresses.
241Bouncing addresses are tagged in database ; last bounce is kept for
242each bouncing address.
243
244List owners will be able to access information about the bounces
245via WWSympa after they have been processed by bounced.
246
247=head1 OPTIONS
248
249These programs follow the usual GNU command line syntax,
250with long options starting with two dashes (C<-->).  A summary of
251options is included below.
252
253=over 5
254
255=item C<-F>, C<--foreground>
256
257Do not detach TTY.
258
259=item C<-f>, C<--config=>I<file>
260
261Force bounced to use an alternative configuration file instead
262of F<--CONFIG-->.
263
264=item C<-d>, C<--debug>
265
266Run the program in a debug mode.
267
268=item C<-h>, C<--help>
269
270Print this help message.
271
272=item C<--log_level=>I<level>
273
274Sets daemon log level.
275
276=back
277
278=head1 FILES
279
280F<--CONFIG--> Sympa configuration file.
281
282F<$LIBEXECDIR/bouncequeue> bounce spooler, referenced from sendmail alias file
283
284F<$SPOOLDIR/bounce> incoming bounces directory
285
286F<$PIDDIR/bounced.pid> this file contains the process ID
287of F<bounced.pl>.
288
289=head1 MORE DOCUMENTATION
290
291The full documentation can be
292found in L<https://sympa-community.github.io/manual/>.
293
294The mailing lists (with web archives) can be accessed at
295L<https://listes.renater.fr/sympa/lists/informatique/sympa>.
296
297=head1 HISTORY
298
299This program was originally written by:
300
301=over 4
302
303=item Serge Aumont
304
305ComitE<233> RE<233>seau des UniversitE<233>s
306
307=item Olivier SalaE<252>n
308
309ComitE<233> RE<233>seau des UniversitE<233>s
310
311=back
312
313This manual page was initially written by
314JE<233>rE<244>me Marant <jerome.marant@IDEALX.org>
315for the Debian GNU/Linux system.
316
317=head1 LICENSE
318
319You may distribute this software under the terms of the GNU General
320Public License Version 2.  For more details see F<README> file.
321
322Permission is granted to copy, distribute and/or modify this document
323under the terms of the GNU Free Documentation License, Version 1.1 or
324any later version published by the Free Software Foundation; with no
325Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.  A
326copy of the license can be found under
327L<http://www.gnu.org/licenses/fdl.html>.
328
329=head1 BUGS
330
331Report bugs to Sympa bug tracker.
332See L<http://www.sympa.org/tracking>.
333
334=head1 SEE ALSO
335
336L<sympa_msg(8)>, L<wwsympa(8)>, L<mhonarc(1)>, L<sympa.conf(5)>.
337
338L<Sympa::Spindle::ProcessBounce>.
339
340=cut
341