Sharedwww / cgi-bin / openwebmail / openwebmail-abook.plOpen in CoCalc
Author: William A. Stein
1
#!/usr/bin/perl
2
#
3
# openwebmail-abook.pl - address book program
4
#
5
6
use vars qw($SCRIPT_DIR);
7
if ( $0 =~ m!^(\S*)/[\w\d\-\.]+\.pl! ) { $SCRIPT_DIR=$1 }
8
if ($SCRIPT_DIR eq '' && open(F, '/etc/openwebmail/openwebmail_path.conf')) {
9
$_=<F>; close(F); if ( $_=~/^(\S*)/) { $SCRIPT_DIR=$1 }
10
}
11
if ($SCRIPT_DIR eq '') { print "Content-type: text/html\n\nSCRIPT_DIR not set in /etc/openwebmail/openwebmail_path.conf !\n"; exit 0; }
12
push (@INC, $SCRIPT_DIR);
13
14
foreach (qw(ENV BASH_ENV CDPATH IFS TERM)) {delete $ENV{$_}}; $ENV{PATH}='/bin:/usr/bin'; # secure ENV
15
umask(0002); # make sure the openwebmail group can write
16
17
use strict;
18
use Fcntl qw(:DEFAULT :flock);
19
use CGI qw(-private_tempfiles :standard);
20
use CGI::Carp qw(fatalsToBrowser carpout);
21
22
require "modules/dbm.pl";
23
require "modules/suid.pl";
24
require "modules/filelock.pl";
25
require "modules/tool.pl";
26
require "modules/datetime.pl";
27
require "modules/lang.pl";
28
require "modules/mime.pl";
29
require "auth/auth.pl";
30
require "quota/quota.pl";
31
require "shares/ow-shared.pl";
32
33
# common globals
34
use vars qw(%config %config_raw);
35
use vars qw($thissession);
36
use vars qw($domain $user $userrealname $uuid $ugid $homedir);
37
use vars qw(%prefs %style %icontext);
38
39
# extern vars
40
use vars qw(%lang_folders %lang_sizes %lang_text %lang_err); # defined in lang/xy
41
42
# local globals
43
use vars qw($folder $messageid);
44
use vars qw($sort $page);
45
use vars qw($escapedmessageid $escapedfolder);
46
47
########## MAIN ##################################################
48
openwebmail_requestbegin();
49
$SIG{PIPE}=\&openwebmail_exit; # for user stop
50
$SIG{TERM}=\&openwebmail_exit; # for user stop
51
52
userenv_init();
53
54
if (!$config{'enable_webmail'}) {
55
openwebmailerror(__FILE__, __LINE__, "$lang_text{'webmail'} $lang_err{'access_denied'}");
56
}
57
58
$folder = param('folder') || 'INBOX';
59
$page = param('page') || 1;
60
$sort = param('sort') || $prefs{'sort'} || 'date';
61
$messageid=param('message_id') || '';
62
63
$escapedfolder=ow::tool::escapeURL($folder);
64
$escapedmessageid=ow::tool::escapeURL($messageid);
65
66
my $action = param('action')||'';
67
if ($action eq "addressbook") {
68
addressbook();
69
} elsif ($action eq "editaddresses") {
70
editaddresses();
71
} elsif ($action eq "addaddress") {
72
modaddress("add");
73
} elsif ($action eq "deleteaddress") {
74
modaddress("delete");
75
} elsif ($action eq "clearaddress") {
76
clearaddress();
77
} elsif ($action eq "importabook") {
78
importabook();
79
} elsif ($action eq "exportabook") {
80
exportabook();
81
} elsif ($action eq "importabook_pine") {
82
importabook_pine();
83
} elsif ($action eq "exportabook_pine") {
84
exportabook_pine();
85
} else {
86
openwebmailerror(__FILE__, __LINE__, "Action $lang_err{'has_illegal_chars'}");
87
}
88
89
openwebmail_requestend();
90
########## END MAIN ##############################################
91
92
########## ADDRESSBOOK ###########################################
93
sub addressbook {
94
my $elist = param('elist') || ''; # emails not checked or not convered by addressbook
95
$elist=ow::tool::unescapeURL($elist); # unescape elist becuase it is passed in escaped format (see line 276)
96
97
my $tolist = join(",", param('to')) || ''; # emails checked in addressbook window
98
my $form=param('form')||'';
99
my $field=param('field')||'';
100
101
my %emailhash=(); # store all entries in emailhash
102
foreach my $u (ow::tool::str2list($elist,0), ow::tool::str2list($tolist,0)) {
103
if ($u ne '') {
104
my $email=(ow::tool::email2nameaddr($u))[1];
105
$emailhash{$email}=$u;
106
}
107
}
108
109
my $abook_keyword = param('abook_keyword') || '';
110
my $abook_searchtype = param('abook_searchtype') || 'name';
111
my $results_flag = 0;
112
113
my ($html, $temphtml);
114
$html = applystyle(readtemplate("addressbook.template"));
115
116
if (defined($lang_text{$field})) {
117
$temphtml=$lang_text{$field}.": $lang_text{'abook'}";
118
} else {
119
$temphtml=uc($field).": $lang_text{'abook'}";
120
}
121
$html =~ s/\@\@\@ADDRESSBOOKFOR\@\@\@/$temphtml/g;
122
123
$temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail-abook.pl",
124
-name=>'addressbook');
125
$html =~ s/\@\@\@STARTADDRESSFORM\@\@\@/$temphtml/g;
126
127
my %searchtypelabels = ('name'=>$lang_text{'name'},
128
'email'=>$lang_text{'email'},
129
'note'=>$lang_text{'note'},
130
'all'=>$lang_text{'all'});
131
$temphtml = popup_menu(-name=>'abook_searchtype',
132
-default=>$abook_searchtype || 'name',
133
-values=>['name', 'email', 'note', 'all'],
134
-labels=>\%searchtypelabels);
135
$temphtml .= textfield(-name=>'abook_keyword',
136
-default=>$abook_keyword,
137
-size=>'16',
138
-override=>'1');
139
$temphtml .= "&nbsp;";
140
$temphtml .= submit(-name=>$lang_text{'search'},
141
-class=>'medtext');
142
$html =~ s/\@\@\@SEARCH\@\@\@/$temphtml/g;
143
144
$temphtml="";
145
$temphtml .= qq|<tr><td colspan="4">&nbsp;</td></tr>|;
146
147
my $addrbookfile=dotpath('address.book');
148
149
my $count=0;
150
my $bgcolor = $style{"tablerow_dark"};
151
if ( -f $addrbookfile ) {
152
my %addresses=();
153
my %notes=();
154
155
my ($stat,$err,@namelist)=read_abook($addrbookfile,\%addresses,\%notes);
156
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
157
158
foreach (@namelist) {
159
delete $addresses{$_} if (!is_entry_matched($abook_keyword,$abook_searchtype,
160
$_, $notes{$_}, $addresses{$_}));
161
}
162
foreach my $name (sort { lc($a) cmp lc($b) } keys %addresses) {
163
my $email=$addresses{$name};
164
my $emailstr;
165
166
if ( $form eq "newaddress" && $field eq "email" ) { # if addr popup window is used to define group email
167
$emailstr="$email"; # then only pure addr is required
168
} else {
169
if ( $email =~ /[,"]/ ) { # expand multiple addr to multiple "name" <addr>
170
foreach my $e (ow::tool::str2list($email,0)) {
171
foreach my $n (keys %addresses) {
172
if ( $e eq $addresses{$n} ) {
173
$e="\&quot;$n\&quot; &lt;$e&gt;";
174
last;
175
}
176
}
177
$emailstr .= "," if ($emailstr ne "");
178
$emailstr .= $e;
179
}
180
} else {
181
$emailstr="\&quot;$name\&quot; &lt;$email&gt;";
182
}
183
}
184
185
my $accesskeystr=$count%10+1;
186
if ($accesskeystr == 10) {
187
$accesskeystr=qq|accesskey="0"|;
188
} elsif ($accesskeystr < 10) {
189
$accesskeystr=qq|accesskey="$accesskeystr"|;
190
}
191
$temphtml .= qq|<tr>| if ($count %2 == 0);
192
$temphtml .= qq|<td width="20" bgcolor=$bgcolor><input type="checkbox" name="to" value="$emailstr"|;
193
194
if (defined($emailhash{$email})) {
195
$temphtml .= " checked";
196
delete $emailhash{$email};
197
}
198
199
$emailstr=~s/\\/\\\\/g; $emailstr=~s/'/\\'/g; # escape \ and ' for javascript
200
$temphtml .= qq|></td><td width="45%" bgcolor=$bgcolor nowrap>|.
201
qq|<a $accesskeystr href="javascript:Update('$emailstr')" title="$email $notes{$name}">$name</a></td>\n|;
202
$temphtml .= qq|</tr>| if ($count %2 == 1);
203
204
if ($bgcolor eq $style{"tablerow_dark"}) {
205
$bgcolor = $style{"tablerow_light"} if ($count %2 == 0);
206
} else {
207
$bgcolor = $style{"tablerow_dark"} if ($count %2 == 0);
208
}
209
$results_flag = 1;
210
$count++
211
}
212
213
}
214
$temphtml .= qq|<tr><td colspan="4">&nbsp;</td></tr>| if ($count>0);
215
216
$count = 0;
217
if ( $config{'global_addressbook'} ne "" && -f "$config{'global_addressbook'}" ) {
218
my %globaladdresses=();
219
my %globalnotes=();
220
221
my ($stat,$err,@namelist)=read_abook($config{'global_addressbook'},\%globaladdresses,\%globalnotes);
222
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
223
224
foreach my $name (@namelist) {
225
next if (!is_entry_matched($abook_keyword,$abook_searchtype,
226
$name, $globalnotes{$name}, $globaladdresses{$name}));
227
my $email=$globaladdresses{$name};
228
my $emailstr;
229
230
if ( $form eq "newaddress" && $field eq "email" ) { # if addr popup window is used to define group email
231
$emailstr="$email"; # then only pure addr is required
232
} else {
233
if ( $email =~ /[,"]/ ) { # expamd multiple addr to "name" <addr>
234
foreach my $e (ow::tool::str2list($email,0)) {
235
foreach my $n (keys %globaladdresses) {
236
if ( $e eq $globaladdresses{$n} ) {
237
$e="\&quot;$n\&quot; &lt;$e&gt;";
238
last;
239
}
240
}
241
$emailstr .= "," if ($emailstr ne "");
242
$emailstr .= $e;
243
}
244
} else {
245
$emailstr="\&quot;$name\&quot; &lt;$email&gt;";
246
}
247
}
248
249
$temphtml .= qq|<tr>| if ($count %2 == 0);
250
$temphtml .= qq|<td width="20" bgcolor=$bgcolor><input type="checkbox" name="to" value="$emailstr"|;
251
252
if (defined($emailhash{$email})) {
253
$temphtml .= " checked";
254
delete $emailhash{$email};
255
}
256
257
$emailstr=~s/\\/\\\\/g; $emailstr=~s/'/\\'/g; # escape \ and ' for javascript
258
$temphtml .= qq|></td><td width="45%" bgcolor=$bgcolor nowrap>|.
259
qq|<a href="javascript:Update('$emailstr')" title="$email $globalnotes{$name}">$name</a></td>\n|;
260
$temphtml .= qq|</tr>| if ($count %2 == 1);
261
262
if ($bgcolor eq $style{"tablerow_dark"}) {
263
$bgcolor = $style{"tablerow_light"} if ($count %2 == 0);
264
} else {
265
$bgcolor = $style{"tablerow_dark"} if ($count %2 == 0);
266
}
267
$results_flag = 1;
268
$count++
269
}
270
$temphtml .= qq|<tr><td colspan="4">&nbsp;</td></tr>| if ($count>0);
271
}
272
273
$html =~ s/\@\@\@ADDRESSES\@\@\@/$temphtml/g;
274
275
# rebuild entries not checked on address popup window backto elist
276
my @u=sort values(%emailhash);
277
278
$elist=join(",", @u);
279
$elist=ow::tool::escapeURL($elist); # escape elist to make it a safe string in HTML
280
281
$temphtml = ow::tool::hiddens(elist=>$elist,
282
action=>'addressbook',
283
sessionid=>$thissession,
284
form=>$form,
285
field=>$field);
286
$html =~ s/\@\@\@HIDDENFIELDS\@\@\@/$temphtml/g;
287
288
$temphtml = button(-name=>'update',
289
-value=>$lang_text{'continue'},
290
-accesskey=>'C', # continue
291
-class=>'medtext',
292
-onclick=>'Update(); return false;').
293
"&nbsp;&nbsp;".
294
button(-name=>'cancel',
295
-value=>$lang_text{'cancel'},
296
-onclick=>'window.close();',
297
-class=>'medtext',
298
-accesskey=>'Q', # quit
299
-override=>'1');
300
301
my $temphtml_before = '&nbsp;</td></tr><tr><td align="center" colspan=4>'.$temphtml;
302
if ($prefs{'abook_buttonposition'} eq 'after') {
303
$html =~ s/\@\@\@BUTTONSBEFORE\@\@\@//g;
304
$html =~ s/\@\@\@BUTTONSAFTER\@\@\@/$temphtml/g;
305
} elsif (($prefs{'abook_buttonposition'} eq 'both') && $results_flag) {
306
$html =~ s/\@\@\@BUTTONSBEFORE\@\@\@/$temphtml_before/g;
307
$html =~ s/\@\@\@BUTTONSAFTER\@\@\@/$temphtml/g;
308
} else {
309
$html =~ s/\@\@\@BUTTONSBEFORE\@\@\@/$temphtml_before/g;
310
$html =~ s/\@\@\@BUTTONSAFTER\@\@\@//g;
311
}
312
313
$temphtml = end_form();
314
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/g;
315
316
$html =~ s/\@\@\@FORMNAME\@\@\@/$form/g;
317
$html =~ s/\@\@\@FIELDNAME\@\@\@/$field/g;
318
319
httpprint([], [htmlheader(), $html, htmlfooter(0)]);
320
}
321
########## END ADDRESSBOOK #######################################
322
323
########## IMPORT/EXPORTABOOK ####################################
324
sub importabook {
325
my ($name, $email, $note);
326
my (%addresses, %notes);
327
my $abookupload = param('abook') || '';
328
my $abooktowrite='';
329
my $mua = param('mua') || '';
330
331
my $addrbookfile=dotpath('address.book');
332
333
if ($abookupload) {
334
my $abookcontents = '';
335
while (<$abookupload>) {
336
$abookcontents .= $_;
337
}
338
close($abookupload);
339
# if ($mua eq 'outlookexp5') {
340
# unless ($abookcontents =~ /^Name,E-mail Address/) {
341
# openwebmailerror(__FILE__, __LINE__, qq|$lang_err{'abook_invalid'} <a href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=importabook&amp;sessionid=$thissession&amp;sort=$sort&amp;folder=$escapedfolder&amp;page=$page&amp;message_id=$escapedmessageid">$lang_err{'back'}</a> $lang_err{'tryagain'}|);
342
# }
343
# }
344
345
if (! -f $addrbookfile) {
346
open (ABOOK, ">>$addrbookfile"); # Create if nonexistent
347
close(ABOOK);
348
}
349
ow::filelock::lock($addrbookfile, LOCK_EX) or
350
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $addrbookfile!");
351
352
my ($stat,$err,@namelist)=read_abook($addrbookfile,\%addresses,\%notes);
353
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
354
355
foreach my $line (split(/\r*\n/, $abookcontents)) {
356
# next if ( ($mua eq 'outlookexp5') && (/^Name,E-mail Address/) );
357
next if ( $line !~ /\@/ );
358
my @t = ow::tool::str2list($line,1);
359
if ( $mua eq 'outlookexp5' && $t[0] && $t[1] ) {
360
$name=shift(@t);
361
$name =~ s/</&lt;/g; $name =~ s/>/&gt;/g;
362
$email=shift(@t);
363
while ($t[0]=~/^[\w\d\.-_]+\@[\w\d-_]+(\.[\w\d-_]+)+$/) {
364
$email.=",".shift(@t); # for owm group addr import
365
}
366
$email =~ s/</&lt;/g; $email =~ s/>/&gt;/g;
367
$note = join(",", @t);
368
$note =~ s/,\s*,//g; $note =~ s/^\s*,\s*//g; $note =~ s/\s*,\s*$//g;
369
370
$addresses{$name} = $email;
371
$notes{$name} = $note;
372
373
} elsif ( $mua eq 'nsmail' && $t[0] && $t[6] ) {
374
$name=$t[0];
375
$name =~ s/</&lt;/g; $name =~ s/>/&gt;/g;
376
$email=$t[6];
377
$email =~ s/</&lt;/g; $email =~ s/>/&gt;/g;
378
$note = join(",", @t[1..5,7..9]);
379
$note =~ s/,\s*,//g; $note =~ s/^\s*,\s*//g; $note =~ s/\s*,\s*$//g;
380
381
$addresses{$name} = $email;
382
$notes{$name} = $note;
383
}
384
}
385
386
($stat,$err)=write_abook($addrbookfile,$config{'maxbooksize'},\%addresses,\%notes);
387
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
388
389
ow::filelock::lock($addrbookfile, LOCK_UN);
390
391
writelog("import addressbook");
392
writehistory("import addressbook");
393
394
editaddresses();
395
396
} else {
397
398
my $abooksize = ( -s $addrbookfile ) || 0;
399
my $freespace = int($config{'maxbooksize'} - ($abooksize/1024) + .5);
400
401
my ($html, $temphtml);
402
$html = applystyle(readtemplate("importabook.template"));
403
404
$html =~ s/\@\@\@FREESPACE\@\@\@/$freespace $lang_sizes{'kb'}/g;
405
406
$temphtml = start_multipart_form().
407
ow::tool::hiddens(action=>'importabook',
408
sessionid=>$thissession,
409
sort=>$sort,
410
page=>$page,
411
folder=>$folder,
412
message_id=>$messageid);
413
$html =~ s/\@\@\@STARTIMPORTFORM\@\@\@/$temphtml/;
414
415
416
my %mualabels =(outlookexp5 => 'Outlook Express 5',
417
nsmail => 'Netscape Mail 4.x');
418
$temphtml = radio_group(-name=>'mua',
419
-values=>['outlookexp5','nsmail'],
420
-default=>'outlookexp5',
421
-labels=>\%mualabels);
422
$html =~ s/\@\@\@MUARADIOGROUP\@\@\@/$temphtml/;
423
424
$temphtml = filefield(-name=>'abook',
425
-default=>'',
426
-size=>'30',
427
-override=>'1');
428
$html =~ s/\@\@\@IMPORTFILEFIELD\@\@\@/$temphtml/;
429
430
$temphtml = submit("$lang_text{'import'}");
431
$html =~ s/\@\@\@IMPORTBUTTON\@\@\@/$temphtml/;
432
433
$temphtml = end_form();
434
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/g;
435
436
$temphtml = start_form(-action=>"$config{'ow_cgiurl'}/openwebmail-abook.pl").
437
ow::tool::hiddens(action=>'editaddresses',
438
sessionid=>$thissession,
439
sort=>$sort,
440
folder=>$folder,
441
page=>$page,
442
message_id=>$messageid);
443
$html =~ s/\@\@\@STARTCANCELFORM\@\@\@/$temphtml/;
444
445
$temphtml = submit("$lang_text{'cancel'}");
446
$html =~ s/\@\@\@CANCELBUTTON\@\@\@/$temphtml/;
447
448
httpprint([], [htmlheader(), $html, htmlfooter(2)]);
449
}
450
}
451
452
sub exportabook {
453
my $addrbookfile=dotpath('address.book');
454
455
ow::filelock::lock($addrbookfile, LOCK_EX) or
456
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $addrbookfile!");
457
458
my %addresses=();
459
my %notes=();
460
my ($stat,$err,@namelist)=read_abook($addrbookfile, \%addresses, \%notes);
461
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
462
463
ow::filelock::lock($addrbookfile, LOCK_UN);
464
465
# disposition:attachment default to save
466
print qq|Connection: close\n|,
467
qq|Content-Type: text/plain; name="adbook.csv"\n|;
468
if ( $ENV{'HTTP_USER_AGENT'}=~/MSIE 5.5/ ) { # ie5.5 is broken with content-disposition: attachment
469
print qq|Content-Disposition: filename="adbook.csv"\n|;
470
} else {
471
print qq|Content-Disposition: attachment; filename="adbook.csv"\n|;
472
}
473
print qq|\n|;
474
print qq|Name,E-mail Address,Note\n|;
475
foreach (@namelist) {
476
my @line = ($_, $addresses{$_}, $notes{$_});
477
map { $_ = qq|"$_"| if /,/; } @line; # quote str if contains comma
478
print join(",", @line)."\n";
479
}
480
481
writelog("export addressbook");
482
writehistory("export addressbook");
483
484
return;
485
}
486
487
########## END IMPORT/EXPORTABOOK ################################
488
489
########## IMPORT/EXPORTABOOK PINE ###############################
490
sub importabook_pine {
491
my $addrbookfile=dotpath('address.book');
492
493
if ( ! -f $addrbookfile ) {
494
open (ABOOK, ">>$addrbookfile"); # Create if nonexistent
495
close(ABOOK);
496
}
497
498
if (open (PINEBOOK,"$homedir/.addressbook") ) {
499
my @lines=();
500
my ($name, $email, $note);
501
my (%addresses, %notes);
502
my $abooktowrite='';
503
504
ow::filelock::lock($addrbookfile, LOCK_EX) or
505
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $addrbookfile!");
506
507
my ($stat,$err,@namelist)=read_abook($addrbookfile, \%addresses, \%notes);
508
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
509
510
while (<PINEBOOK>) {
511
chomp;
512
if (/^ / && $#lines>=0) {
513
s/^ //;
514
$lines[$#lines].=$_;
515
} else {
516
push(@lines, $_);
517
}
518
}
519
close (PINEBOOK);
520
foreach (@lines) {
521
my ($name, $email, $note) = (split(/\t/, $_,5))[1,2,4];
522
next if ($email=~/^\s*$/); # skip if email is null
523
$name=decode_mimewords($name);
524
$addresses{"$name"} = decode_mimewords($email);
525
$notes{"$name"}=decode_mimewords($note);
526
}
527
528
# replace the address book
529
($stat,$err)=write_abook($addrbookfile,$config{'maxbooksize'},\%addresses,\%notes);
530
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
531
532
ow::filelock::lock($addrbookfile, LOCK_UN);
533
534
writelog("import pine addressbook - $homedir/.addressbook");
535
writehistory("import pine addressbook - $homedir/.addressbook");
536
}
537
editaddresses();
538
}
539
540
sub exportabook_pine {
541
my $addrbookfile=dotpath('address.book');
542
543
if (-f $addrbookfile) {
544
ow::filelock::lock($addrbookfile, LOCK_SH|LOCK_NB) or
545
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $addrbookfile!");
546
547
my (%nicknames, %emails, %fccs, %notes);
548
my ($nickname, $name, $email, $fcc, $note);
549
my $abooktowrite='';
550
551
my ($stat,$err,@namelist)=read_abook($addrbookfile, \%emails, \%notes);
552
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
553
554
ow::filelock::lock($addrbookfile, LOCK_UN);
555
556
ow::filelock::lock("$homedir/.addressbook", LOCK_EX) or
557
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $homedir/.addressbook!");
558
559
if (open (PINEBOOK, "$homedir/.addressbook")) {
560
while (<PINEBOOK>) {
561
my ($nickname, $name, $email, $fcc, $note) = (split(/\t/, $_,5))[1,2,4];
562
foreach ($nickname, $name, $email, $fcc, $note) { chomp; }
563
next if ($email=~/^\s*$/); # skip if email is null
564
$nicknames{$name}=$nickname;
565
$emails{$name} = $email;
566
$fccs{$name}=$fcc;
567
$notes{$name}=$note;
568
}
569
close(PINEBOOK);
570
}
571
572
open (PINEBOOK,">$homedir/.addressbook") or
573
openwebmailerror(__FILE__, __LINE__, "couldnt_open $homedir/.address.book! ($!)");
574
575
foreach (sort keys %emails) {
576
$abooktowrite .= join("\t", $nicknames{$_}, $_,
577
$emails{$_}, $fccs{$_}, $notes{$_})."\n";
578
}
579
print PINEBOOK $abooktowrite;
580
close (PINEBOOK);
581
ow::filelock::lock("$homedir/.addressbook", LOCK_UN);
582
583
writelog("emport addressbook to pine, $homedir/.addressbook");
584
writehistory("emport addressbook to pine, $homedir/.addressbook");
585
}
586
editaddresses();
587
}
588
########## END IMPORT/EXPORTABOOK PINE ###########################
589
590
########## EDITADDRESSES #########################################
591
sub editaddresses {
592
my %addresses=();
593
my %notes=();
594
my %globaladdresses=();
595
my %globalnotes=();
596
my @globalnamelist=();
597
my ($name, $email, $note);
598
my $abook_keyword = param('abook_keyword') || '';
599
my $abook_searchtype = param('abook_searchtype') || 'name';
600
my ($stat,$err)=(0);
601
602
my ($html, $temphtml);
603
$html = applystyle(readtemplate("editaddresses.template"));
604
605
my $addrbookfile=dotpath('address.book');
606
607
if ( -f $addrbookfile ) {
608
($stat,$err,@globalnamelist)=read_abook($addrbookfile, \%addresses, \%notes);
609
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
610
}
611
my $abooksize = ( -s $addrbookfile ) || 0;
612
my $freespace = int($config{'maxbooksize'} - ($abooksize/1024) + .5);
613
614
if ( $config{'global_addressbook'} ne "" && -f "$config{'global_addressbook'}" ) {
615
($stat,$err,@globalnamelist)=read_abook($config{'global_addressbook'}, \%globaladdresses, \%globalnotes);
616
openwebmailerror(__FILE__, __LINE__, $err) if ($stat<0);
617
}
618
619
$html =~ s/\@\@\@FREESPACE\@\@\@/$freespace $lang_sizes{'kb'}/g;
620
621
if ( param('message_id') ) {
622
$temphtml = iconlink("backtofolder.gif", "$lang_text{'backto'} ".($lang_folders{$folder}||$folder),
623
qq|accesskey="B" href="$config{'ow_cgiurl'}/openwebmail-read.pl?action=readmessage&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid"|);
624
} else {
625
$temphtml = iconlink("backtofolder.gif", "$lang_text{'backto'} ".($lang_folders{$folder}||$folder),
626
qq|accesskey="B" href="$config{'ow_cgiurl'}/openwebmail-main.pl?action=listmessages&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder"|);
627
}
628
629
$temphtml .= "&nbsp;\n";
630
631
$temphtml .= iconlink("import.gif", $lang_text{'importadd'}, qq|accesskey="I" href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=importabook&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid"|);
632
if ( -f "$homedir/.addressbook" ) {
633
$temphtml .= iconlink("import.gif", "$lang_text{'importadd'} (Pine)", qq|href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=importabook_pine&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid"|);
634
}
635
$temphtml .= iconlink("export.gif", $lang_text{'exportadd'}, qq|accesskey="E" href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=exportabook&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid"|).
636
iconlink("export.gif", "$lang_text{'exportadd'} (Pine)", qq|href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=exportabook_pine&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid"|).
637
iconlink("clearaddress.gif", $lang_text{'clearadd'}, qq|accesskey="Z" href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=clearaddress&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid" onclick="return confirm('$lang_text{'clearadd'}?')"|). qq| &nbsp; \n|;
638
if ($abook_keyword ne ''){
639
$temphtml .= iconlink("refresh.gif", $lang_text{'refresh'}, qq|accesskey="R" href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=editaddresses&amp;sessionid=$thissession&amp;sort=$sort&amp;page=$page&amp;folder=$escapedfolder&amp;message_id=$escapedmessageid&amp;abook_keyword="|);
640
}
641
642
$html =~ s/\@\@\@MENUBARLINKS\@\@\@/$temphtml/g;
643
644
$temphtml = start_form(-action=>"$config{'ow_cgiurl'}/openwebmail-abook.pl").
645
ow::tool::hiddens(action=>'editaddresses',
646
sessionid=>$thissession,
647
sort=>$sort,
648
page=>$page,
649
folder=>$folder,
650
message_id=>$messageid);
651
$html =~ s/\@\@\@STARTSEARCHFORM\@\@\@/$temphtml/g;
652
653
my %searchtypelabels = ('name'=>$lang_text{'name'},
654
'email'=>$lang_text{'email'},
655
'note'=>$lang_text{'note'},
656
'all'=>$lang_text{'all'});
657
$temphtml = popup_menu(-name=>'abook_searchtype',
658
-default=>$abook_searchtype || 'name',
659
-values=>['name', 'email', 'note', 'all'],
660
-labels=>\%searchtypelabels);
661
$temphtml .= textfield(-name=>'abook_keyword',
662
-default=>$abook_keyword,
663
-size=>'25',
664
-accesskey=>'S',
665
-override=>'1');
666
$temphtml .= "&nbsp;";
667
$temphtml .= submit(-name=>$lang_text{'search'},
668
-class=>'medtext');
669
$html =~ s/\@\@\@SEARCH\@\@\@/$temphtml/g;
670
671
$temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail-abook.pl",
672
-name=>'newaddress').
673
ow::tool::hiddens(action=>'addaddress',
674
sessionid=>$thissession,
675
sort=>$sort,
676
page=>$page,
677
folder=>$folder,
678
message_id=>$messageid);
679
$html =~ s/\@\@\@STARTADDRESSFORM\@\@\@/$temphtml/;
680
681
$temphtml = textfield(-name=>'realname',
682
-default=>'',
683
-size=>'20',
684
-accesskey=>'I',
685
-override=>'1');
686
$html =~ s/\@\@\@REALNAMEFIELD\@\@\@/$temphtml/;
687
688
$temphtml = qq|<table cellspacing="0" cellpadding="0"><tr><td>|.
689
textfield(-name=>'email',
690
-default=>'',
691
-size=>'30',
692
-override=>'1').
693
qq|</td><td>|.
694
iconlink("group.gif", $lang_text{'group'}, qq|accesskey="G" href="Javascript:GoAddressWindow('email')"|).
695
qq|</td></tr></table>|;
696
$html =~ s/\@\@\@EMAILFIELD\@\@\@/$temphtml/;
697
698
$temphtml = textfield(-name=>'note',
699
-default=>'',
700
-size=>'25',
701
-override=>'1');
702
$html =~ s/\@\@\@NOTEFIELD\@\@\@/$temphtml/;
703
704
$temphtml = submit(-name=>$lang_text{'addmod'},
705
-accesskey=>'A',
706
-onClick=>'return addcheck();',
707
-class=>"medtext");
708
$html =~ s/\@\@\@ADDBUTTON\@\@\@/$temphtml/;
709
710
$temphtml = end_form();
711
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/g;
712
713
$temphtml = '';
714
my $bgcolor = $style{"tablerow_dark"};
715
my $i=0;
716
foreach my $key (sort { lc($a) cmp lc($b) } keys %addresses) {
717
my ($namestr, $emailstr, $notestr)=($key, $addresses{$key}, $notes{$key});
718
next if (!is_entry_matched($abook_keyword,$abook_searchtype, $namestr,$notestr,$emailstr));
719
$namestr=substr($namestr, 0, 25)."..." if (length($namestr)>30);
720
$emailstr=substr($emailstr, 0, 35)."..." if (length($emailstr)>40);
721
722
my $accesskeystr=$i%10+1;
723
if ($accesskeystr == 10) {
724
$accesskeystr=qq|accesskey="0"|;
725
} elsif ($accesskeystr < 10) {
726
$accesskeystr=qq|accesskey="$accesskeystr"|;
727
}
728
729
my ($k, $a, $n)=($key, $addresses{$key}, $notes{$key});
730
$k=~s/\\/\\\\/; $k=~s/'/\\'/;
731
$a=~s/\\/\\\\/; $a=~s/'/\\'/;
732
$n=~s/\\/\\\\/; $n=~s/'/\\'/; # escape \ and ' for javascript
733
$temphtml .= qq|<tr>|.
734
qq|<td bgcolor=$bgcolor><a $accesskeystr href="Javascript:Update('$k','$a','$n')">$namestr</a></td>|.
735
qq|<td bgcolor=$bgcolor><a href="$config{'ow_cgiurl'}/openwebmail-send.pl?action=composemessage&amp;page=$page&amp;sort=$sort&amp;folder=$escapedfolder&amp;sessionid=$thissession&amp;composetype=sendto&amp;to=|.
736
ow::tool::escapeURL($addresses{$key}).qq|&amp;compose_caller=abook">$emailstr</a></td>|.
737
qq|<td bgcolor=$bgcolor>$notestr</td>|;
738
739
$temphtml .= qq|<td bgcolor=$bgcolor align="center">|;
740
741
$temphtml .= start_form(-action=>"$config{'ow_cgiurl'}/openwebmail-abook.pl").
742
ow::tool::hiddens(action=>'deleteaddress',
743
sessionid=>$thissession,
744
sort=>$sort,
745
page=>$page,
746
folder=>$folder,
747
message_id=>$messageid,
748
realname=>$key).
749
submit(-name=>$lang_text{'delete'},
750
-class=>"medtext").
751
qq|</td></tr>|.
752
end_form();
753
754
if ($bgcolor eq $style{"tablerow_dark"}) {
755
$bgcolor = $style{"tablerow_light"};
756
} else {
757
$bgcolor = $style{"tablerow_dark"};
758
}
759
$i++;
760
}
761
762
if ($#globalnamelist >= 0) {
763
$temphtml .= qq|<tr><td colspan="4">&nbsp;</td></tr>\n|.
764
qq|<tr><td colspan="4" bgcolor=$style{columnheader}><B>$lang_text{globaladdressbook}</B> ($lang_text{readonly})</td></tr>\n|;
765
}
766
$bgcolor = $style{"tablerow_dark"};
767
$i=0;
768
foreach my $key (@globalnamelist) {
769
my ($namestr, $emailstr, $notestr)=($key, $globaladdresses{$key}, $globalnotes{$key});
770
next if (!is_entry_matched($abook_keyword,$abook_searchtype, $namestr,$notestr,$emailstr));
771
$namestr=substr($namestr, 0, 25)."..." if (length($namestr)>30);
772
$emailstr=substr($emailstr, 0, 35)."..." if (length($emailstr)>40);
773
774
my ($k, $a, $n)=($key, $globaladdresses{$key}, $globalnotes{$key});
775
$k=~s/\\/\\\\/; $k=~s/'/\\'/;
776
$a=~s/\\/\\\\/; $a=~s/'/\\'/;
777
$n=~s/\\/\\\\/; $n=~s/'/\\'/; # escape \ and ' for javascript
778
$temphtml .= qq|<tr>|.
779
qq|<td bgcolor=$bgcolor><a href="Javascript:Update('$k','$a','$n')">$namestr</a></td>|.
780
qq|<td bgcolor=$bgcolor><a href="$config{'ow_cgiurl'}/openwebmail-send.pl?action=composemessage&amp;page=$page&amp;sort=$sort&amp;folder=$escapedfolder&amp;sessionid=$thissession&amp;composetype=sendto&amp;to=|.
781
ow::tool::escapeURL($globaladdresses{$key}).qq|&amp;compose_caller=abook">$emailstr</a></td>|.
782
qq|<td bgcolor=$bgcolor>$notestr</td>|.
783
qq|<td bgcolor=$bgcolor align="center">-----</td></tr>|;
784
785
if ($bgcolor eq $style{"tablerow_dark"}) {
786
$bgcolor = $style{"tablerow_light"};
787
} else {
788
$bgcolor = $style{"tablerow_dark"};
789
}
790
$i++;
791
}
792
$html =~ s/\@\@\@ADDRESSES\@\@\@/$temphtml/;
793
794
httpprint([], [htmlheader(), $html, htmlfooter(2)]);
795
}
796
########## END EDITADDRESSES #####################################
797
798
########## MODADDRESS ############################################
799
sub modaddress {
800
my $mode = shift;
801
my $realname = param('realname') || '';
802
my $address = param('email') || '';
803
my $usernote = param('note') || '';
804
$realname =~ s/^\s*//; $realname =~ s/^\s*//;
805
$address =~ s/[\<\>\[\]\\:\`\"\s]//g;
806
$address =~ s/^\s*mailto:\s*//;
807
$usernote =~ s/^\s*//; $usernote =~ s/\s*$//;
808
809
if (($realname && $address) || (($mode eq 'delete') && $realname) ) {
810
811
my $addrbookfile=dotpath('address.book');
812
my ($stat,$err,@namelist);
813
my (%addresses, %notes, $name, $email, $note);
814
815
ow::filelock::lock($addrbookfile, LOCK_EX) or
816
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $addrbookfile!");
817
818
if (! -z $addrbookfile ) {
819
($stat,$err,@namelist)=read_abook($addrbookfile, \%addresses, \%notes);
820
if ($stat<0) {
821
ow::filelock::lock($addrbookfile, LOCK_UN);
822
openwebmailerror(__FILE__, __LINE__, $err);
823
}
824
}
825
826
if ($mode eq 'delete') {
827
delete $addresses{"$realname"};
828
} else {
829
if ( (-s $addrbookfile) >= ($config{'maxbooksize'} * 1024) ) {
830
ow::filelock::lock($addrbookfile, LOCK_UN);
831
openwebmailerror(__FILE__, __LINE__, qq|$lang_err{'abook_toobig'} <a href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=editaddresses&amp;sessionid=$thissession&amp;sort=$sort&amp;folder=$escapedfolder&amp;page=$page&amp;message_id=$escapedmessageid">$lang_err{'back'}</a>$lang_err{'tryagain'}|);
832
}
833
$addresses{"$realname"} = $address;
834
# overwrite old note only if new one is not _reserved_
835
# check addaddress in openwebmail-read.pl
836
$notes{"$realname"} = $usernote if ($usernote ne '_reserved_');
837
}
838
839
# replace the address book
840
($stat,$err)=write_abook($addrbookfile,$config{'maxbooksize'},\%addresses,\%notes);
841
if ($stat<0) {
842
ow::filelock::lock($addrbookfile, LOCK_UN) or
843
openwebmailerror(__FILE__, __LINE__, $err);
844
}
845
846
ow::filelock::lock($addrbookfile, LOCK_UN);
847
}
848
849
if ( param('message_id') ) {
850
my $searchtype = param('searchtype') || 'subject';
851
my $keyword = param('keyword') || '';
852
my $escapedkeyword = ow::tool::escapeURL($keyword);
853
print redirect(-location=>"$config{'ow_cgiurl'}/openwebmail-read.pl?sessionid=$thissession&folder=$escapedfolder&page=$page&sort=$sort&keyword=$escapedkeyword&searchtype=$searchtype&message_id=$escapedmessageid&action=readmessage&headers=$prefs{'headers'}&attmode=simple");
854
} else {
855
editaddresses();
856
}
857
}
858
########## END MODADDRESS ########################################
859
860
########## CLEARADDRESS ##########################################
861
sub clearaddress {
862
my $addrbookfile=dotpath('address.book');
863
864
if ( -f $addrbookfile ) {
865
open (ABOOK, ">$addrbookfile") or
866
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $addrbookfile! ($!)");
867
close (ABOOK) or openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_close'} $addrbookfile! ($!)");
868
}
869
870
writelog("clear addressbook");
871
writehistory("clear addressbook");
872
873
editaddresses();
874
}
875
########## END CLEARADDRESS ######################################
876
877
########## IS_ENTRY_MATCHED ######################################
878
sub is_entry_matched {
879
my ($keyword,$searchtype, $name,$note,$email)=@_;
880
881
$keyword=~s/^\s*//; $keyword=~s/\s*$//;
882
return 1 if ($keyword eq '');
883
884
my %string= (
885
name => $name,
886
email => $email,
887
note => $note,
888
all => "$name $email $note"
889
);
890
if ($string{$searchtype}=~/\Q$keyword\E/i ||
891
(ow::tool::is_regex($keyword) && $string{$searchtype}=~/$keyword/i) ) {
892
return 1;
893
}
894
return 0;
895
}
896
########## END IS_ENTRY_MATCHED ##################################
897
898
########## READ_ABOOK ######################################
899
# Read the address book file (assumes locking has been done elsewhere)
900
sub read_abook {
901
my ($file, $r_addr, $r_notes)=@_;
902
my ($stat,$err,@namelist)=(0);
903
904
# read openwebmail addressbook
905
if ( open(ABOOK, $file) ) {
906
while (<ABOOK>) {
907
my ($name, $email, $note) = split(/\@\@\@/, $_, 3);
908
chomp($email); chomp($note);
909
$$r_addr{$name} = $email;
910
$$r_notes{$name} = $note;
911
push(@namelist, $name);
912
}
913
close (ABOOK) or ($stat,$err)=(-1, "$lang_err{'couldnt_close'} $file! ($!)");
914
} else {
915
($stat,$err)=(-1, "$lang_err{'couldnt_open'} $file! ($!)");
916
}
917
918
return ($stat,$err,@namelist);
919
}
920
########## END READ_ABOOK ######################################
921
922
########## WRITE_ABOOK ######################################
923
# Write the address book file (assumes locking has been done elsewhere)
924
sub write_abook {
925
my ($file, $maxsize, $r_addr, $r_notes)=@_;
926
my ($stat,$err,$abooktowrite)=(0);
927
928
foreach (sort keys %$r_addr) {
929
my ($name,$email,$note)=($_, $$r_addr{$_}, $$r_notes{$_});
930
$name=~s/\@\@/\@\@ /g; $name=~s/\@$/\@ /;
931
$email=~s/\@\@/\@\@ /g; $email=~s/\@$/\@ /;
932
$abooktowrite .= "$name\@\@\@$email\@\@\@$note\n";
933
}
934
if (length($abooktowrite) <= ($maxsize * 1024)) {
935
if ( open(ABOOK, ">$file") ) {
936
print ABOOK $abooktowrite;
937
close (ABOOK) or ($stat,$err)=(-1, "$lang_err{'couldnt_close'} $file! ($!)");
938
} else {
939
($stat,$err)=(-1, "$lang_err{'couldnt_open'} $file! ($!)");
940
}
941
} else {
942
($stat,$err)=(-2, qq|$lang_err{'abook_toobig'}|.
943
qq|<a href="$config{'ow_cgiurl'}/openwebmail-abook.pl?action=importabook&amp;sessionid=$thissession&amp;sort=$sort&amp;folder=$escapedfolder&amp;page=$page&amp;message_id=$escapedmessageid">$lang_err{'back'}</a>|.
944
qq|$lang_err{'tryagain'}|);
945
}
946
947
return ($stat,$err);
948
}
949
########## END WRITE_ABOOK ######################################
950
951