Sharedwww / cgi-bin / openwebmail / openwebmail-tool.plOpen in CoCalc
Author: William A. Stein
1
#!/usr/bin/perl
2
#
3
# openwebmail-tool.pl - command tool for mail/event/notify/index...
4
#
5
# 03/27/2003 tung.AT.turtle.ee.ncku.edu.tw
6
# Ebola.AT.turtle.ee.ncku.edu.tw
7
#
8
use vars qw($SCRIPT_DIR);
9
if ( $0 =~ m!^(\S*)/[\w\d\-\.]+\.pl! ) { $SCRIPT_DIR=$1 }
10
if ($SCRIPT_DIR eq '' && open(F, '/etc/openwebmail/openwebmail_path.conf')) {
11
$_=<F>; close(F); if ( $_=~/^(\S*)/) { $SCRIPT_DIR=$1 }
12
}
13
if ($SCRIPT_DIR eq '') {
14
print qq|\nOpen WebMail is unable to locate itself on this system,\n|.
15
qq|please put 'the path of openwebmail CGI directory' to\n|.
16
qq|the first line of file /etc/openwebmail/openwebmail_path.conf\n\n|.
17
qq|For example, if the script is\n\n|.
18
qq|/usr/local/www/cgi-bin/openwebmail/openwebmail-tool.pl,\n\n|.
19
qq|then the content of /etc/openwebmail/openwebmail_path.conf should be:\n\n|.
20
qq|/usr/local/www/cgi-bin/openwebmail/\n\n|;
21
exit 0;
22
}
23
push (@INC, $SCRIPT_DIR);
24
25
foreach (qw(ENV BASH_ENV CDPATH IFS TERM)) {delete $ENV{$_}}; $ENV{PATH}='/bin:/usr/bin'; # secure ENV
26
umask(0002); # make sure the openwebmail group can write
27
28
use strict;
29
use Fcntl qw(:DEFAULT :flock);
30
use Net::SMTP;
31
32
require "modules/dbm.pl";
33
require "modules/suid.pl";
34
require "modules/filelock.pl";
35
require "modules/tool.pl";
36
require "modules/execute.pl";
37
require "modules/datetime.pl";
38
require "modules/lang.pl";
39
require "modules/mime.pl";
40
require "modules/mailparse.pl";
41
require "modules/spamcheck.pl";
42
require "modules/viruscheck.pl";
43
require "auth/auth.pl";
44
require "quota/quota.pl";
45
require "shares/ow-shared.pl";
46
require "shares/maildb.pl";
47
require "shares/lockget.pl";
48
require "shares/cut.pl";
49
require "shares/mailfilter.pl";
50
require "shares/fetchmail.pl";
51
require "shares/pop3book.pl";
52
require "shares/calbook.pl";
53
require "shares/lunar.pl";
54
require "shares/iconv-chinese.pl";
55
require "shares/upgrade.pl";
56
57
# common globals
58
use vars qw(%config %config_raw);
59
use vars qw($default_logindomain $loginname $logindomain $loginuser);
60
use vars qw($domain $user $userrealname $uuid $ugid $homedir);
61
use vars qw(%prefs);
62
63
# extern vars
64
use vars qw(%is_config_option); # from ow-shared.pl
65
use vars qw($DBVERSION $_OFFSET $_FROM $_TO $_DATE $_SUBJECT $_CONTENT_TYPE $_STATUS $_SIZE $_REFERENCES $_CHARSET $_HEADERSIZE $_HEADERCHKSUM);
66
use vars qw(%is_internal_dbkey); # from maildb.pl
67
68
# local globals
69
use vars qw($POP3_TIMEOUT %opt);
70
71
########## main ##################################################
72
openwebmail_requestbegin();
73
$SIG{PIPE}=\&openwebmail_exit; # for user stop
74
$SIG{TERM}=\&openwebmail_exit; # for user stop
75
$SIG{CHLD}='IGNORE'; # prevent zombie
76
77
$POP3_TIMEOUT=20;
78
79
%opt=('null'=>1);
80
$default_logindomain="";
81
82
my @list=();
83
84
# set to ruid for secure access, this will be set to euid $>
85
# if operation is from inetd or -m (query mail status ) or -e(query event status)
86
my $euid_to_use=$<;
87
88
# no buffer on stdout
89
local $|=1;
90
91
if ($ARGV[0] eq "--") { # called by inetd
92
push(@list, $ARGV[1]);
93
$opt{'mail'}=1; $opt{'event'}=1; $opt{'null'}=0; $euid_to_use=$>;
94
} else {
95
for (my $i=0; $i<=$#ARGV; $i++) {
96
if ($ARGV[$i] eq "--init") {
97
$opt{'init'}=1;
98
} elsif ($ARGV[$i] eq "--test") {
99
$opt{'test'}=1;
100
101
} elsif ($ARGV[$i] eq "--yes" || $ARGV[$i] eq "-y") {
102
$opt{'yes'}=1;
103
} elsif ($ARGV[$i] eq "--no") {
104
$opt{'no'}=1;
105
} elsif ($ARGV[$i] eq "--debug") {
106
$opt{'debug'}=1;
107
} elsif ($ARGV[$i] eq "--quiet" || $ARGV[$i] eq "-q") {
108
$opt{'quiet'}=1;
109
110
} elsif ($ARGV[$i] eq "--domain" || $ARGV[$i] eq "-d") {
111
$i++ if $ARGV[$i+1]!~/^\-/;
112
$default_logindomain=safedomainname($ARGV[$i]);
113
} elsif ($ARGV[$i] eq "--alluser" || $ARGV[$i] eq "-a") {
114
$opt{'allusers'}=1;
115
} elsif ($ARGV[$i] eq "--file" || $ARGV[$i] eq "-f") {
116
$i++;
117
if ( -f $ARGV[$i] ) {
118
open(F, $ARGV[$i]);
119
while (<F>) { chomp $_; push(@list, $_); }
120
close(F);
121
}
122
123
} elsif ($ARGV[$i] eq "--thumbnail" || $ARGV[$i] eq "-t") {
124
$opt{'thumbnail'}=1;
125
126
} elsif ($ARGV[$i] eq "--index" || $ARGV[$i] eq "-i") {
127
$opt{'iv'}='ALL'; $opt{'null'}=0; $euid_to_use=$<;
128
} elsif ($ARGV[$i] eq "-id") {
129
$i++; $opt{'id'}=$ARGV[$i]; $opt{'null'}=0;
130
} elsif ($ARGV[$i] eq "-iv") {
131
$i++; $opt{'iv'}=$ARGV[$i]; $opt{'null'}=0;
132
} elsif ($ARGV[$i] eq "-if") {
133
$i++; $opt{'if'}=$ARGV[$i]; $opt{'null'}=0;
134
} elsif ($ARGV[$i] eq "-ir") {
135
$i++; $opt{'ir'}=$ARGV[$i]; $opt{'null'}=0;
136
} elsif ($ARGV[$i] eq "-iz") {
137
$i++; $opt{'iz'}=$ARGV[$i]; $opt{'null'}=0;
138
139
} elsif ($ARGV[$i] eq "--mail" || $ARGV[$i] eq "-m") {
140
$opt{'mail'}=1; $opt{'null'}=0; $euid_to_use=$>;
141
} elsif ($ARGV[$i] eq "--event" || $ARGV[$i] eq "-e") {
142
$opt{'event'}=1; $opt{'null'}=0; $euid_to_use=$>;
143
} elsif ($ARGV[$i] eq "--notify" || $ARGV[$i] eq "-n") {
144
$opt{'notify'}=1; $opt{'null'}=0;
145
146
} elsif ($ARGV[$i] eq "--pop3" || $ARGV[$i] eq "-p") {
147
$opt{'pop3'}=1; $opt{'null'}=0;
148
} elsif ($ARGV[$i] eq "--size" || $ARGV[$i] eq "-s") {
149
$opt{'size'}=1; $opt{'null'}=0;
150
} elsif ($ARGV[$i] eq "--zaptrash" || $ARGV[$i] eq "-z") {
151
$opt{'zap'}=1; $opt{'null'}=0;
152
153
} else {
154
push(@list, $ARGV[$i]);
155
}
156
}
157
}
158
159
$>=$euid_to_use;
160
161
my $retval=0;
162
if ($opt{'init'}) {
163
$retval=init();
164
} elsif ($opt{'test'}) {
165
$retval=do_test();
166
} elsif ($opt{'thumbnail'}) {
167
$retval=makethumbnail(\@list);
168
} else {
169
if ($opt{'allusers'}) {
170
$retval=allusers(\@list);
171
openwebmail_exit($retval) if ($retval<0);
172
}
173
if ($#list>=0 && !$opt{'null'}) {
174
$retval=usertool($euid_to_use, \@list);
175
} else {
176
$retval=showhelp();
177
}
178
}
179
180
openwebmail_exit($retval);
181
182
########## showhelp ##############################################
183
sub showhelp {
184
print "
185
Syntax: openwebmail-tool.pl --init [options]
186
openwebmail-tool.pl --test
187
openwebmail-tool.pl -t [options] [image1 image2 ...]
188
openwebmail-tool.pl [options] [user1 user2 ...]
189
190
common options:
191
-q, --quite \t quiet, no output
192
--debug \t print debug information
193
194
init options:
195
-y, --yes \t default answer yes to send site report
196
--no \t default answer no to send site report
197
198
thumbnail option:
199
-f <imglist> \t image list from file, each line for one path
200
-t, --thumbnail make thumbnail for images
201
202
mail/calendar options:
203
-a, --alluser\t check for all users in all domains
204
-d, --domain \t default domain for user with no domain specified
205
-e, --event \t check today's calendar event
206
-f <userlist>\t userlist from file, each line for one user
207
-i, --index \t verify index of all folders and reindex if needed
208
-id <folder> \t dump index of folder
209
-iv <folder> \t verify index of folder and reindex if needed
210
-if <folder> \t fast rebuild index of folder
211
-ir <folder> \t rebuild index of folder
212
-iz <folder> \t clear zap messages from folder
213
-m, --mail \t check new mail
214
-n, --notify \t check and send calendar notification email
215
-p, --pop3 \t fetch pop3 mail for user
216
-s, --size \t check user quota and cut mails/files if over quotalimit
217
-z, --zaptrash\t remove stale messages from trash folder
218
219
ps: <folder> can be INBOX, ALL or folder filename
220
221
";
222
return 1;
223
}
224
225
########## init ##################################################
226
sub init {
227
print "\n";
228
229
my $err=do_test(1);
230
if ($err<0) {
231
print qq|And execute '$SCRIPT_DIR/openwebmail-tool.pl --init' again!\n\n|.
232
qq|ps: If you are running openwebmail in persistent mode,\n|.
233
qq| don't forget to 'touch openwebmail*.pl', so speedycgi\n|.
234
qq| will reload all scripts, modules and conf files in --init.\n\n|;
235
return $err;
236
}
237
238
foreach my $table ('b2g', 'g2b', 'lunar') {
239
if ( $config{$table.'_map'} ) {
240
my $tabledb="$config{'ow_mapsdir'}/$table";
241
my $err=0;
242
if (ow::dbm::exist($tabledb)) {
243
my %T;
244
if (!ow::dbm::open(\%T, $tabledb, LOCK_SH) ||
245
!ow::dbm::close(\%T, $tabledb) ) {
246
ow::dbm::unlink($tabledb);
247
print "delete old db $tabledb\n";
248
}
249
}
250
if ( !ow::dbm::exist($tabledb)) {
251
die "$config{$table.'_map'} not found" if (!-f $config{$table.'_map'});
252
print "creating db $config{'ow_mapsdir'}/$table ...";
253
254
$err=-2 if ($table eq 'b2g' and mkdb_b2g()<0);
255
$err=-3 if ($table eq 'g2b' and mkdb_g2b()<0);
256
$err=-4 if ($table eq 'lunar' and mkdb_lunar()<0);
257
if ($err < 0) {
258
print "error!\n"; return $err;
259
}
260
print "done.\n";
261
}
262
}
263
}
264
265
#
266
# This should be discused on Debian-devel
267
#
268
return (0);
269
270
%prefs = readprefs(); # send_mail() uses $prefs{...}
271
272
my $id = $ENV{'USER'} || $ENV{'LOGNAME'} || getlogin || (getpwuid($>))[0];
273
my $hostname=ow::tool::hostname();
274
my $realname=(getpwnam($id))[6]||$id;
275
my $to="openwebmail\@turtle.ee.ncku.edu.tw";
276
my $date = ow::datetime::dateserial2datefield(ow::datetime::gmtime2dateserial(), $config{'default_timeoffset'}, $prefs{'daylightsaving'});
277
my $subject="site report - $hostname";
278
my $os;
279
if ( -f "/usr/bin/uname") {
280
$os=`/usr/bin/uname -srm`; chomp($os);
281
} else {
282
$os=`/bin/uname -srm`; chomp($os);
283
}
284
my $content=qq|OS: $os\n|.
285
qq|Perl: $]\n|.
286
qq|WebMail: $config{'name'} $config{'version'} $config{'releasedate'}\n|;
287
288
if ($opt{'yes'}) {
289
print qq|$content\n|.
290
qq|sending site report...\n|;
291
send_mail("$id\@$hostname", $realname, $to, $date, $subject, "$content \n");
292
} elsif ($opt{'no'} or $opt{'debug'}) {
293
print qq|$content\n|.
294
qq|No site report sent.\n|;
295
} else {
296
print qq|Welcome to the Open WebMail!\n\n|.
297
qq|This program is going to send a short message back to the developer,\n|.
298
qq|so we could have the idea that who is installing and how many sites are\n|.
299
qq|using this software, the content to be sent is:\n\n|.
300
qq|$content\n|.
301
qq|Send the site report?(Y/n) |;
302
$_=<STDIN>;
303
if ($_!~/n/i) {
304
print qq|sending report...\n|;
305
send_mail("$id\@$hostname", $realname, $to, $date, $subject, "$content \n")
306
}
307
}
308
print qq|\nThank you.\n\n|;
309
return 0;
310
}
311
312
sub do_test {
313
my ($in_init)[email protected]_;
314
my $err=0;
315
print "\n";
316
317
load_owconf(\%config_raw, "/usr/share/openwebmail/configs/openwebmail.conf");
318
if ( -f "/etc/openwebmail/openwebmail.conf") {
319
read_owconf(\%config, \%config_raw, "/etc/openwebmail/openwebmail.conf");
320
print "D readconf /etc/openwebmail/openwebmail.conf\n" if ($opt{'debug'});
321
}
322
323
$logindomain=$default_logindomain||ow::tool::hostname();
324
$logindomain=lc(safedomainname($logindomain));
325
$logindomain=$config{'domainname_equiv'}{'map'}{$logindomain} if (defined($config{'domainname_equiv'}{'map'}{$logindomain}));
326
if ( -f "$config{'ow_sitesconfdir'}/$logindomain") {
327
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain");
328
print "D readconf $config{'ow_sitesconfdir'}/$logindomain\n" if ($opt{'debug'});
329
}
330
331
# disable this warning to make user happy...
332
# if ($in_init && check_tell_bug() <0) {
333
# print qq|Please hit 'Enter' to continue or Ctrl-C to break.\n|;
334
# $_=<STDIN> if (!$opt{'yes'} && !$opt{'no'});
335
# }
336
337
my ($dbm_ext, $dbmopen_ext, $dbmopen_haslock)=ow::dbm::guessoptions();
338
339
print_dbm_module() if (!$in_init);
340
341
$err-- if (check_db_file_pm()<0);
342
$err-- if (check_dbm_option($in_init, $dbm_ext, $dbmopen_ext, $dbmopen_haslock)<0);
343
$err-- if (check_savedsuid_support()<0);
344
345
return $err;
346
}
347
348
sub check_tell_bug {
349
my $offset;
350
my $testfile=ow::tool::untaint("/tmp/testfile.$$");
351
352
open(F, ">$testfile"); print F "test"; close(F);
353
open(F, ">>$testfile"); $offset=tell(F); close(F);
354
unlink($testfile);
355
356
# if ($offset==0) {
357
# print qq|WARNING!\n\n|.
358
# qq|The perl on your system has serious bug in routine tell()!\n|.
359
# qq|While openwebmail can work properly with this bug, other perl application\n|.
360
# qq|may not function properly and thus cause data loss.\n\n|.
361
# qq|We suggest that you should patch your perl as soon as possible.\n\n\n|;
362
# return -1;
363
# }
364
return 0;
365
}
366
367
sub print_dbm_module {
368
print "You perl uses the following packages for dbm:\n\n";
369
my @pm;
370
foreach (keys %INC) { push (@pm, $_) if (/DB.*File/); }
371
foreach (sort @pm) { print "$_\t\t$INC{$_}\n"; }
372
print "\n\n";
373
}
374
375
sub check_db_file_pm {
376
my $dbfile_pm=$INC{'DB_File.pm'};
377
if ($dbfile_pm) {
378
my $t;
379
open(F, $dbfile_pm); while(<F>) {$t.=$_;} close(F);
380
$t=~s/\s//gms;
381
if ($t!~/\$arg\[3\]=0666unlessdefined\$arg\[3\];/sm
382
&& $t!~/\$arg\[3\]=0666if\@arg>=4&&!defined\$arg\[3\];/sm) {
383
print qq|Please modify $dbfile_pm by adding\n\n|.
384
qq|\t\$arg[3] = 0666 unless defined \$arg[3];\n\n|.
385
qq|before the following text (about line 247)\n\n|.
386
qq|\t# make recno in Berkeley DB version 2 work like recno in version 1\n\n\n|.
387
qq|\tFor more information, please have a look to the README.Debian\n\n\n|;
388
return 0;
389
}
390
}
391
return 0;
392
}
393
394
sub check_dbm_option {
395
my ($in_init, $dbm_ext, $dbmopen_ext, $dbmopen_haslock)[email protected]_;
396
397
my $err=0;
398
if ($dbm_ext ne $ow::dbm::dbm_ext ||
399
$dbmopen_ext ne $ow::dbm::dbmopen_ext ||
400
($dbmopen_haslock ne $ow::dbm::dbmopen_haslock && $dbmopen_haslock) ) {
401
$err++;
402
}
403
404
my %str;
405
@str{'dbm_ext', 'dbmopen_ext', 'dbmopen_haslock'}=
406
($dbm_ext, $dbmopen_ext, $dbmopen_haslock);
407
@str{'conf_dbm_ext', 'conf_dbmopen_ext', 'conf_dbmopen_haslock'}=
408
($ow::dbm::dbm_ext, $ow::dbm::dbmopen_ext, $ow::dbm::dbmopen_haslock);
409
foreach ('dbm_ext', 'dbmopen_ext', 'conf_dbm_ext', 'conf_dbmopen_ext') {
410
$str{$_}='none' if ($str{$_} eq '');
411
}
412
foreach ('dbmopen_haslock', 'conf_dbmopen_haslock') {
413
if ($str{$_}) {
414
$str{$_}='yes';
415
} else {
416
$str{$_}='no';
417
}
418
}
419
420
if ($in_init && $err) {
421
print qq|Please change '/etc/openwebmail/dbm.conf' from\n\n|.
422
qq|dbm_ext \t$str{conf_dbm_ext}\n|.
423
qq|dbmopen_ext \t$str{conf_dbmopen_ext}\n|.
424
qq|dbmopen_haslock \t$str{conf_dbmopen_haslock}\n|.
425
qq|\nto\n\n|.
426
qq|dbm_ext \t$str{dbm_ext}\n|.
427
qq|dbmopen_ext \t$str{dbmopen_ext}\n|.
428
qq|dbmopen_haslock \t$str{dbmopen_haslock}\n\n\n|;
429
}
430
if (!$in_init) {
431
print qq|'/etc/openwebmail/dbm.conf' should be set as follows:\n\n|.
432
qq|dbm_ext \t$str{dbm_ext}\n|.
433
qq|dbmopen_ext \t$str{dbmopen_ext}\n|.
434
qq|dbmopen_haslock \t$str{dbmopen_haslock}\n\n\n|;
435
}
436
437
return -1 if ($err);
438
return 0;
439
}
440
441
sub check_savedsuid_support {
442
return if ($>!=0);
443
444
$>=65534;
445
$>=0;
446
if ($>!=0) {
447
print qq|Your system didn't have saved suid support,\n|.
448
qq|please set the following option in $SCRIPT_DIR/etc/suid.conf\n\n|.
449
qq|\thas_savedsuid_support no\n\n\n|;
450
return -1;
451
}
452
return 0;
453
}
454
455
########## make_thumbnail ########################################
456
sub makethumbnail {
457
my $r_files=$_[0];
458
my $err=0;
459
460
my $convertbin=ow::tool::findbin("convert");
461
if ($convertbin eq '') {
462
print "Program convert doesn't exist\n" if (!$opt{'quiet'});
463
return -1;
464
}
465
my @cmd=($convertbin, '+profile', '*', '-interlace', 'NONE', '-geometry', '64x64');
466
467
foreach my $image (@{$r_files}) {
468
next if ( $image!~/\.(jpe?g|gif|png|bmp|tif)$/i || !-f $image);
469
470
my $thumbnail=ow::tool::untaint(path2thumbnail($image));
471
my @p=split(/\//, $thumbnail); pop(@p);
472
my $thumbnaildir=join('/', @p);
473
if (!-d "$thumbnaildir") {
474
if (!mkdir (ow::tool::untaint("$thumbnaildir"), 0755)) {
475
print "$!\n" if (!$opt{'quiet'});
476
$err++; next;
477
}
478
}
479
480
my ($img_atime,$img_mtime)= (stat($image))[8,9];
481
if (-f $thumbnail) {
482
my ($thumbnail_atime,$thumbnail_mtime)= (stat($thumbnail))[8,9];
483
if ($thumbnail_mtime==$img_mtime) {
484
print "$thumbnail already exist.\n" if (!$opt{'quiet'});
485
next;
486
}
487
}
488
my ($stdout, $stderr, $exit, $sig)=ow::execute::execute(@cmd, $image, $thumbnail);
489
490
if (!$opt{'quiet'}) {
491
print "$thumbnail";
492
if ($exit||$sig) {
493
print ", exit $exit" if ($exit);
494
print ", signal $sig" if ($sig);
495
print "\n";
496
print "($stderr)\n" if ($stderr);
497
$err++; next;
498
} else {
499
print "\n";
500
}
501
}
502
503
if (-f "$thumbnail.0") { # use 1st thumbnail of merged gifs
504
my @f;
505
foreach (1..20) {
506
push(@f, "$thumbnail.$_");
507
}
508
unlink @f;
509
rename("$thumbnail.0", $thumbnail);
510
}
511
if (-f $thumbnail) {
512
utime(ow::tool::untaint($img_atime), ow::tool::untaint($img_mtime), $thumbnail)
513
}
514
}
515
return($err);
516
}
517
518
sub path2thumbnail {
519
my @p=split(/\//, $_[0]);
520
my $tfile=pop(@p); $tfile=~s/\.[^\.]*$/\.jpg/i;
521
push(@p, '.thumbnail');
522
return(join('/',@p)."/$tfile");
523
}
524
525
526
########## user folder/calendar routines #########################
527
sub allusers {
528
my $r_list=$_[0];
529
my $loaded_domain=0;
530
my %userhash=();
531
532
load_owconf(\%config_raw, "/usr/share/openwebmail/configs/openwebmail.conf");
533
if ( -f "/etc/openwebmail/openwebmail.conf") {
534
read_owconf(\%config, \%config_raw, "/etc/openwebmail/openwebmail.conf");
535
print "D readconf /etc/openwebmail/openwebmail.conf\n" if ($opt{'debug'});
536
}
537
538
# trap this once now. Let usertool() test it at the domain level later
539
if ( $>!=0 && # setuid is required if spool is located in system dir
540
($config{'mailspooldir'} eq "/var/mail" ||
541
$config{'mailspooldir'} eq "/var/spool/mail")) {
542
print "This operation is only available to root\n"; openwebmail_exit(0);
543
}
544
545
my $logindomain=$default_logindomain||ow::tool::hostname();
546
$logindomain=lc(safedomainname($logindomain));
547
$logindomain=$config{'domainname_equiv'}{'map'}{$logindomain} if (defined($config{'domainname_equiv'}{'map'}{$logindomain}));
548
print "D found default domain $logindomain\n" if ($opt{'debug'});
549
550
# if there's localusers defined for vdomain,
551
# we should grab them otherwise they'll be missed
552
foreach (@{$config{'localusers'}}) {
553
if (/^(.+)\@(.+)$/) {
554
$userhash{$2}{$1}=1;
555
} else {
556
$userhash{$logindomain}{$_}=1;
557
}
558
}
559
560
my @domains=($logindomain);
561
foreach (alldomains()) {
562
push(@domains, $_) if ($_ ne $logindomain);
563
}
564
565
foreach $logindomain (@domains) {
566
%config_raw=();
567
load_owconf(\%config_raw, "/usr/share/openwebmail/configs/openwebmail.conf");
568
if ( -f "/etc/openwebmail/openwebmail.conf") {
569
read_owconf(\%config, \%config_raw, "/etc/openwebmail/openwebmail.conf");
570
print "D readconf /etc/openwebmail/openwebmail.conf\n" if ($opt{'debug'});
571
}
572
573
if ( -f "$config{'ow_sitesconfdir'}/$logindomain") {
574
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain");
575
print "D readconf $config{'ow_sitesconfdir'}/$logindomain\n" if ($opt{'debug'});
576
}
577
578
ow::auth::load($config{'auth_module'});
579
print "D ow::auth::load $config{'auth_module'}\n" if ($opt{'debug'});
580
581
my ($errcode, $errmsg, @userlist)=ow::auth::get_userlist(\%config);
582
if ($errcode!=0) {
583
writelog("userlist error - $config{'auth_module'}, ret $errcode , $errmsg");
584
if ($errcode==-1) {
585
print "-a is not supported by $config{'auth_module'}, use -f instead\n" if (!$opt{'quiet'});
586
} else {
587
print "Unable to get userlist, error code $errcode\n" if (!$opt{'quiet'});
588
}
589
} else {
590
$loaded_domain++;
591
foreach (@userlist) {
592
if (/^(.+)\@(.+)$/) {
593
$userhash{$2}{$1}=1;
594
} else {
595
$userhash{$logindomain}{$_}=1;
596
}
597
}
598
}
599
}
600
601
foreach $logindomain ( sort keys %userhash ) {
602
foreach (sort keys %{$userhash{$logindomain}}) {
603
push @{$r_list}, "$_\@$logindomain";
604
}
605
}
606
607
return if ($loaded_domain>0);
608
return -1;
609
}
610
611
612
sub alldomains {
613
my %domainnames=();
614
615
if ( ! opendir(SITEDIR, $config{'ow_sitesconfdir'})){
616
writelog("siteconf dir error $config{'ow_sitesconfdir'} $!");
617
print "Unable to read siteconf dir $config{'ow_sitesconfdir'} $!\n" if (!$opt{'quiet'});
618
return -1;
619
}
620
while ($domain=readdir(SITEDIR)) {
621
next if ($domain=~/^(\.|readme|sameple)/i);
622
$domainnames{$domain}=1;
623
print "D found domain $domain\n" if ($opt{'debug'});
624
}
625
closedir(SITEDIR);
626
627
return(keys %domainnames);
628
}
629
630
sub usertool {
631
my ($euid_to_use, $r_userlist)=@_;
632
my $hostname=ow::tool::hostname();
633
my %homedir_processed=();
634
my $usercount=0;
635
636
foreach $loginname (@{$r_userlist}) {
637
# reset back to init $euid before switch to next user
638
#$>=0;
639
$>=$euid_to_use;
640
641
%config_raw=();
642
load_owconf(\%config_raw, "/usr/share/openwebmail/configs/openwebmail.conf");
643
if ( -f "/etc/openwebmail/openwebmail.conf") {
644
read_owconf(\%config, \%config_raw, "/etc/openwebmail/openwebmail.conf");
645
print "D readconf /etc/openwebmail/openwebmail.conf\n" if ($opt{'debug'});
646
}
647
648
if ($config{'smtpauth'}) { # load smtp auth user/pass
649
read_owconf(\%config, \%config_raw, "$SCRIPT_DIR/etc/smtpauth.conf");
650
if ($config{'smtpauth_username'} eq "" || $config{'smtpauth_password'} eq "") {
651
die "Invalid username/password in $SCRIPT_DIR/etc/smtpauth.conf!";
652
}
653
}
654
655
if ($loginname=~/^(.+)\@(.+)$/) {
656
($loginuser, $logindomain)=($1, $2);
657
} else {
658
$loginuser=$loginname;
659
$logindomain=$default_logindomain||$hostname;
660
}
661
$loginuser=lc($loginuser) if ($config{'case_insensitive_login'});
662
$logindomain=lc(safedomainname($logindomain));
663
print "D loginuser=$loginuser, logindomain=$logindomain\n" if ($opt{'debug'});
664
665
if (defined($config{'domainname_equiv'}{'map'}{$logindomain})) {
666
$logindomain=$config{'domainname_equiv'}{'map'}{$logindomain};
667
print "D logindomain equiv to $logindomain\n" if ($opt{'debug'});
668
}
669
670
if (!is_localuser("$loginuser\@$logindomain") && -f "$config{'ow_sitesconfdir'}/$logindomain") {
671
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain");
672
print "D readconf $config{'ow_sitesconfdir'}/$logindomain\n" if ($opt{'debug'});
673
}
674
ow::auth::load($config{'auth_module'});
675
print "D ow::auth::load $config{'auth_module'}\n" if ($opt{'debug'});
676
677
update_virtuserdb(); # update index db of virtusertable
678
679
($domain, $user, $userrealname, $uuid, $ugid, $homedir)
680
=get_domain_user_userinfo($logindomain, $loginuser);
681
if ($opt{'debug'}) {
682
print "D get_domain_user_info()\n";
683
print "D domain=$domain (auth_withdomain=$config{'auth_withdomain'})\n";
684
print "D user=$user, realname=$userrealname\n";
685
print "D uuid=$uuid, ugid=$ugid, homedir=$homedir\n";
686
}
687
688
if ($user eq "") {
689
print "user $loginname doesn't exist\n" if (!$opt{'quiet'});
690
next;
691
}
692
if ($user eq 'root' || $user eq 'toor'||
693
$user eq 'daemon' || $user eq 'operator' || $user eq 'bin' ||
694
$user eq 'tty' || $user eq 'kmem' || $user eq 'uucp') {
695
print "D system user $user, skipped!\n" if ($opt{'debug'});
696
next;
697
}
698
699
if ( $>!=$uuid &&
700
$>!=0 && # setuid root is required if spool is located in system dir
701
($config{'mailspooldir'} eq "/var/mail" ||
702
$config{'mailspooldir'} eq "/var/spool/mail")) {
703
print "This operation is only available to root\n"; openwebmail_exit(0);
704
}
705
706
# load user config
707
my $userconf="$config{'ow_usersconfdir'}/$user";
708
$userconf="$config{'ow_usersconfdir'}/$domain/$user" if ($config{'auth_withdomain'});
709
if ( -f "$userconf") {
710
read_owconf(\%config, \%config_raw, "$userconf");
711
print "D readconf $userconf\n" if ($opt{'debug'});
712
}
713
714
# override auto guessing domainanmes if loginame has domain
715
if (${$config_raw{'domainnames'}}[0] eq 'auto' && $loginname=~/\@/) {
716
$config{'domainnames'}=[ $logindomain ];
717
}
718
# override realname if defined in config
719
if ($config{'default_realname'} ne 'auto') {
720
$userrealname=$config{'default_realname'};
721
print "D change realname to $userrealname\n" if ($opt{'debug'});
722
}
723
724
my $owuserdir = ow::tool::untaint("$config{'ow_usersdir'}/".($config{'auth_withdomain'}?"$domain/$user":$user));
725
if ( !$config{'use_syshomedir'} ) {
726
$homedir = $owuserdir;
727
print "D change homedir to $homedir\n" if ($opt{'debug'});
728
}
729
if ($homedir eq '/') {
730
print "D homedir is /, skipped!\n" if ($opt{'debug'});
731
}
732
733
if (defined($homedir_processed{$homedir})) {
734
print "D $loginname homedir already processed, skipped!\n" if ($opt{'debug'});
735
next;
736
}
737
$homedir_processed{$homedir}=1;
738
739
$user=ow::tool::untaint($user);
740
$uuid=ow::tool::untaint($uuid);
741
$ugid=ow::tool::untaint($ugid);
742
$homedir=ow::tool::untaint($homedir);
743
744
# create domainhome for stuff not put in syshomedir
745
if (!$config{'use_syshomedir'} || !$config{'use_syshomedir_for_dotdir'} ) {
746
if ($config{'auth_withdomain'}) {
747
my $domainhome=ow::tool::untaint("$config{'ow_usersdir'}/$domain");
748
if (!-d $domainhome) {
749
mkdir($domainhome, 0750) or die("Couldn't create domain homedir $domainhome");
750
my $mailgid=getgrnam('mail');
751
chown($uuid, $mailgid, $domainhome);
752
}
753
}
754
}
755
upgrade_20030323();
756
# create owuserdir for stuff not put in syshomedir
757
if (!$config{'use_syshomedir'} || !$config{'use_syshomedir_for_dotdir'} ) {
758
if (!-d $owuserdir) {
759
my $fgid=(split(/\s+/,$ugid))[0];
760
if (mkdir ($owuserdir, oct(700)) && chown($uuid, $fgid, $owuserdir)) {
761
writelog("create owuserdir - $owuserdir, uid=$uuid, gid=$fgid");
762
print "D create owuserdir $owuserdir, uid=$uuid, gid=$fgid\n" if ($opt{'debug'});
763
} else {
764
print "D couldn't create $owuserdir ($!)\n" if ($opt{'debug'});
765
next;
766
}
767
}
768
}
769
770
umask(0077);
771
if ( $>==0 ) { # switch to uuid:mailgid if process is setuid to root
772
my $mailgid=getgrnam('mail'); # for better compatibility with other mail progs
773
ow::suid::set_euid_egids($uuid, $mailgid, split(/\s+/,$ugid));
774
if ( $)!~/\b$mailgid\b/) { # group mail doesn't exist?
775
print "Set effective gid to mail($mailgid) failed!"; openwebmail_exit(0);
776
}
777
}
778
print "D ruid=$<, euid=$>, rgid=$(, eguid=$)\n" if ($opt{'debug'});
779
780
# get user release date
781
my $user_releasedate=read_releasedatefile();
782
783
if ( ! -d $homedir ) {
784
print "D $homedir doesn't exist\n" if ($opt{'debug'});
785
next;
786
}
787
788
my $folderdir=ow::tool::untaint("$homedir/$config{'homedirfolderdirname'}");
789
if ( ! -d $folderdir ) {
790
if (-f "$homedir/.openwebmailrc") {
791
if (mkdir ($folderdir, 0700)) {
792
writelog("create folderdir - $folderdir, euid=$>, egid=$)");
793
print "D create folderdir $folderdir, euid=$>, egid=$<\n" if ($opt{'debug'});
794
upgrade_20021218($user_releasedate);
795
} else {
796
print "D couldn't create $folderdir ($!)\n" if ($opt{'debug'});
797
next;
798
}
799
} else {
800
print "D $folderdir doesn't exist\n" if ($opt{'debug'});
801
next;
802
}
803
}
804
805
if ($user_releasedate ne "") { # release file found
806
check_and_create_dotdir(dotpath('/')); # create dirs under ~/.openwebmail/
807
if ($user_releasedate ne $config{'releasedate'}) {
808
upgrade_all($user_releasedate);
809
print "D do release upgrade...\n" if ($opt{'debug'});
810
update_releasedatefile();
811
}
812
update_openwebmailrc($user_releasedate);
813
}
814
if ( ! -d dotpath('/') ) {
815
print "D ".dotpath('/')." doesn't exist\n" if ($opt{'debug'});
816
next;
817
}
818
819
# create dirs under ~/.openwebmail/
820
check_and_create_dotdir(dotpath('/'));
821
822
# remove stale folder db
823
my (@validfolders, $inboxusage, $folderusage);
824
getfolders(\@validfolders, \$inboxusage, \$folderusage);
825
del_staledb($user, \@validfolders);
826
827
%prefs = readprefs();
828
829
if ($opt{'pop3'}) {
830
my $ret=pop3_fetches($POP3_TIMEOUT);
831
print "pop3_fetches($POP3_TIMEOUT) return $ret\n" if (!$opt{'quiet'} && $ret!=0);
832
}
833
if ($opt{'zap'}) {
834
my $ret=clean_trash_spamvirus();
835
print "clean_trash_spamvirus() return $ret\n" if (!$opt{'quiet'} && $ret!=0);
836
}
837
838
if ($opt{'ir'}) {
839
my $ret=folderindex('rebuild', $opt{'ir'});
840
print "folderindex('rebuild', $opt{'ir'}) return $ret\n" if (!$opt{'quiet'} && $ret!=0);
841
} elsif ($opt{'if'}) {
842
my $ret=folderindex('fastrebuild', $opt{'if'});
843
print "folderindex('fastrebuild', $opt{'if'}) return $ret\n" if (!$opt{'quiet'} && $ret!=0);
844
} elsif ($opt{'iv'}) {
845
my $ret=folderindex('verify', $opt{'iv'});
846
print "folderindex('verify', $opt{'iv'}) return $ret\n" if (!$opt{'quiet'} && $ret!=0);
847
} elsif ($opt{'id'}) {
848
my $ret=folderindex('dump', $opt{'id'});
849
print "folderindex('dump', $opt{'id'}) return $ret\n" if (!$opt{'quiet'} && $ret!=0);
850
} elsif ($opt{'iz'}) {
851
my $ret=folderindex('zap', $opt{'iz'});
852
print "folderindex('zap', $opt{'iz'}) return $ret\n" if (!$opt{'quiet'} && $ret!=0);
853
}
854
855
if ($opt{'size'}) {
856
my $ret=checksize();
857
print "checksize() return $ret\n" if (!$opt{'quiet'} && $ret!=0);
858
}
859
if ($opt{'mail'}||$opt{'pop3'}) { # call checknewmail for pop3 because we want mail filtering
860
my $ret=checknewmail();
861
print "checknewmail() return $ret\n" if (!$opt{'quiet'} && $ret!=0);
862
}
863
if ($opt{'event'}) {
864
my $ret=checknewevent();
865
print "checknewevent() return $ret\n" if (!$opt{'quiet'} && $ret!=0);
866
}
867
if ($opt{'notify'}) {
868
my $ret=checknotify();
869
print "checknotify() return $ret\n" if (!$opt{'quiet'} && $ret!=0);
870
}
871
872
$usercount++;
873
}
874
875
if ($usercount>0) {
876
return 0;
877
} else {
878
return 1;
879
}
880
}
881
882
883
sub folderindex {
884
my ($op, $folder)=@_;
885
my (@validfolders, $inboxusage, $folderusage);
886
887
if ($folder eq 'ALL') {
888
getfolders(\@validfolders, \$inboxusage, \$folderusage);
889
} else {
890
push(@validfolders, $folder);
891
}
892
893
foreach (@validfolders) {
894
my ($folderfile, $folderdb)=get_folderpath_folderdb($user, $_);
895
my %FDB;
896
897
if (! -f $folderfile) {
898
print "$folderfile doesn't exist\n" if (!$opt{'quiet'});
899
next;
900
}
901
902
# in case any error in dump, return immediately and do not proceed next
903
if ($op eq "dump") {
904
my %folderinfo; foreach (keys %is_internal_dbkey) { $folderinfo{$_}=0 }
905
my (@messageids, @attr, $buff, $buff2, $headerlen);
906
my $error=0;
907
908
if (!ow::dbm::exist($folderdb)) {
909
print "db $folderdb doesn't exist\n" if (!$opt{'quiet'});
910
return -1;
911
}
912
@messageids=get_messageids_sorted_by_offset($folderdb);
913
914
if (!ow::filelock::lock($folderfile, LOCK_SH|LOCK_NB)) {
915
print "Couldn't get read lock on $folderfile\n" if (!$opt{'quiet'});
916
return -1;
917
}
918
if (!ow::dbm::open(\%FDB, $folderdb, LOCK_SH)) {
919
print "Couldn't get read lock on db $folderdb\n" if (!$opt{'quiet'});
920
ow::filelock::lock($folderfile, LOCK_UN);
921
return -1;
922
}
923
open (FOLDER, $folderfile);
924
925
for(my $i=0; $i<=$#messageids; $i++) {
926
@attr=get_message_attributes($messageids[$i], $folderdb);
927
next if ($#attr<0); # msg not found in db
928
929
$headerlen=$attr[$_HEADERSIZE]||6;
930
seek(FOLDER, $attr[$_OFFSET], 0);
931
read(FOLDER, $buff, $headerlen);
932
seek(FOLDER, $attr[$_OFFSET]+$attr[$_SIZE], 0);
933
read(FOLDER, $buff2, 6);
934
935
my @check=(0,0,0);
936
$check[0]=1 if ( $buff=~/^From / );
937
$check[1]=1 if ( $attr[$_HEADERCHKSUM] eq ow::tool::calc_checksum(\$buff) );
938
$check[2]=1 if ( $buff2=~/^From / || $buff2 eq "" );
939
940
$error++ if (!$check[0] || !$check[1] || !$check[2]);
941
942
printf ("%s%s%s %4d, OFFSET:%8d, SIZE:%8d, HSIZE:%4d, DATE:%s, CHARSET:%s, STAT:%3s, MSGID:%s, FROM:%s, TO:%s, SUB:%s\n",
943
$check[0]?'+':'-', $check[1]?'+':'-', $check[2]?'+':'-',
944
$i+1, $attr[$_OFFSET], $attr[$_SIZE], $attr[$_HEADERSIZE], $attr[$_DATE], $attr[$_CHARSET], $attr[$_STATUS],
945
substr($messageids[$i],0,50), $attr[$_FROM], $attr[$_TO], $attr[$_SUBJECT]) if (!$opt{'quiet'});
946
#printf ("buf=$buff, buff2=$buff2\n");
947
948
$folderinfo{'ALLMESSAGES'}++;
949
if ($attr[$_STATUS]=~/Z/i) {
950
$folderinfo{'ZAPMESSAGES'}++; $folderinfo{'ZAPSIZE'}+=$attr[$_SIZE];
951
} elsif (is_internal_subject($attr[$_SUBJECT])) {
952
$folderinfo{'INTERNALMESSAGES'}++; $folderinfo{'INTERNALSIZE'}+=$attr[$_SIZE];
953
} elsif ($attr[$_STATUS]!~/R/i) {
954
$folderinfo{'NEWMESSAGES'}++;
955
}
956
}
957
958
$folderinfo{'DBVERSION'}=$DBVERSION;
959
$folderinfo{'METAINFO'}=ow::tool::metainfo($folderfile);
960
if (!$opt{'quiet'}) {
961
print "\n";
962
foreach my $key (qw(DBVERSION METAINFO ALLMESSAGES NEWMESSAGES INTERNALMESSAGES INTERNALSIZE ZAPMESSAGES ZAPSIZE)) {
963
my $sign="+++";
964
if ($FDB{$key} ne $folderinfo{$key}) {
965
$sign="---"; $error++;
966
}
967
printf("$sign %-16s db:%-30s, folder:%-30s\n", $key, $FDB{$key}, $folderinfo{$key});
968
}
969
}
970
ow::dbm::close(\%FDB, $folderdb);
971
close(FOLDER);
972
ow::filelock::lock($folderfile, LOCK_UN);
973
974
print "$error errors in db $folderdb\n" if (!$opt{'quiet'});
975
976
} elsif ($op eq "zap") {
977
if (!ow::filelock::lock($folderfile, LOCK_EX)) {
978
print "Couldn't get write lock on $folderfile\n" if (!$opt{'quiet'});
979
next;
980
}
981
my $ret=folder_zapmessages($folderfile, $folderdb);
982
$ret=folder_zapmessages($folderfile, $folderdb) if ($ret==-9||$ret==-10);
983
if ($ret>=0) {
984
print "$ret messages have been zapped from $folder\n" if (!$opt{'quiet'});
985
} elsif ($ret<0) {
986
print "zap folder return error $ret\n" if (!$opt{'quiet'});
987
}
988
ow::filelock::lock($folderfile, LOCK_UN);
989
990
} else {
991
if (!ow::filelock::lock($folderfile, LOCK_EX)) {
992
print "Couldn't get write lock on $folderfile\n" if (!$opt{'quiet'});
993
next;
994
}
995
my $ret;
996
if ($op eq "verify") {
997
$ret=update_folderindex($folderfile, $folderdb);
998
} elsif ($op eq "rebuild") {
999
ow::dbm::unlink($folderdb);
1000
$ret=update_folderindex($folderfile, $folderdb);
1001
} elsif ($op eq "fastrebuild") {
1002
if (!ow::dbm::open(\%FDB, $folderdb, LOCK_EX, 0600)) {
1003
print "Couldn't get write lock on db $folderdb\n" if (!$opt{'quiet'});
1004
ow::filelock::lock($folderfile, LOCK_UN);
1005
next;
1006
}
1007
@FDB{'METAINFO', 'LSTMTIME'}=('ERR', -1);
1008
ow::dbm::close(\%FDB, $folderdb);
1009
$ret=update_folderindex($folderfile, $folderdb);
1010
}
1011
ow::filelock::lock($folderfile, LOCK_UN);
1012
1013
if (!$opt{'quiet'}) {
1014
if ($ret<0) {
1015
print "db $folderdb $op error $ret\n";
1016
} elsif ($op ne 'verify' || ($op eq 'verify' && $ret==0)) {
1017
print "db $folderdb $op ok\n";
1018
} else {
1019
print "db $folderdb $op & updated ok\n";
1020
}
1021
}
1022
}
1023
}
1024
return 0;
1025
}
1026
1027
1028
sub clean_trash_spamvirus {
1029
my %reserveddays=('mail-trash' => $prefs{'trashreserveddays'},
1030
'spam-mail' => $prefs{'spamvirusreserveddays'},
1031
'virus-mail' => $prefs{'spamvirusreserveddays'} );
1032
my (@f, $msg);
1033
push(@f, 'virus-mail') if ($config{'has_virusfolder_by_default'});
1034
push(@f, 'spam-mail') if ($config{'has_spamfolder_by_default'});
1035
push(@f, 'mail-trash');
1036
foreach my $folder (@f) {
1037
my ($folderfile, $folderdb)=get_folderpath_folderdb($user, $folder);
1038
if (ow::filelock::lock($folderfile, LOCK_EX)) {
1039
my $deleted=delete_message_by_age($reserveddays{$folder}, $folderdb, $folderfile);
1040
if ($deleted > 0) {
1041
$msg.=', ' if ($msg ne '');
1042
$msg.="$deleted msg deleted from $folder";
1043
}
1044
ow::filelock::lock($folderfile, LOCK_UN);
1045
}
1046
}
1047
if ($msg ne '') {
1048
writelog("clean trash/spam/virus - $msg");
1049
writehistory("clean trash/spam/virus - $msg");
1050
print "clean trash/spam/virus - $msg\n" if (!$opt{'quiet'});
1051
}
1052
return 0;
1053
}
1054
1055
1056
sub checksize {
1057
return 0 if (!$config{'quota_module'});
1058
ow::quota::load($config{'quota_module'});
1059
1060
my ($ret, $errmsg, $quotausage, $quotalimit)=ow::quota::get_usage_limit(\%config, $user, $homedir, 0);
1061
if ($ret<0) {
1062
print "$errmsg\n" if (!$opt{'quiet'});
1063
return $ret;
1064
}
1065
$quotalimit=$config{'quota_limit'} if ($quotalimit<0);
1066
return 0 if (!$quotalimit);
1067
1068
my $i=0;
1069
while ($quotausage>$quotalimit && $i<2) {
1070
$quotausage=(ow::quota::get_usage_limit(\%config, $user, $homedir, 1))[2]; # get uptodate usage
1071
return 0 if ($quotausage<=$quotalimit);
1072
1073
my (@validfolders, $inboxusage, $folderusage);
1074
getfolders(\@validfolders, \$inboxusage, \$folderusage);
1075
1076
my $sizetocut=($quotausage-$quotalimit*0.9)*1024;
1077
if ($config{'delmail_ifquotahit'} && !$config{'delfile_ifquotahit'}) {
1078
cutfoldermails($sizetocut, $user, @validfolders);
1079
} elsif (!$config{'delmail_ifquotahit'} && $config{'delfile_ifquotahit'}) {
1080
my $webdiskrootdir=$homedir.absolute_vpath("/", $config{'webdisk_rootpath'});
1081
cutdirfiles($sizetocut, $webdiskrootdir);
1082
} else { # both delmail/delfile are on or off, choose by percent
1083
if ($folderusage>$quotausage*0.5) {
1084
cutfoldermails($sizetocut, $user, @validfolders);
1085
} else {
1086
my $webdiskrootdir=$homedir.absolute_vpath("/", $config{'webdisk_rootpath'});
1087
cutdirfiles($sizetocut, $webdiskrootdir);
1088
}
1089
}
1090
$i++;
1091
}
1092
return 0;
1093
}
1094
1095
1096
sub checknewmail {
1097
my ($spoolfile, $folderdb)=get_folderpath_folderdb($user, 'INBOX');
1098
print "$loginname " if (!$opt{'quiet'});
1099
1100
if ($config{'authpop3_getmail'}) {
1101
my $authpop3book=dotpath('authpop3.book');
1102
my %accounts;
1103
if (-f "$authpop3book" && readpop3book("$authpop3book", \%accounts)>0) {
1104
my $login=$user; $login.="\@$domain" if ($config{'auth_withdomain'});
1105
my ($pop3ssl, $pop3passwd, $pop3del)
1106
=(split(/\@\@\@/, $accounts{"$config{'authpop3_server'}:$config{'authpop3_port'}\@\@\@$login"}))[2,4,5];
1107
1108
my ($ret, $errmsg) = fetchmail($config{'authpop3_server'}, $config{'authpop3_port'}, $pop3ssl,
1109
$login, $pop3passwd, $pop3del);
1110
if ($ret<0) {
1111
writelog("pop3 error - $errmsg at $login\@$config{'authpop3_server'}:$config{'authpop3_port'}");
1112
}
1113
}
1114
}
1115
1116
if ( ! -f $spoolfile || (stat($spoolfile))[7]==0 ) {
1117
print "has no mail\n" if (!$opt{'quiet'});
1118
return 0;
1119
}
1120
1121
update_folderindex($spoolfile, $folderdb);
1122
1123
# filtermessage in background
1124
filtermessage($user, 'INBOX', \%prefs);
1125
1126
if (!$opt{'quiet'}) {
1127
my %FDB;
1128
if (!ow::dbm::open(\%FDB, $folderdb, LOCK_SH)) {
1129
print "couldn't get read lock on db $folderdb\n";
1130
return -1;
1131
}
1132
my $newmessages=$FDB{'NEWMESSAGES'};
1133
my $oldmessages=$FDB{'ALLMESSAGES'}-$FDB{'ZAPMESSAGES'}-$FDB{'INTERNALMESSAGES'}-$newmessages;
1134
ow::dbm::close(\%FDB, $folderdb);
1135
1136
if ($newmessages == 1 ) {
1137
print "has 1 new mail\n";
1138
} elsif ($newmessages > 1 ) {
1139
print "has $newmessages new mails\n";
1140
} elsif ($oldmessages == 1 ) {
1141
print "has 1 mail\n";
1142
} elsif ($oldmessages > 1 ) {
1143
print "has $oldmessages mails\n";
1144
} else {
1145
print "has no mail\n";
1146
}
1147
}
1148
return 0;
1149
}
1150
1151
1152
sub checknewevent {
1153
my ($newevent, $oldevent);
1154
1155
my $localtime=ow::datetime::time_gm2local(time(), $prefs{'timeoffset'}, $prefs{'daylightsaving'});
1156
my ($wdaynum, $year, $month, $day, $hour, $min)=(ow::datetime::seconds2array($localtime))[6,5,4,3,2,1];
1157
$year+=1900; $month++;
1158
my $hourmin=sprintf("%02d%02d", $hour, $min);
1159
1160
my $dow=$ow::datetime::wday_en[$wdaynum];
1161
my $date=sprintf("%04d%02d%02d", $year, $month, $day);
1162
my $date2=sprintf("%04d,%02d,%02d,%s", $year,$month,$day,$dow);
1163
1164
my (%items, %indexes);
1165
if ( readcalbook(dotpath('calendar.book'), \%items, \%indexes, 0)<0 ) {
1166
return -1;
1167
}
1168
if ($prefs{'calendar_reminderforglobal'}) {
1169
readcalbook("$config{'global_calendarbook'}", \%items, \%indexes, 1E6);
1170
if ($prefs{'calendar_holidaydef'} eq 'auto') {
1171
readcalbook("$config{'ow_holidaysdir'}/$prefs{'language'}", \%items, \%indexes, 1E7);
1172
} elsif ($prefs{'calendar_holidaydef'} ne 'none') {
1173
readcalbook("$config{'ow_holidaysdir'}/$prefs{'calendar_holidaydef'}", \%items, \%indexes, 1E7);
1174
}
1175
}
1176
1177
my @indexlist=();
1178
push(@indexlist, @{$indexes{$date}}) if (defined($indexes{$date}));
1179
push(@indexlist, @{$indexes{'*'}}) if (defined($indexes{'*'}));
1180
@indexlist=sort { ($items{$a}{'starthourmin'}||1E9)<=>($items{$b}{'starthourmin'}||1E9) } @indexlist;
1181
1182
for my $index (@indexlist) {
1183
if ($date=~/$items{$index}{'idate'}/ ||
1184
$date2=~/$items{$index}{'idate'}/ ||
1185
ow::datetime::easter_match($year,$month,$day,$items{$index}{'idate'}) ) {
1186
if ($items{$index}{'starthourmin'}>=$hourmin ||
1187
$items{$index}{'endhourmin'}>$hourmin ||
1188
$items{$index}{'starthourmin'}==0) {
1189
$newevent++;
1190
} else {
1191
$oldevent++;
1192
}
1193
}
1194
}
1195
1196
if (!$opt{'quiet'}) {
1197
if ($newevent > 0 ) {
1198
print "$loginname has new event\n";
1199
} elsif ($oldevent > 0 ) {
1200
print "$loginname has event\n";
1201
}
1202
}
1203
return 0;
1204
}
1205
1206
1207
sub checknotify {
1208
my %message=();
1209
1210
my $localtime=ow::datetime::time_gm2local(time(), $prefs{'timeoffset'}, $prefs{'daylightsaving'});
1211
my ($wdaynum, $year, $month, $day, $hour, $min)=(ow::datetime::seconds2array($localtime))[6,5,4,3,2,1];
1212
$year+=1900; $month++;
1213
1214
my $dow=$ow::datetime::wday_en[$wdaynum];
1215
my $date=sprintf("%04d%02d%02d", $year, $month, $day);
1216
my $date2=sprintf("%04d,%02d,%02d,%s", $year,$month,$day,$dow);
1217
1218
my $notifycheckfile=dotpath('notify.check');
1219
1220
my $checkstart="0000";
1221
if ( -f $notifycheckfile ) {
1222
open (NOTIFYCHECK, $notifycheckfile ) or return -1; # read err
1223
my $lastcheck=<NOTIFYCHECK>;
1224
close (NOTIFYCHECK);
1225
$checkstart=$1 if ($lastcheck=~/$date(\d\d\d\d)/);
1226
}
1227
1228
my $checkend="2400";
1229
my ($wdaynum2, $year2, $month2, $day2, $hour2, $min2)=
1230
(ow::datetime::seconds2array($localtime+$config{'calendar_email_notifyinterval'}*60))[6,5,4,3,2,1];
1231
$checkend=sprintf("%02d%02d", $hour2, $min2) if ( $day2 eq $day );
1232
1233
return 0 if ($checkend<=$checkstart);
1234
1235
open (NOTIFYCHECK, ">$notifycheckfile" ) or return -2; # write err
1236
print NOTIFYCHECK "$date$checkend";
1237
close (NOTIFYCHECK);
1238
1239
my (%items, %indexes);
1240
1241
if ( readcalbook(dotpath('calendar.book'), \%items, \%indexes, 0)<0 ) {
1242
return -3;
1243
}
1244
if ($prefs{'calendar_reminderforglobal'}) {
1245
readcalbook("$config{'global_calendarbook'}", \%items, \%indexes, 1E6);
1246
if ($prefs{'calendar_holidaydef'} eq 'auto') {
1247
readcalbook("$config{'ow_holidaysdir'}/$prefs{'language'}", \%items, \%indexes, 1E7);
1248
} elsif ($prefs{'calendar_holidaydef'} ne 'none') {
1249
readcalbook("$config{'ow_holidaysdir'}/$prefs{'calendar_holidaydef'}", \%items, \%indexes, 1E7);
1250
}
1251
}
1252
1253
my @indexlist=();
1254
push(@indexlist, @{$indexes{$date}}) if (defined($indexes{$date}));
1255
push(@indexlist, @{$indexes{'*'}}) if (defined($indexes{'*'}));
1256
@indexlist=sort { ($items{$a}{'starthourmin'}||1E9)<=>($items{$b}{'starthourmin'}||1E9) } @indexlist;
1257
1258
my $future_items=0;
1259
for my $index (@indexlist) {
1260
if ( $items{$index}{'email'} &&
1261
($date=~/$items{$index}{'idate'}/ ||
1262
$date2=~/$items{$index}{'idate'}/ ||
1263
ow::datetime::easter_match($year,$month,$day,$items{$index}{'idate'})) ) {
1264
if ( ($items{$index}{'starthourmin'}>=$checkstart &&
1265
$items{$index}{'starthourmin'}<$checkend) ||
1266
($items{$index}{'starthourmin'}==0 &&
1267
$checkstart eq "0000") ) {
1268
my $itemstr;
1269
if ($items{$index}{'starthourmin'}==0) {
1270
$itemstr="##:##";
1271
} elsif ($items{$index}{'endhourmin'}==0) {
1272
$itemstr=hourmin($items{$index}{'starthourmin'});
1273
} else {
1274
$itemstr=hourmin($items{$index}{'starthourmin'})."-".hourmin($items{$index}{'endhourmin'});
1275
}
1276
$itemstr .= " $items{$index}{'string'}";
1277
$itemstr .= " ($items{$index}{'link'})" if ($items{$index}{'link'});
1278
1279
if (defined($message{$items{$index}{'email'}})) {
1280
$message{$items{$index}{'email'}} .= $itemstr."\n";
1281
} else {
1282
$message{$items{$index}{'email'}} = $itemstr."\n";
1283
}
1284
}
1285
if ($items{$index}{'starthourmin'}>=$checkend) {
1286
$future_items++;
1287
}
1288
}
1289
}
1290
1291
if ($future_items==0) { # today has no more item to notify, set checkend to 2400
1292
if (open (NOTIFYCHECK, ">$notifycheckfile" )) {
1293
print NOTIFYCHECK $date."2400";
1294
close (NOTIFYCHECK);
1295
}
1296
}
1297
1298
my $title=$prefs{'dateformat'}||"mm/dd/yyyy";
1299
my ($m, $d)=(sprintf("%02d",$month), sprintf("%02d",$day));
1300
$title=~s/yyyy/$year/; $title=~s/mm/$m/; $title=~s/dd/$d/;
1301
$title.=" Event(s) between ".hourmin($checkstart)."-".hourmin($checkend)."\n".
1302
"------------------------------------------------------------\n";
1303
my $from=$prefs{'email'};
1304
my %userfrom=get_userfrom($logindomain, $loginuser, $user, $userrealname, dotpath('from.book'));
1305
my $realname=$userfrom{$from};
1306
foreach my $email (keys %message) {
1307
my $date = ow::datetime::dateserial2datefield(ow::datetime::gmtime2dateserial(), $prefs{'timeoffset'}, $prefs{'daylightsaving'});
1308
my $ret=send_mail($from, $realname, $email, $date, "calendar notification", $title.$message{$email});
1309
if (!$opt{'quiet'}) {
1310
print "mailing notification to $email for $loginname";
1311
print ", return $ret" if ($ret!=0);
1312
print "\n";
1313
}
1314
}
1315
return 0;
1316
}
1317
1318
1319
sub hourmin {
1320
return("$1:$2") if ($_[0] =~ /(\d+)(\d{2})$/);
1321
return($_[0]);
1322
}
1323
1324
1325
sub send_mail {
1326
my ($from, $realname, $to, $date, $subject, $body)=@_;
1327
1328
$from =~ s/['"]/ /g; # Get rid of shell escape attempts
1329
$realname =~ s/['"]/ /g; # Get rid of shell escape attempts
1330
1331
($realname =~ /^(.+)$/) && ($realname = '"'.$1.'"');
1332
foreach ($from, $to, $date) { $_=ow::tool::untaint($_) }
1333
1334
# fake a messageid for this message
1335
my $fakedid = ow::datetime::gmtime2dateserial().'.M'.int(rand()*100000);
1336
$fakedid="<$fakedid".'@'."${$config{'domainnames'}}[0]>";
1337
1338
my $smtp;
1339
$smtp=Net::SMTP->new($config{'smtpserver'},
1340
Port => $config{'smtpport'},
1341
Timeout => 120,
1342
Hello => ${$config{'domainnames'}}[0]) or
1343
die "Couldn't SMTP server $config{'smtpserver'}:$config{'smtpport'}!";
1344
1345
# SMTP SASL authentication (PLAIN only)
1346
if ($config{'smtpauth'}) {
1347
my $auth = $smtp->supports("AUTH");
1348
$smtp->auth($config{'smtpauth_username'}, $config{'smtpauth_password'}) or
1349
die "SMTP server $config{'smtpserver'} error - ".$smtp->message;
1350
}
1351
1352
$smtp->mail($from);
1353
1354
my @recipients=();
1355
foreach (ow::tool::str2list($to,0)) {
1356
my $email=(ow::tool::email2nameaddr($_))[1];
1357
next if ($email eq "" || $email=~/\s/);
1358
push (@recipients, $email);
1359
}
1360
if (! $smtp->recipient(@recipients, { SkipBad => 1 }) ) {
1361
$smtp->reset();
1362
$smtp->quit();
1363
return -1;
1364
}
1365
1366
$smtp->data();
1367
$smtp->datasend("From: ".ow::mime::encode_mimewords("$realname <$from>", ('Charset'=>$prefs{'charset'}))."\n",
1368
"To: ".ow::mime::encode_mimewords($to, ('Charset'=>$prefs{'charset'}))."\n");
1369
$smtp->datasend("Reply-To: ".ow::mime::encode_mimewords($prefs{'replyto'}, ('Charset'=>$prefs{'charset'}))."\n") if ($prefs{'replyto'});
1370
1371
$smtp->datasend("Subject: ".ow::mime::encode_mimewords($subject, ('Charset'=>$prefs{'charset'}))."\n",
1372
"Date: $date\n",
1373
"Message-Id: $fakedid\n",
1374
safexheaders($config{'xheaders'}),
1375
"MIME-Version: 1.0\n",
1376
"Content-Type: text/plain; charset=$prefs{'charset'}\n\n",
1377
$body, "\n\n");
1378
$smtp->datasend($config{'mailfooter'}, "\n") if ($config{'mailfooter'}=~/[^\s]/);
1379
1380
if (!$smtp->dataend()) {
1381
$smtp->reset();
1382
$smtp->quit();
1383
return -2;
1384
}
1385
$smtp->quit();
1386
1387
return 0;
1388
}
1389
1390
sub pop3_fetches {
1391
my $timeout=$_[0];
1392
my ($spoolfile, $header)=get_folderpath_folderdb($user, 'INBOX');
1393
# create system spool file /var/mail/xxxx
1394
if ( ! -f "$spoolfile" ) {
1395
open (F, ">>$spoolfile"); close(F);
1396
}
1397
1398
my %accounts=();
1399
my $pop3bookfile=dotpath('pop3.book');
1400
1401
return 0 if (!-f $pop3bookfile);
1402
return -1 if (readpop3book($pop3bookfile, \%accounts) <0);
1403
1404
foreach (values %accounts) {
1405
my ($pop3host,$pop3port,$pop3ssl, $pop3user,$pop3passwd, $pop3del, $enable,)=split(/\@\@\@/,$_);
1406
next if (!$enable);
1407
1408
my $disallowed=0;
1409
foreach ( @{$config{'pop3_disallowed_servers'}} ) {
1410
if ($pop3host eq $_) {
1411
$disallowed=1; last;
1412
}
1413
}
1414
next if ($disallowed);
1415
1416
my ($ret, $errmsg) = fetchmail($pop3host, $pop3port, $pop3ssl,
1417
$pop3user, $pop3passwd, $pop3del);
1418
if ( $ret<0) {
1419
writelog("pop3 error - $errmsg at $pop3user\@$pop3host:$pop3port");
1420
}
1421
}
1422
1423
return 0;
1424
}
1425