File Coverage

blib/lib/EMDIS/ECS/Config.pm
Criterion Covered Total %
statement 242 264 91.6
branch 103 138 74.6
condition 33 51 64.7
subroutine 15 16 93.7
pod 0 2 0.0
total 393 471 83.4


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             #
3             # Copyright (C) 2002-2025 National Marrow Donor Program. All rights reserved.
4             #
5             # For a description of this module, please refer to the POD documentation
6             # embedded at the bottom of the file (e.g. perldoc EMDIS::ECS::Config).
7              
8             package EMDIS::ECS::Config;
9              
10 2     2   31095 use Carp;
  2         5  
  2         219  
11 2     2   22 use Cwd;
  2         5  
  2         181  
12 2     2   896 use EMDIS::ECS qw($VERSION is_yes is_no);
  2         6  
  2         374  
13 2     2   29 use File::Basename;
  2         4  
  2         242  
14 2     2   76 use File::Spec::Functions qw(catdir catfile file_name_is_absolute rel2abs);
  2         6  
  2         146  
15 2     2   11 use strict;
  2         2  
  2         91  
16 2     2   1619 use Text::ParseWords;
  2         3774  
  2         155  
17 2     2   14 use vars qw($AUTOLOAD %ok_attr);
  2         4  
  2         375  
18              
19             # ----------------------------------------------------------------------
20             # initialize %ok_attr hash with valid attribute names
21             BEGIN
22             {
23 2     2   70 my @attrlist = qw(
24             MSG_PROC MAIL_MRK THIS_NODE T_CHK T_SCN ERR_FILE LOG_FILE ADM_ADDR
25             M_MSG_PROC BCK_DIR ACK_THRES LOG_LEVEL MAIL_LEVEL
26             ECS_BIN_DIR ECS_DAT_DIR ECS_TO_DIR ECS_FROM_DIR ECS_DEBUG
27             NODE_TBL NODE_TBL_LCK T_ADM_DELAY T_ADM_REMIND T_MSG_PROC
28             ADAPTER_CMD ALWAYS_ACK GNU_TAR T_RESEND_DELAY
29             SMTP_HOST SMTP_DOMAIN SMTP_TIMEOUT SMTP_DEBUG SMTP_FROM SMTP_PORT
30             SMTP_USE_SSL SMTP_USE_STARTTLS SMTP_USERNAME SMTP_PASSWORD
31             INBOX_PROTOCOL INBOX_HOST INBOX_PORT INBOX_TIMEOUT INBOX_DEBUG
32             INBOX_FOLDER INBOX_USERNAME INBOX_PASSWORD INBOX_MAX_MSG_SIZE
33             INBOX_DIRECTORY INBOX_USE_SSL INBOX_USE_STARTTLS
34             MSG_PART_SIZE_DFLT
35             GPG_HOMEDIR GPG_KEYID GPG_PASSPHRASE
36             OPENPGP_CMD_ENCRYPT OPENPGP_CMD_DECRYPT
37             PGP_HOMEDIR PGP_KEYID PGP_PASSPHRASE
38             PGP2_CMD_ENCRYPT PGP2_CMD_DECRYPT
39             ENABLE_AMQP
40             AMQP_BROKER_URL AMQP_VHOST AMQP_ADDR_META AMQP_ADDR_MSG AMQP_ADDR_DOC
41             AMQP_TRUSTSTORE AMQP_SSLCERT AMQP_SSLKEY AMQP_SSLPASS
42             AMQP_USERNAME AMQP_PASSWORD
43             AMQP_RECV_TIMEOUT AMQP_RECV_TIMELIMIT AMQP_SEND_TIMELIMIT
44             AMQP_DEBUG_LEVEL AMQP_CMD_SEND AMQP_CMD_RECV
45             EMDIS_MESSAGE_VERSION ENABLE_ENV_CONFIG
46             INBOX_OAUTH_TOKEN_CMD
47             INBOX_OAUTH_TOKEN_CMD_TIMELIMIT
48             INBOX_OAUTH_SASL_MECHANISM
49             SMTP_OAUTH_TOKEN_CMD
50             SMTP_OAUTH_TOKEN_CMD_TIMELIMIT
51             SMTP_OAUTH_SASL_MECHANISM
52             );
53 2         9 for my $attr (@attrlist)
54             {
55 172         8312 $ok_attr{$attr} = 1;
56             }
57             }
58              
59             # ----------------------------------------------------------------------
60             # use AUTOLOAD method to provide accessor methods
61             # (as described in Perl Cookbook)
62             sub AUTOLOAD
63             {
64 166     166   1651 my $this = shift;
65 166         264 my $attr = $AUTOLOAD;
66 166         1046 $attr =~ s/.*:://;
67 166 100       1338 return unless $attr =~ /[^A-Z]/; # skip DESTROY and all-cap methods
68             # (for EMDIS::ECS::Config, all valid
69             # attribute names contain at least
70             # one underscore)
71 157 50       420 croak "invalid attribute method: ->$attr()" unless $ok_attr{$attr};
72 157         1279 return $this->{uc $attr};
73             }
74              
75             # ----------------------------------------------------------------------
76             # Constructor.
77             # Returns EMDIS::ECS::Config reference if successful or error message if
78             # error encountered.
79             sub new
80             {
81 10     10 0 200076 my $class = shift;
82 10         28 my $cfg_file = shift;
83 10         42 my $skip_val = shift;
84 10 100       71 $skip_val = '' unless defined $skip_val;
85 10         25 my $this = {};
86 10         33 bless $this, $class;
87 10 50       53 $cfg_file = 'ecs.cfg' unless defined($cfg_file);
88 10         75 $this->{CFG_FILE} = $cfg_file;
89 10         86756 $this->{CFG_CWD} = cwd(); # remember cwd in case it may be needed
90 10         379 $this->_set_defaults();
91 10 50       91 return $this if $cfg_file eq ''; # default config (used by ecs_setup)
92 10         157 my $err = $this->_read_config();
93 10 100       109 return $err if $err;
94 8 100       66 return $this if $skip_val; # skip validation (used by ecs_setup)
95 7         50 $err = $this->_massage_config();
96 7 50       21 return $err if $err;
97 7         162 $err = $this->_validate_config();
98 7 100       143 return $err if $err;
99 4         75 return $this;
100             }
101              
102             # ----------------------------------------------------------------------
103             # Display configuration data.
104             sub display
105             {
106 0     0 0 0 my $this = shift;
107 0         0 my $fmt = "%-20s %s\n";
108 0         0 print "ECS_CFG\n";
109 0         0 print "---------------------------------------------------------------\n";
110 0         0 for my $attr (sort keys %$this) {
111 0         0 my $value = $this->{$attr};
112 0 0       0 $value = '********' if $attr =~ /PASSWORD|PASSPHRASE/i;
113 0         0 printf $fmt, $attr, $value;
114             }
115             }
116              
117             # ----------------------------------------------------------------------
118             # Parse config file data.
119             # Returns empty string if successful or error message if error encountered.
120             sub _read_config
121             {
122 10     10   28 my $this = shift;
123              
124             # read config file
125 10         42 my $err = '';
126 10 100       813 if(not open CONFIG, "< $this->{CFG_FILE}")
127             {
128 1         37 return "Unable to open config file '$this->{CFG_FILE}': $!";
129             }
130 9         457 while()
131             {
132 208         474 chomp; # trim EOL character(s)
133 208         566 s/^\s+//; # trim leading whitespace
134 208         862 s/\s+$//; # trim trailing whitespace
135 208 100       468 next unless length; # skip blank line
136 200 100       757 next if /^#/; # skip comment line
137 162         314 my @fields = ();
138 162         542 my @tokens = split '\|'; # split on pipe ('|') delimiter
139 162         309 for my $token (@tokens)
140             {
141 486 50 66     1617 if($#fields >= 0 and $fields[$#fields] =~ /\\$/)
142             {
143             # rejoin tokens separated by escaped pipe ('\|')
144 0         0 chop($fields[$#fields]);
145 0         0 $fields[$#fields] .= "|$token";
146             }
147             else
148             {
149 486         959 push(@fields, $token);
150             }
151             }
152             # trim leading & trailing whitespace
153 162         355 @fields = map { s/^\s+//; s/\s+$//; $_; } @fields;
  486         1434  
  486         1661  
  486         1216  
154 162         411 my ($attr, $value, $comment) = @fields;
155 162 100       455 if($ok_attr{$attr})
156             {
157             # store value
158 161         1455 $this->{$attr} = $value;
159             }
160             else
161             {
162 1         64 $err .=
163             "Unexpected input '$attr' at $this->{CFG_FILE} line $.\n";
164             }
165             }
166 9         143 close CONFIG;
167 9 100       62 if($err)
168             {
169 1         12 return $err .
170             "Error(s) encountered while attempting to process " .
171             "$this->{CFG_FILE}.";
172             }
173              
174 8         42 return '';
175             }
176              
177             # ----------------------------------------------------------------------
178             # Massage config data.
179             # Returns empty string if successful or error message if error encountered.
180             sub _massage_config
181             {
182 7     7   21 my $this = shift;
183              
184             # initialize
185 7         115 my $err = '';
186 7         459 my $script_dir = dirname($0);
187 7 50       208 $script_dir = rel2abs($script_dir)
188             unless file_name_is_absolute($script_dir);
189 7         1140 my $config_dir = dirname($this->{CFG_FILE});
190 7 50       53 $config_dir = rel2abs($config_dir)
191             unless file_name_is_absolute($config_dir);
192 7 100       321 if(is_yes($this->{ENABLE_ENV_CONFIG}))
193             {
194 6         358 for my $attr (keys %ok_attr)
195             {
196 561 100       1178 if(exists $this->{$attr})
197             {
198 373         640 my $value = $this->{$attr};
199             # if value follows $ENV{envvar} pattern, use value of environment variable
200 373 100       903 if($value =~ /^\$ENV\{(\S+)\}$/)
201             {
202 2         18 my $envvar = $1;
203 2         12 my $env_value = $ENV{$envvar};
204 2 50       23 if(defined $env_value)
205             {
206 2         15 $this->{$attr} = $env_value;
207             }
208             else
209             {
210 0         0 $err .=
211             "Environment variable '$envvar' has undefined value - referenced by $attr in config file '$this->{CFG_FILE}'\n";
212             }
213             }
214             }
215             }
216             }
217              
218             # parse some special tokens
219 7         204 for my $attr (keys %ok_attr)
220             {
221 656 100       1486 if(exists $this->{$attr})
222             {
223 435         690 my $value = $this->{$attr};
224 435         846 $value =~ s/__SCRIPT_DIR__/$script_dir/;
225 435         684 $value =~ s/__CONFIG_DIR__/$config_dir/;
226 435         2066 $this->{$attr} = $value;
227             }
228             }
229              
230             # prepend ECS_DAT_DIR to non-absolute file/path names
231 7         81 for my $attr (qw(ERR_FILE GPG_HOMEDIR LOG_FILE NODE_TBL NODE_TBL_LCK
232             PGP_HOMEDIR ECS_TO_DIR ECS_FROM_DIR))
233             {
234             $this->{$attr} = catfile($this->{ECS_DAT_DIR}, $this->{$attr})
235             if exists($this->{$attr})
236             and not ($this->{$attr} eq '')
237 56 100 66     737 and not file_name_is_absolute($this->{$attr});
      100        
238             }
239              
240             # prepend ECS_BIN_DIR to non-absolute executable command names
241 7         27 for my $attr (qw(MSG_PROC M_MSG_PROC))
242             {
243             $this->{$attr} = catfile($this->{ECS_BIN_DIR}, $this->{$attr})
244             if exists($this->{$attr})
245 14 50 33     152 and not file_name_is_absolute($this->{$attr});
246             }
247              
248             # compute derived values
249 7         98 $this->{ECS_TMP_DIR} = catdir($this->{ECS_DAT_DIR}, 'tmp');
250 7 100 66     56 if ( ! defined($this->{ECS_TO_DIR}) || $this->{ECS_TO_DIR} eq '')
251             {
252 6         51 $this->{ECS_DRP_DIR} = catdir($this->{ECS_DAT_DIR}, 'maildrop');
253             }
254             else
255             {
256 1         14 $this->{ECS_DRP_DIR} = $this->{ECS_TMP_DIR};
257             }
258 7         59 $this->{ECS_MBX_DIR} = catdir($this->{ECS_DAT_DIR}, 'mboxes');
259 7         59 $this->{ECS_MBX_AMQP_STAGING_DIR} = catdir($this->{ECS_MBX_DIR}, 'amqp_staging');
260 7         42 $this->{ECS_MBX_IN_DIR} = catdir($this->{ECS_MBX_DIR}, 'in');
261 7         44 $this->{ECS_MBX_IN_FML_DIR} = catdir($this->{ECS_MBX_DIR}, 'in_fml');
262 7         45 $this->{ECS_MBX_OUT_DIR} = catdir($this->{ECS_MBX_DIR}, 'out');
263 7         49 $this->{ECS_MBX_TRASH_DIR} = catdir($this->{ECS_MBX_DIR}, 'trash');
264 7         47 $this->{ECS_MBX_STORE_DIR} = catdir($this->{ECS_MBX_DIR}, 'store');
265 7         28 for my $attr (qw(ECS_TMP_DIR ECS_DRP_DIR ECS_MBX_DIR
266             ECS_MBX_AMQP_STAGING_DIR ECS_MBX_IN_DIR
267             ECS_MBX_IN_FML_DIR ECS_MBX_OUT_DIR ECS_MBX_TRASH_DIR
268             ECS_MBX_STORE_DIR))
269             {
270 63         180 $ok_attr{$attr} = 1;
271             }
272              
273             # parse more special tokens
274 7         147 for my $attr (keys %ok_attr)
275             {
276 665 100       1387 if(exists $this->{$attr})
277             {
278 498         790 my $value = $this->{$attr};
279 498         858 $value =~ s/__MAILDROP_DIR__/$this->{ECS_DRP_DIR}/;
280 498         1124 $this->{$attr} = $value;
281             }
282             }
283              
284             # if indicated, assign SMTP_PORT default value
285 7 100       111 if(not defined($this->{SMTP_PORT})) {
286 6         38 $this->{SMTP_PORT} = 25;
287 6 100       44 $this->{SMTP_PORT} = 465 if is_yes($this->{SMTP_USE_SSL});
288 6 100       26 $this->{SMTP_PORT} = 587 if is_yes($this->{SMTP_USE_STARTTLS});
289             }
290              
291             # if indicated, assign INBOX_PORT default value
292 7 100       35 if(not defined($this->{INBOX_PORT})) {
293 6         21 for($this->{INBOX_PROTOCOL})
294             {
295 6 100       35 /POP3/ and do {
296 4         14 $this->{INBOX_PORT} = 110;
297 4 50       14 $this->{INBOX_PORT} = 995 if is_yes($this->{INBOX_USE_SSL});
298             };
299 6 100       37 /IMAP/ and do {
300 1         37 $this->{INBOX_PORT} = 143;
301 1 50       17 $this->{INBOX_PORT} = 993 if is_yes($this->{INBOX_USE_SSL});
302             };
303             }
304             }
305              
306 7         26 return $err;
307             }
308              
309             # ----------------------------------------------------------------------
310             # Assign default values to configuration settings.
311             # Note: no default value for THIS_NODE, ADM_ADDR, ADAPTER_CMD, SMTP_DOMAIN,
312             # SMTP_FROM, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, INBOX_PORT,
313             # INBOX_FOLDER, INBOX_USERNAME, INBOX_PASSWORD, GPG_HOMEDIR, GPG_KEYID,
314             # GPG_PASSPHRASE, PGP_HOMEDIR, PGP_KEYID, PGP_PASSPHRASE,
315             # AMQP_BROKER_URL, AMQP_VHOST, AMQP_TRUSTSTORE, AMQP_SSLCERT AMQP_SSLKEY,
316             # AMQP_SSLPASS, AMQP_USERNAME, AMQP_PASSWORD
317             sub _set_defaults
318             {
319 10     10   85 my $this = shift;
320 10         121 $this->{MSG_PROC} = "ecs_proc_msg";
321 10         124 $this->{MAIL_MRK} = "EMDIS";
322 10         96 $this->{T_CHK} = "7200";
323 10         137 $this->{T_SCN} = "3600";
324 10         114 $this->{ENABLE_ENV_CONFIG} = 'YES';
325 10         1716 my $basename = basename($0); # default; use magic logfile name
326 10         106 $this->{ERR_FILE} = "$basename.err";
327 10         133 $this->{LOG_FILE} = "$basename.log";
328 10         86 $this->{M_MSG_PROC} = "ecs_proc_meta";
329 10         112 $this->{BCK_DIR} = "NONE";
330 10         92 $this->{ACK_THRES} = "100";
331 10         76 $this->{ALWAYS_ACK} = "NO";
332 10         47 $this->{GNU_TAR} = "/usr/bin/tar";
333 10         93 $this->{ECS_BIN_DIR} = "__SCRIPT_DIR__";
334 10         79 $this->{ECS_DAT_DIR} = "__CONFIG_DIR__";
335 10         109 $this->{ECS_DEBUG} = "0";
336 10         80 $this->{NODE_TBL} = "node_tbl.dat";
337 10         95 $this->{NODE_TBL_LCK} = "node_tbl.lock";
338 10         39 $this->{T_ADM_DELAY} = "0";
339 10         76 $this->{T_ADM_REMIND} = "86400";
340 10         132 $this->{T_MSG_PROC} = "3600";
341 10         66 $this->{T_RESEND_DELAY} = "14400";
342 10         138 $this->{LOG_LEVEL} = 1;
343 10         91 $this->{MAIL_LEVEL} = 2;
344 10         60 $this->{MSG_PART_SIZE_DFLT} = "1073741824";
345 10         61 $this->{SMTP_HOST} = "smtp";
346 10         95 $this->{SMTP_TIMEOUT} = "60";
347 10         39 $this->{SMTP_DEBUG} = "0";
348 10         38 $this->{SMTP_USE_SSL} = "NO";
349 10         47 $this->{SMTP_USE_STARTTLS} = "NO";
350 10         59 $this->{INBOX_PROTOCOL} = "POP3";
351 10         45 $this->{INBOX_HOST} = "mail";
352 10         36 $this->{INBOX_FOLDER} = "INBOX";
353 10         48 $this->{INBOX_TIMEOUT} = "60";
354 10         55 $this->{INBOX_DEBUG} = "0";
355 10         38 $this->{INBOX_USE_SSL} = "NO";
356 10         41 $this->{INBOX_USE_STARTTLS} = "NO";
357 10         91 $this->{INBOX_MAX_MSG_SIZE} = "1048576";
358 10         83 $this->{OPENPGP_CMD_ENCRYPT} = '/usr/local/bin/gpg --armor --batch ' .
359             '--charset ISO-8859-1 --force-mdc --logger-fd 1 --openpgp ' .
360             '--output __OUTPUT__ --pinentry-mode loopback --passphrase-fd 0 ' .
361             '--quiet --recipient __RECIPIENT__ --recipient __SELF__ --yes ' .
362             '--sign --local-user __SELF__ --encrypt __INPUT__';
363 10         69 $this->{OPENPGP_CMD_DECRYPT} = '/usr/local/bin/gpg --batch ' .
364             '--charset ISO-8859-1 --logger-fd 1 --openpgp --output __OUTPUT__ ' .
365             '--pinentry-mode loopback --passphrase-fd 0 --quiet --yes ' .
366             '--decrypt __INPUT__';
367 10         62 $this->{PGP2_CMD_ENCRYPT} = '/usr/local/bin/pgp +batchmode +verbose=0 ' .
368             '+force +CharSet=latin1 +ArmorLines=0 -o __OUTPUT__ ' .
369             '-u __SELF__ -eats __INPUT__ __RECIPIENT__ __SELF__';
370 10         61 $this->{PGP2_CMD_DECRYPT} = '/usr/local/bin/pgp +batchmode +verbose=0 ' .
371             '+force +CharSet=latin1 -o __OUTPUT__ __INPUT__';
372 10         88 $this->{ENABLE_AMQP} = "NO";
373 10         97 $this->{AMQP_RECV_TIMEOUT} = 5;
374 10         26 $this->{AMQP_RECV_TIMELIMIT} = 300;
375 10         33 $this->{AMQP_SEND_TIMELIMIT} = 60;
376 10         60 $this->{AMQP_DEBUG_LEVEL} = 0;
377 10         39 $this->{AMQP_CMD_SEND} = 'ecs_amqp_send.py';
378 10         36 $this->{AMQP_CMD_RECV} = 'ecs_amqp_recv.py';
379 10         63 $this->{INBOX_OAUTH_TOKEN_CMD_TIMELIMIT} = "60";
380 10         65 $this->{INBOX_OAUTH_SASL_MECHANISM} = "XOAUTH2 OAUTHBEARER";
381 10         62 $this->{SMTP_OAUTH_TOKEN_CMD_TIMELIMIT} = "60";
382 10         97 $this->{SMTP_OAUTH_SASL_MECHANISM} = "XOAUTH2 OAUTHBEARER";
383             }
384              
385             # ----------------------------------------------------------------------
386             # Do a few sanity checks on the configuration data.
387             # Returns empty string if successful or error message if error encountered.
388             sub _validate_config
389             {
390 7     7   19 my $this = shift;
391 7         20 my @errors = ();
392 7         163 my @required_attrlist = qw(
393             MSG_PROC MAIL_MRK THIS_NODE T_CHK T_SCN ERR_FILE LOG_FILE ADM_ADDR
394             M_MSG_PROC BCK_DIR ACK_THRES
395             ECS_BIN_DIR ECS_DAT_DIR ECS_DEBUG
396             NODE_TBL NODE_TBL_LCK T_ADM_REMIND T_MSG_PROC
397             SMTP_HOST SMTP_DOMAIN SMTP_TIMEOUT SMTP_DEBUG SMTP_FROM
398             INBOX_PROTOCOL INBOX_HOST INBOX_TIMEOUT INBOX_DEBUG
399             INBOX_MAX_MSG_SIZE
400             MSG_PART_SIZE_DFLT
401             );
402              
403             # check for required values that are undefined
404 7         71 for my $attr (@required_attrlist)
405             {
406             push(@errors, "$attr not defined.")
407 203 100       446 unless exists($this->{$attr});
408             }
409              
410             # validate INBOX_PROTOCOL
411            
412             # username/password not needed for DIRECTORY inbox
413 7 50 33     97 if($this->{INBOX_PROTOCOL} !~ /DIRECTORY/i and not exists($this->{INBOX_OAUTH_TOKEN_CMD}))
414             {
415 7         26 for my $attr (qw( INBOX_USERNAME INBOX_PASSWORD))
416             {
417             push(@errors, "$attr not defined.")
418 14 100       54 unless exists($this->{$attr});
419             }
420             }
421              
422 7 50       25 if(exists $this->{INBOX_OAUTH_TOKEN_CMD}) {
423 0         0 for my $attr (qw(INBOX_USERNAME
424             INBOX_OAUTH_TOKEN_CMD_TIMELIMIT
425             INBOX_OAUTH_SASL_MECHANISM))
426             {
427             push(@errors, "$attr not defined.")
428 0 0       0 unless exists($this->{$attr});
429             }
430             }
431              
432 7 100       126 if($this->{INBOX_PROTOCOL} =~ /IMAP/i)
    100          
    50          
    50          
433             {
434 2         19 $this->{INBOX_PROTOCOL} = 'IMAP'; # force uppercase
435             push(@errors,
436             "INBOX_FOLDER not defined, but is required for IMAP protocol.")
437 2 50       15 unless defined($this->{INBOX_FOLDER});
438             }
439             elsif($this->{INBOX_PROTOCOL} =~ /POP3/i)
440             {
441 4         21 $this->{INBOX_PROTOCOL} = 'POP3'; # force uppercase
442             }
443             elsif($this->{INBOX_PROTOCOL} =~ /DIRECTORY/i)
444             {
445 0         0 $this->{INBOX_PROTOCOL} = 'DIRECTORY'; # force uppercase
446             push(@errors, "INBOX_DIRECTORY not defined, but is required for " .
447             "DIRECTORY protocol.")
448 0 0       0 unless defined($this->{INBOX_DIRECTORY});
449             }
450             elsif($this->{INBOX_PROTOCOL} =~ /NONE/i)
451             {
452 0         0 $this->{INBOX_PROTOCOL} = 'NONE'; # force uppercase
453             }
454             else
455             {
456 1         11 push(@errors,
457             "Unrecognized INBOX_PROTOCOL: $this->{INBOX_PROTOCOL}");
458             }
459              
460 7 50       30 if(exists $this->{SMTP_OAUTH_TOKEN_CMD}) {
461 0         0 for my $attr (qw(SMTP_USERNAME
462             SMTP_OAUTH_TOKEN_CMD_TIMELIMIT
463             SMTP_OAUTH_SASL_MECHANISM))
464             {
465             push(@errors, "$attr not defined.")
466 0 0       0 unless exists($this->{$attr});
467             }
468             }
469              
470 7 50       39 if(is_yes($this->{ENABLE_AMQP}))
471             {
472             # sanity checks on AMQP configuration
473 0         0 for my $attr (qw(AMQP_ADDR_META AMQP_ADDR_MSG AMQP_BROKER_URL
474             AMQP_CMD_SEND AMQP_CMD_RECV AMQP_DEBUG_LEVEL
475             AMQP_RECV_TIMEOUT AMQP_RECV_TIMELIMIT
476             AMQP_SEND_TIMELIMIT))
477             {
478             push(@errors, "$attr not defined, but is required for AMQP " .
479             "messaging.")
480 0 0       0 unless exists($this->{$attr});
481             }
482             }
483              
484             # check whether an encryption method is configured
485 7 50 66     39 if(!exists($this->{GPG_HOMEDIR}) && !exists($this->{PGP_HOMEDIR}))
486             {
487 1         21 push(@errors, "No encryption method configured. Need to " .
488             "configure either GPG_HOMEDIR or PGP_HOMEDIR, etc.");
489             }
490              
491             # check OpenPGP encryption setup
492 7 100       29 if(exists($this->{GPG_HOMEDIR}))
493             {
494 6         29 for my $attr (qw(GPG_HOMEDIR GPG_KEYID GPG_PASSPHRASE
495             OPENPGP_CMD_ENCRYPT OPENPGP_CMD_DECRYPT))
496             {
497             push(@errors, "$attr not defined, but is required for OpenPGP " .
498             "encryption setup (GPG_HOMEDIR = " .
499             $this->{GPG_HOMEDIR} . ").")
500 30 100       125 unless exists($this->{$attr});
501             }
502             }
503              
504             # check PGP encryption setup
505 7 100       28 if(exists($this->{PGP_HOMEDIR}))
506             {
507 3         13 for my $attr (qw(PGP_HOMEDIR PGP_KEYID PGP_PASSPHRASE
508             PGP2_CMD_ENCRYPT PGP2_CMD_DECRYPT))
509             {
510             push(@errors, "$attr not defined, but is required for PGP2 " .
511             "encryption setup (PGP_HOMEDIR = " .
512             $this->{PGP_HOMEDIR} . ").")
513 15 100       54 unless exists($this->{$attr});
514             }
515             }
516              
517             # validate T_CHK
518 7 100       40 if($this->{T_CHK} <= 0)
519             {
520 1         10 push(@errors,
521             "T_CHK ($this->{T_CHK}) is required to be greater than zero.");
522             }
523              
524             # validate T_SCN
525 7 100       30 if($this->{T_SCN} <= 0)
526             {
527 1         7 push(@errors,
528             "T_SCN ($this->{T_SCN}) is required to be greater than zero.");
529             }
530              
531             # validate T_ADM_REMIND
532 7 100       49 if($this->{T_ADM_REMIND} <= 0)
533             {
534 1         10 push(@errors,
535             "T_ADM_REMIND ($this->{T_ADM_REMIND}) is required " .
536             "to be greater than zero.");
537             }
538              
539             # validate T_MSG_PROC
540 7 100       29 if($this->{T_MSG_PROC} <= 0)
541             {
542 1         5 push(@errors,
543             "T_MSG_PROC ($this->{T_MSG_PROC}) is required " .
544             "to be greater than zero.");
545             }
546              
547             # validate YES/NO values
548 7         26 for my $name (qw(ALWAYS_ACK INBOX_USE_SSL INBOX_USE_STARTTLS SMTP_USE_SSL SMTP_USE_STARTTLS))
549             {
550 35 100 66     198 if(exists $this->{$name} and not is_yes($this->{$name})
      100        
551             and not is_no($this->{$name}))
552             {
553             push(@errors, "Unrecognized $name (YES/NO) value: " .
554 5         30 $this->{$name});
555             }
556             }
557              
558 7 100 100     26 if(is_yes($this->{INBOX_USE_SSL})
559             and is_yes($this->{INBOX_USE_STARTTLS}))
560             {
561 1         12 push(@errors, "INBOX_USE_SSL and INBOX_USE_STARTTLS " .
562             "are both selected, but they are mutually exclusive.");
563             }
564              
565 7 0 33     32 if(exists $this->{INBOX_OAUTH_TOKEN_CMD}
      33        
566             and not is_yes($this->{INBOX_USE_SSL})
567             and not is_yes($this->{INBOX_USE_STARTTLS}))
568             {
569 0         0 push(@errors, "INBOX OAuth 2.0 authentication requires SSL/TLS " .
570             "(INBOX_USE_SSL or INBOX_USE_STARTTLS).");
571             }
572              
573 7 100 100     30 if(is_yes($this->{SMTP_USE_SSL})
574             and is_yes($this->{SMTP_USE_STARTTLS}))
575             {
576 1         5 push(@errors, "SMTP_USE_SSL and SMTP_USE_STARTTLS " .
577             "are both selected, but they are mutually exclusive.");
578             }
579              
580 7 0 33     59 if(exists $this->{SMTP_OAUTH_TOKEN_CMD}
      33        
581             and not is_yes($this->{SMTP_USE_SSL})
582             and not is_yes($this->{SMTP_USE_STARTTLS}))
583             {
584 0         0 push(@errors, "SMTP OAuth 2.0 authentication requires SSL/TLS " .
585             "(SMTP_USE_SSL or SMTP_USE_STARTTLS).");
586             }
587              
588             # check whether directories exist
589 7         168 my @dirs = qw(ECS_BIN_DIR ECS_DAT_DIR ECS_TMP_DIR ECS_MBX_DIR
590             ECS_MBX_IN_DIR ECS_MBX_IN_FML_DIR ECS_MBX_OUT_DIR
591             ECS_MBX_TRASH_DIR ECS_MBX_STORE_DIR GPG_HOMEDIR
592             PGP_HOMEDIR);
593 7 50       35 push(@dirs, 'BCK_DIR') if($this->{BCK_DIR} ne 'NONE');
594             push(@dirs, 'ECS_DRP_DIR')
595             if( ! defined($this->{ECS_TO_DIR})
596 7 100 66     47 || $this->{ECS_TO_DIR} eq '');
597 7 50       32 push(@dirs, 'ECS_MBX_AMQP_STAGING_DIR') if is_yes($this->{ENABLE_AMQP});
598 7         22 for my $dir (@dirs)
599             {
600 83 100 100     1687 if(exists $this->{$dir} and not -d $this->{$dir})
601             {
602 8         67 push(@errors,
603             "$dir ($this->{$dir}) directory not found.");
604             }
605             }
606              
607             # return error messages, if any
608 7 100       34 if($#errors >= 0)
609             {
610 3         35 push(@errors,
611             "Error(s) detected in configuration file $this->{CFG_FILE}");
612 3         9 push(@errors, "Fatal configuration error(s) encountered.\n");
613 3         48 return "\n" . join("\n", @errors);
614             }
615 4         42 return '';
616             }
617              
618             1;
619              
620             __DATA__