File Coverage

blib/lib/EMDIS/ECS/Config.pm
Criterion Covered Total %
statement 243 265 91.7
branch 104 140 74.2
condition 35 54 64.8
subroutine 15 16 93.7
pod 0 2 0.0
total 397 477 83.2


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