1# aliases-lib.pl
2# Alias file functions
3
4# aliases_file(&config)
5# Returns the alias filenames
6sub aliases_file
7{
8if ($config{'alias_file'}) { return [ $config{'alias_file'} ]; }
9else {
10	local(@afiles, $o);
11	foreach $o (&find_type("O", $_[0])) {
12		if ($o->{'value'} =~ /^\s*AliasFile=(.*)$/) {
13			push(@afiles, split(/,/, $1));
14			}
15		}
16	map { s/dbm:// } @afiles;
17	return \@afiles;
18	}
19}
20
21# list_aliases(files)
22# Returns an array of data structures, each containing information about
23# one sendmail alias
24sub list_aliases
25{
26local $jfiles = join(",", @{$_[0]});
27local $c = $list_aliases_cache{$jfiles};
28if (!defined($c)) {
29	$c = $list_aliases_cache{$jfiles} = [ ];
30	local $file;
31	local @skip = split(/\s+/, $config{'alias_skip'});
32	foreach $file (@{$_[0]}) {
33		local $lalias;
34		local $lnum = 0;
35		local $cmt;
36		&open_readfile(AFILE, $file);
37		while(<AFILE>) {
38			s/\r|\n//g;	# remove newlines
39			if (/^\s*#+\s*(.*)/ && &is_table_comment($_, 1)) {
40				# A comment line
41				$cmt = &is_table_comment($_, 1);
42				}
43			elsif (/^(#*)\s*([^:$ \t]+)\s*:\s*(.*)$/) {
44				local(%alias, @values, $v);
45				$alias{'line'} = $cmt ? $lnum-1 : $lnum;
46				$alias{'eline'} = $lnum;
47				$alias{'file'} = $file;
48				$alias{'files'} = $_[0];
49				$alias{'enabled'} = $1 ? 0 : 1;
50				$alias{'name'} = $2;
51				$alias{'cmt'} = $cmt;
52				$v = $3;
53				$alias{'value'} = $v;
54				while($v =~ /^\s*,?\s*()"([^"]+)"(.*)$/ ||
55				      $v =~ /^\s*,?\s*(\|)"([^"]+)"(.*)$/ ||
56				      $v =~ /^\s*,?\s*()([^,\s]+)(.*)$/) {
57					push(@values, $1.$2); $v = $3;
58					}
59				$alias{'values'} = \@values;
60				$alias{'num'} = scalar(@$c);
61				if (&indexof($alias{'name'}, @skip) < 0) {
62					push(@$c, \%alias);
63					$lalias = \%alias;
64					}
65				$cmt = undef;
66				}
67			elsif (/^(#*)\s+(\S.*)$/ && $lalias &&
68			       ($1 && !$lalias->{'enabled'} ||
69				!$1 && $lalias->{'enabled'})) {
70				# continuation of last alias
71				$lalias->{'eline'} = $lnum;
72				local $v = $2;
73				$lalias->{'value'} .= $v;
74				while($v =~ /^\s*,?\s*()"([^"]+)"(.*)$/ ||
75				      $v =~ /^\s*,?\s*(\|)"([^"]+)"(.*)$/ ||
76				      $v =~ /^\s*,?\s*()([^,\s]+)(.*)$/) {
77					push(@{$lalias->{'values'}}, $1.$2); $v = $3;
78					}
79				$cmt = undef;
80				}
81			else {
82				# Some other line
83				$lalias = undef;
84				$cmt = undef;
85				}
86			$lnum++;
87			}
88		close(AFILE);
89		}
90	}
91return @$c;
92}
93
94# alias_form([alias], [no-comment])
95# Display a form for editing or creating an alias. Each alias can map to
96# 1 or more programs, files, lists or users
97sub alias_form
98{
99local ($a, $nocmt, $afile) = @_;
100local (@values, $v, $type, $val, @typenames);
101if ($a) { @values = @{$a->{'values'}}; }
102@typenames = map { $text{"aform_type$_"} } (0 .. 6);
103$typenames[0] = "&lt;$typenames[0]&gt;";
104
105# Start of form and table
106print &ui_form_start("save_alias.cgi", "post");
107if ($a) {
108	print &ui_hidden("num", $a->{'num'}),"\n";
109	}
110else {
111	print &ui_hidden("new", 1),"\n";
112	}
113print &ui_table_start($a ? $text{'aform_edit'}
114			 : $text{'aform_create'}, undef, 2);
115
116# Description
117if (!$nocmt) {
118	print &ui_table_row(&hlink($text{'aform_cmt'},"alias_cmt"),
119		&ui_textbox("cmt", $a ? $a->{'cmt'} : undef, 50));
120	}
121
122
123# Alias name
124print &ui_table_row(&hlink($text{'aform_name'},"alias_name"),
125		    &ui_textbox("name", $a ? $a->{'name'} : "", 20));
126
127# Enabled flag
128print &ui_table_row(&hlink($text{'aform_enabled'}, "alias_enabled"),
129		    &ui_yesno_radio("enabled", !$a || $a->{'enabled'} ? 1 : 0));
130
131# Alias file, if more than one possible
132if ($afile && @$afile > 1) {
133	print &ui_table_row(&hlink($text{'aform_file'}, "alias_file"),
134		&ui_select("afile", undef, $afile));
135	}
136
137# Destinations
138local @typeopts;
139for($j=0; $j<@typenames; $j++) {
140	if (!$j || $access{"aedit_$j"}) {
141		push(@typeopts, [ $j, $typenames[$j] ]);
142		}
143	}
144for($i=0; $i<=@values; $i++) {
145	($type, $val) = $values[$i] ? &alias_type($values[$i]) : (0, "");
146
147	local $typesel = &ui_select("type_$i", $type, \@typeopts);
148	local $valtxt = &ui_textbox("val_$i", $val, 30);
149	local $edlnk;
150	if ($type == 2 && $a) {
151		$edlnk = &ui_link("edit_afile.cgi?file=$val&num=$a->{'num'}",$text{'aform_afile'});
152		}
153	elsif ($type == 5 && $a) {
154		$edlnk = &ui_link("edit_rfile.cgi?file=$val&num=$a->{'num'}",$text{'aform_afile'});
155		}
156	elsif ($type == 6 && $a) {
157		$edlnk = &ui_link("edit_ffile.cgi?file=$val&num=$a->{'num'}",$text{'aform_afile'});
158		}
159	print &ui_table_row(&hlink($text{'aform_val'},"alias_to"),
160			      $typesel."\n".$valtxt."\n".$edlnk);
161	}
162
163# Table and form end
164print &ui_table_end();
165if ($a) {
166	print &ui_form_end([ [ "save", $text{'save'} ],
167			     [ "delete", $text{'delete'} ] ]);
168	}
169else {
170	print &ui_form_end([ [ "create", $text{'create'} ] ]);
171	}
172}
173
174# create_alias(&details, &files, [norebuild])
175# Create a new alias
176sub create_alias
177{
178&list_aliases($_[1]);	# force cache init
179
180# Update the config file
181local(%aliases);
182$_[0]->{'file'} ||= $_[1]->[0];
183local $lref = &read_file_lines($_[0]->{'file'});
184$_[0]->{'line'} = scalar(@$lref);
185push(@$lref, &make_table_comment($_[0]->{'cmt'}, 1));
186local $str = ($_[0]->{'enabled'} ? "" : "# ") . $_[0]->{'name'} . ": " .
187	     join(',', map { /\s/ ? "\"$_\"" : $_ } @{$_[0]->{'values'}});
188push(@$lref, $str);
189$_[0]->{'eline'} = scalar(@$lref)-1;
190&flush_file_lines($_[0]->{'file'});
191if (!$_[2]) {
192	if (!&rebuild_map_cmd($_[0]->{'file'})) {
193		&system_logged("newaliases >/dev/null 2>&1");
194		}
195	}
196
197# Add to the cache
198local $jfiles = join(",", @{$_[1]});
199local $c = $list_aliases_cache{$jfiles};
200$_[0]->{'num'} = scalar(@$c);
201push(@$c, $_[0]);
202}
203
204# delete_alias(&details, [norebuild])
205# Deletes one mail alias
206sub delete_alias
207{
208# Remove from the file
209local $lref = &read_file_lines($_[0]->{'file'});
210local $len = $_[0]->{'eline'} - $_[0]->{'line'} + 1;
211splice(@$lref, $_[0]->{'line'}, $len);
212&flush_file_lines($_[0]->{'file'});
213if (!$_[1]) {
214	if (!&rebuild_map_cmd($_[0]->{'file'})) {
215		&system_logged("newaliases >/dev/null 2>&1");
216		}
217	}
218
219# Remove from the cache
220local $jfiles = join(",", @{$_[0]->{'files'}});
221local $c = $list_aliases_cache{$jfiles};
222local $idx = &indexof($_[0], @$c);
223splice(@$c, $idx, 1) if ($idx != -1);
224&renumber_list($c, $_[0], -$len);
225}
226
227# modify_alias(&old, &details, [norebuild])
228# Update some existing alias
229sub modify_alias
230{
231# Add to the file
232local @newlines;
233push(@newlines, &make_table_comment($_[1]->{'cmt'}, 1));
234local $str = ($_[1]->{'enabled'} ? "" : "# ") . $_[1]->{'name'} . ": " .
235	     join(',', map { /\s/ ? "\"$_\"" : $_ } @{$_[1]->{'values'}});
236push(@newlines, $str);
237local $lref = &read_file_lines($_[0]->{'file'});
238local $len = $_[0]->{'eline'} - $_[0]->{'line'} + 1;
239splice(@$lref, $_[0]->{'line'}, $len, @newlines);
240&flush_file_lines($_[0]->{'file'});
241if (!$_[2]) {
242	if (!&rebuild_map_cmd($_[0]->{'file'})) {
243		&system_logged("newaliases >/dev/null 2>&1");
244		}
245	}
246
247local $jfiles = join(",", @{$_[0]->{'files'}});
248local $c = $list_aliases_cache{$jfiles};
249local $idx = &indexof($_[0], @$c);
250$_[1]->{'file'} = $_[0]->{'file'};
251$_[1]->{'line'} = $_[0]->{'line'};
252$_[1]->{'eline'} = $_[1]->{'line'}+scalar(@newlines)-1;
253$c->[$idx] = $_[1] if ($idx != -1);
254&renumber_list($c, $_[0], scalar(@newlines) - $len);
255}
256
257# alias_type(string)
258# Return the type and destination of some alias string
259sub alias_type
260{
261local @rv;
262if ($_[0] =~ /^\|$module_config_directory\/autoreply.pl\s+(\S+)/) {
263	@rv = (5, $1);
264	}
265elsif ($_[0] =~ /^\|$module_config_directory\/filter.pl\s+(\S+)/) {
266	@rv = (6, $1);
267	}
268elsif ($_[0] =~ /^\|(.*)$/) {
269	@rv = (4, $1);
270	}
271elsif ($_[0] =~ /^(\/.*)$/) {
272	@rv = (3, $1);
273	}
274elsif ($_[0] =~ /^:include:"(.*)"$/ || $_[0] =~ /^:include:(.*)$/) {
275	@rv = (2, $1);
276	}
277else {
278	@rv = (1, $_[0]);
279	}
280return wantarray ? @rv : $rv[0];
281}
282
283# lock_alias_files(&files)
284sub lock_alias_files
285{
286foreach $f (@{$_[0]}) {
287	&lock_file($f);
288	}
289}
290
291# unlock_alias_files(&files)
292sub unlock_alias_files
293{
294foreach $f (@{$_[0]}) {
295	&unlock_file($f);
296	}
297}
298
299# can_edit_alias(&alias)
300sub can_edit_alias
301{
302local ($a) = @_;
303foreach my $v (@{$a->{'values'}}) {
304	$access{"aedit_".&alias_type($v)} || return 0;
305	}
306if ($access{'amode'} == 2) {
307	$a->{'name'} =~ /$access{'aliases'}/ || return 0;
308	}
309elsif ($access{'amode'} == 3) {
310	$a->{'name'} eq $remote_user || return 0;
311	}
312return 1;
313}
314
3151;
316
317