Handle hostnames with upper-case letters
[webmin.git] / filter / save.cgi
1 #!/usr/local/bin/perl
2 # Create, update or delete a filter
3
4 require './filter-lib.pl';
5 &foreign_require("mailbox", "mailbox-lib.pl");
6 use Time::Local;
7 &ReadParse();
8
9 # Find existing filter object
10 &lock_file($procmail::procmailrc);
11 @filters = &list_filters();
12 if (!$in{'new'}) {
13         ($filter) = grep { $_->{'index'} == $in{'idx'} } @filters;
14         }
15 else {
16         $filter = { 'index' => scalar(@filters) };
17         }
18
19 if ($in{'delete'}) {
20         # Just remove
21         &delete_filter($filter);
22         }
23 else {
24         # Validate and store inputs
25         &error_setup($text{'save_err'});
26
27         # Parse condition first
28         delete($filter->{'condspam'});
29         delete($filter->{'condlevel'});
30         delete($filter->{'condheader'});
31         delete($filter->{'condtype'});
32         delete($filter->{'cond'});
33         $filter->{'body'} = 0;
34         if ($in{'cmode'} == 0) {
35                 # Always enabled, so nothing to set!
36                 }
37         elsif ($in{'cmode'} == 5) {
38                 # Match if spamassassin has set header
39                 $filter->{'condspam'} = 1;
40                 }
41         elsif ($in{'cmode'} == 6) {
42                 # Match by spam level
43                 $in{'condlevel'} =~ /^[1-9]\d*$/ ||
44                         &error($text{'save_econdlevel'});
45                 $filter->{'condlevel'} = $in{'condlevel'};
46                 }
47         elsif ($in{'cmode'} == 4) {
48                 # Check some header
49                 $filter->{'condheader'} = $in{'condmenu'} || $in{'condheader'};
50                 $filter->{'condheader'} =~ /^[a-zA-Z0-9\-]+$/ ||
51                         &error($text{'save_econdheader'});
52                 if (!$in{'condregexp'} &&
53                     $in{'condvalue'} !~ /^[a-zA-Z0-9_ ]+$/) {
54                         $in{'condvalue'} = quotemeta($in{'condvalue'});
55                         }
56                 if ($in{'condmode'} == 0) {
57                         $filter->{'condvalue'} = $in{'condvalue'};
58                         }
59                 elsif ($in{'condmode'} == 1) {
60                         $filter->{'condvalue'} = ".*".$in{'condvalue'}.".*";
61                         }
62                 else {
63                         $filter->{'condvalue'} = ".*".$in{'condvalue'}."\$";
64                         }
65                 }
66         elsif ($in{'cmode'} == 3) {
67                 # Smaller than some size
68                 $in{'condsmall'} =~ /^\d+$/ || &error($text{'save_esmall'});
69                 $filter->{'cond'} = $in{'condsmall'}*$in{'condsmall_units'};
70                 $filter->{'condtype'} = '<';
71                 }
72         elsif ($in{'cmode'} == 2) {
73                 # Larger than some size
74                 $in{'condlarge'} =~ /^\d+$/ || &error($text{'save_elarge'});
75                 $filter->{'cond'} = $in{'condlarge'}*$in{'condlarge_units'};
76                 $filter->{'condtype'} = '>';
77                 }
78         elsif ($in{'cmode'} == 1) {
79                 # Matches regexp
80                 $in{'cond'} || &error($text{'save_econd'});
81                 $filter->{'cond'} = $in{'cond'};
82                 $filter->{'body'} = $in{'body'};
83                 }
84
85         # Parse action section
86         delete($filter->{'actionreply'});
87         delete($filter->{'actionspam'});
88         delete($filter->{'actionthrow'});
89         delete($filter->{'actiondefault'});
90         delete($filter->{'actionreply'});
91         delete($filter->{'actiontype'});
92         delete($filter->{'continue'});
93         if ($in{'amode'} == 3) {
94                 # Deliver normally
95                 $filter->{'actiondefault'} = 1;
96                 }
97         elsif ($in{'amode'} == 5) {
98                 # Run spamassassin
99                 $filter->{'actionspam'} = 1;
100                 }
101         elsif ($in{'amode'} == 4) {
102                 # Throw away
103                 $filter->{'actionthrow'} = 1;
104                 }
105         elsif ($in{'amode'} == 1) {
106                 # Forward to an address
107                 $in{'forward'} =~ /\S/ || &error($text{'save_eforward'});
108                 $in{'forward'} =~ s/^\s+//;
109                 $in{'forward'} =~ s/\s+$//;
110                 $in{'forward'} =~ s/\s+/,/g;
111                 $filter->{'action'} = $in{'forward'};
112                 $filter->{'actiontype'} = '!';
113                 $filter->{'nobounce'} = $in{'nobounce'};
114                 }
115         elsif ($in{'amode'} == 0) {
116                 # Write to a folder or file
117                 @folders = &mailbox::list_folders();
118                 if ($in{'folder'}) {
119                         $folder = &mailbox::find_named_folder($in{'folder'},
120                                                               \@folders);
121                         $file = $folder->{'file'};
122                         }
123                 else {
124                         $in{'file'} =~ /\S/ || &error($text{'save_efile'});
125                         $file = $in{'file'};
126                         }
127                 $file =~ s/^\Q$remote_user_info[7]\/\E/\$HOME\//;
128                 $filter->{'action'} = $file;
129                 if ($folder->{'type'} == 1 ||
130                     $folder->{'type'} == 4 && -d $folder->{'file'}) {
131                         # Maildir has to end with /
132                         $filter->{'action'} .= '/';
133                         }
134                 }
135         elsif ($in{'amode'} == 6) {
136                 # Send autoreply
137                 $filter->{'actionreply'} = 1;
138                 $in{'reply'} =~ /\S/ || &error($text{'save_ereply'});
139                 $in{'reply'} =~ s/\r//g;
140                 $filter->{'reply'}->{'autotext'} = $in{'reply'};
141                 $filter->{'reply'}->{'from'} =
142                         &mailbox::get_preferred_from_address();
143                 $idx = defined($filter->{'index'}) ? $filter->{'index'}
144                                                    : scalar(@filters);
145                 $filter->{'reply'}->{'autoreply'} ||=
146                         "$remote_user_info[7]/autoreply.$idx.txt";
147                 if ($config{'reply_force'}) {
148                         # Forced to minimum
149                         $min = $config{'reply_min'} || 60;
150                         $filter->{'reply'}->{'period'} = $min*60;
151                         $filter->{'reply'}->{'replies'} ||=
152                                 "$user_module_config_directory/replies";
153                         }
154                 elsif ($in{'period_def'}) {
155                         # No autoreply period
156                         delete($filter->{'reply'}->{'replies'});
157                         delete($filter->{'reply'}->{'period'});
158                         }
159                 else {
160                         # Set reply period and tracking file
161                         $in{'period'} =~ /^\d+$/ ||
162                                 &error($text{'save_eperiod'});
163                         if ($config{'reply_min'} &&
164                             $in{'period'} < $config{'reply_min'}) {
165                                 &error(&text('save_eperiodmin',
166                                              $config{'reply_min'}));
167                                 }
168                         $filter->{'reply'}->{'period'} = $in{'period'}*60;
169                         $filter->{'reply'}->{'replies'} ||=
170                                 "$user_module_config_directory/replies";
171                         }
172                 # Save autoreply start and end
173                 foreach $p ('start', 'end') {
174                         local ($s, $m, $h) = $p eq 'start' ? (0, 0, 0) :
175                                                 (59, 59, 23);
176                         if ($in{'d'.$p}) {
177                                 $tm = timelocal($s, $m, $h, $in{'d'.$p},
178                                         $in{'m'.$p}-1, $in{'y'.$p}-1900);
179                                 $tm || &error($text{'save_e'.$p});
180                                 $filter->{'reply'}->{'autoreply_'.$p} = $tm;
181                                 }
182                         else {
183                                 delete($filter->{'reply'}->{'autoreply_'.$p});
184                                 }
185                         }
186                 # Save character set
187                 if ($in{'charset_def'}) {
188                         delete($filter->{'reply'}->{'charset'});
189                         }
190                 else {
191                         $in{'charset'} =~ /^[a-z0-9\.\-\_]+$/i ||
192                                 error($text{'save_echarset'});
193                         $filter->{'reply'}->{'charset'} = $in{'charset'};
194                         }
195                 }
196         elsif ($in{'amode'} == 7) {
197                 # Create a new folder for saving (always in Maildir format)
198                 $in{'newfolder'} =~ /\S/ || &error($text{'save_enewfolder'});
199                 $in{'newfolder'} !~ /^\// && $in{'newfolder'} !~ /\.\./ ||
200                         &error($text{'save_enewfolder2'});
201                 ($clash) = grep { $_->{'name'} eq $in{'newfolder'} } 
202                                 @folders;
203                 $clash && &error($text{'save_enewfolder3'});
204                 $folder = { 'name' => $in{'newfolder'},
205                             'mode' => 0,
206                             'type' => 1 };
207                 &mailbox::save_folder($folder);
208                 $filter->{'action'} = $folder->{'file'}."/";
209                 $filter->{'action'} =~ s/^\Q$remote_user_info[7]\/\E/\$HOME\//;
210                 }
211         $filter->{'continue'} = $in{'continue'};
212
213         # Save or create
214         if ($in{'new'}) {
215                 &create_filter($filter);
216                 }
217         else {
218                 &modify_filter($filter);
219                 }
220         }
221 &unlock_file($procmail::procmailrc);
222 &redirect("");