File Coverage

blib/lib/EMDIS/ECS/Config.pm
Criterion Covered Total %
statement 245 268 91.4
branch 105 142 73.9
condition 35 54 64.8
subroutine 15 16 93.7
pod 0 2 0.0
total 400 482 82.9


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