1 # Functions for parsing the dovecot config file
3 BEGIN { push(@INC, ".."); };
7 @supported_auths = ( "anonymous", "plain", "digest-md5", "cram-md5", "apop" );
8 @mail_envs = ( undef, "maildir:~/Maildir", "mbox:~/mail/:INBOX=/var/mail/%u",
9 "maildir:~/Maildir:mbox:~/mail/" );
12 # Returns the full path to the first valid config file
15 foreach my $f (split(/\s+/, $config{'dovecot_config'})) {
22 # Returns a list of dovecot config entries
25 if (!scalar(@get_config_cache)) {
26 @get_config_cache = &read_config_file(&get_config_file());
28 return \@get_config_cache;
31 # read_config_file(filename)
32 # Convert a file into a list od directives
36 local $filedir = $file;
37 $filedir =~ s/\/[^\/]+$//;
39 local ($section, @sections);
41 local @lines = <CONF>;
48 if (/^\s*(#?)\s*([a-z0-9\_]+)\s*(\S*)\s*\{\s*$/) {
49 # Start of a section .. add this as a value too
50 local $oldsection = $section;
52 push(@sections, $section); # save old
54 $section = { 'name' => $2,
59 'indent' => scalar(@sections),
64 $section->{'sectionname'} =
65 $oldsection->{'name'};
66 $section->{'sectionvalue'} =
67 $oldsection->{'value'};
71 elsif (/^\s*(#?)\s*}\s*$/ && $section) {
73 $section->{'eline'} = $lnum;
74 $section->{'eline'} = $lnum;
76 $section = pop(@sections);
82 elsif (/^\s*(#?)([a-z0-9\_]+)\s+=\s*(.*)/) {
83 # A directive inside a section
84 local $dir = { 'name' => $2,
90 $dir->{'sectionname'} = $section->{'name'};
91 $dir->{'sectionvalue'} = $section->{'value'};
92 push(@{$section->{'members'}}, $dir);
93 $section->{'eline'} = $lnum;
97 elsif (/^\s*!(include|include_try)\s+(\S+)/) {
100 if ($glob !~ /^\//) {
101 $glob = $filedir."/".$glob;
103 foreach my $i (glob($glob)) {
104 push(@rv, &read_config_file($i));
112 # find(name, &config, [disabled-mode], [sectionname], [sectionvalue])
113 # Mode 0=enabled, 1=disabled, 2=both
116 local ($name, $conf, $mode, $sname, $svalue) = @_;
117 local @rv = grep { !$_->{'section'} &&
118 $_->{'name'} eq $name &&
119 ($mode == 0 && $_->{'enabled'} ||
120 $mode == 1 && !$_->{'enabled'} || $mode == 2) } @$conf;
121 if (defined($sname)) {
122 # If a section was requested, limit to it
123 @rv = grep { $_->{'sectionname'} eq $sname &&
124 $_->{'sectionvalue'} eq $svalue } @rv;
126 return wantarray ? @rv : $rv[0];
129 # find_value(name, &config, [disabled-mode], [sectionname], [sectionvalue])
130 # Mode 0=enabled, 1=disabled, 2=both
133 local @rv = &find(@_);
135 return map { $_->{'value'} } @rv;
138 return $rv[0]->{'value'};
142 # find_section(name, &config, [disabled-mode], [sectionname], [sectionvalue])
143 # Returns a Dovecot config section object
146 local ($name, $conf, $mode, $sname, $svalue) = @_;
147 local @rv = grep { $_->{'section'} &&
148 $_->{'name'} eq $name &&
149 ($mode == 0 && $_->{'enabled'} ||
150 $mode == 1 && !$_->{'enabled'} || $mode == 2) } @$conf;
151 if (defined($sname)) {
152 # If a section was requested, limit to it
153 @rv = grep { $_->{'sectionname'} eq $sname &&
154 $_->{'sectionvalue'} eq $svalue } @rv;
156 return wantarray ? @rv : $rv[0];
159 # save_directive(&conf, name|&dir, value, [sectionname], [sectionvalue])
160 # Updates one directive in the config file
163 local ($conf, $name, $value, $sname, $svalue) = @_;
164 local $dir = ref($name) ? $name : &find($name, $conf, 0, $sname, $svalue);
165 local $newline = ref($name) ? "$name->{'name'} = $value" : "$name = $value";
167 $newline = " ".$newline;
169 if ($dir && defined($value)) {
170 # Updating some directive
171 local $lref = &read_file_lines($dir->{'file'});
172 $lref->[$dir->{'line'}] = $newline;
173 $dir->{'value'} = $value;
175 elsif ($dir && !defined($value)) {
176 # Deleting some directive
177 local $lref = &read_file_lines($dir->{'file'});
178 splice(@$lref, $dir->{'line'}, 1);
179 &renumber($conf, $dir->{'line'}, $dir->{'file'}, -1);
180 @$conf = grep { $_ ne $dir } @$conf;
182 elsif (!$dir && defined($value)) {
183 # Adding some directive .. put it after the commented version, if any
184 local $cmt = &find($name, $conf, 1, $sname, $svalue);
187 local $lref = &read_file_lines($cmt->{'file'});
188 splice(@$lref, $cmt->{'line'}+1, 0, $newline);
189 &renumber($conf, $cmt->{'line'}+1, $cmt->{'file'}, 1);
190 push(@$conf, { 'name' => $name,
192 'line' => $cmt->{'line'}+1,
193 'sectionname' => $sname,
194 'sectionvalue' => $svalue });
197 # Put at end of section
198 local @insect = grep { $_->{'sectionname'} eq $sname &&
199 $_->{'sectionvalue'} eq $svalue } @$conf;
200 @insect || &error("Failed to find section $sname $svalue !");
201 local $lref = &read_file_lines($insect[$#insect]->{'file'});
202 local $line = $insect[$#insect]->{'line'}+1;
203 splice(@$lref, $line, 0, $newline);
204 &renumber($conf, $line, $insect[$#insect]->{'file'}, 1);
205 push(@$conf, { 'name' => $name,
208 'sectionname' => $sname,
209 'sectionvalue' => $svalue });
212 # Need to put at end of main config
213 local $lref = &read_file_lines(&get_config_file());
214 push(@$lref, $newline);
215 push(@$conf, { 'name' => $name,
217 'line' => scalar(@$lref)-1,
218 'sectionname' => $sname,
219 'sectionvalue' => $svalue });
224 # save_section(&conf, §ion)
225 # Updates one section in the config file
228 local ($conf, $section) = @_;
229 local $lref = &read_file_lines($section->{'file'});
230 local $indent = " " x $section->{'indent'};
232 push(@newlines, $indent.$section->{'name'}." ".$section->{'value'}." {");
233 foreach my $m (@{$section->{'members'}}) {
234 push(@newlines, $indent." ".$m->{'name'}." = ".$m->{'value'});
236 push(@newlines, $indent."}");
237 local $oldlen = $section->{'eline'} - $section->{'line'} + 1;
238 splice(@$lref, $section->{'line'}, $oldlen, @newlines);
239 &renumber($conf, $section->{'eline'}, $section->{'file'},
240 scalar(@newlines)-$oldlen);
241 $section->{'eline'} = $section->{'line'} + scalar(@newlines) - 1;
244 # renumber(&conf, line, file, offset)
247 local ($conf, $line, $file, $offset) = @_;
248 foreach my $c (@$conf) {
249 if ($c->{'file'} eq $file) {
250 $c->{'line'} += $offset if ($c->{'line'} >= $line);
251 $c->{'eline'} += $offset if ($c->{'eline'} >= $line);
256 # is_dovecot_running()
257 # Returns the PID if the server process is active, undef if not
258 sub is_dovecot_running
260 # Try the configured PID file first
261 local $pid =&check_pid_file($config{'pid_file'});
262 return $pid if ($pid);
264 # Look in the base dir
265 local $base = &find_value("base_dir", &get_config(), 2);
266 return &check_pid_file("$base/master.pid");
270 # Returns the full path to the Dovecot init script
273 if ($config{'init_script'}) {
274 &foreign_require("init", "init-lib.pl");
275 if ($init::init_mode eq "init") {
276 return &init::action_filename($config{'init_script'});
283 # Attempts to stop the dovecot server process, returning an error message or
284 # undef if successful
287 local $script = &get_initscript();
289 local $out = &backquote_logged("$script stop 2>&1 </dev/null");
290 return $? ? "<pre>$out</pre>" : undef;
293 local $pid = &is_dovecot_running();
294 if ($pid && kill('TERM', $pid)) {
298 return $text{'stop_erunning'};
304 # Attempts to start the dovecot server process, returning an error message or
305 # undef if successful
308 local $script = &get_initscript();
309 local $cmd = $script ? "$script start" : $config{'dovecot'};
310 local $temp = &transname();
311 &system_logged("$cmd >$temp 2>&1 </dev/null &");
313 local $out = &read_file_contents($temp);
315 return &is_dovecot_running() ? undef : "<pre>$out</pre>";
318 # apply_configration()
319 # Stop and re-start the Dovecot server
320 sub apply_configuration
322 local $pid = &is_dovecot_running();
326 for(my $i=0; $i<5; $i++) {
327 $err = &start_dovecot();
334 return $text{'stop_erunning'};
338 # getdef(name, [&mapping])
339 # Returns 'Default (value)' for some config
342 local $def = &find_value($_[0], &get_config(), 1);
346 ($map) = grep { $_->[0] eq $def } @{$_[1]};
349 return "$text{'default'} ($map->[1])";
352 return "$text{'default'} ($def)";
355 return $text{'default'};
358 # get_dovecot_version()
359 # Returns the dovecot version number, or undef if not available
360 sub get_dovecot_version
362 local $out = `$config{'dovecot'} --version 2>&1`;
363 return $out =~ /([0-9\.]+)/ ? $1 : undef;
366 sub list_lock_methods
368 local ($forindex) = @_;
369 return ( "dotlock", "fcntl", "flock", $forindex ? ( ) : ( "lockf" ) );
372 # lock_dovecot_files([&conf])
373 # Lock all files in the Dovecot config
374 sub lock_dovecot_files
377 $conf ||= &get_config();
378 foreach my $f (&unique(map { $_->{'file'} } @$conf)) {
383 # unlock_dovecot_files([&conf])
384 # Release lock on all files
385 sub unlock_dovecot_files
388 $conf ||= &get_config();
389 foreach my $f (reverse(&unique(map { $_->{'file'} } @$conf))) {
394 # get_supported_protocols()
395 # Returns the list of usable protocols for the current Dovecot version
396 sub get_supported_protocols
398 if (&get_dovecot_version() >= 2) {
399 return ( "imap", "pop3", "lmtp" );
402 return ( "imap", "pop3", "imaps", "pop3s" );