Sharedwww / cgi-bin / openwebmail / openwebmail-advsearch.plOpen in CoCalc
Author: William A. Stein
1
#!/usr/bin/perl
2
#
3
# openwebmail-adsearch.pl - advanced search program
4
#
5
# 2002/06/29 [email protected]
6
#
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 '') { print "Content-type: text/html\n\nSCRIPT_DIR not set in /etc/openwebmail/openwebmail_path.conf !\n"; exit 0; }
14
push (@INC, $SCRIPT_DIR);
15
16
foreach (qw(ENV BASH_ENV CDPATH IFS TERM)) {delete $ENV{$_}}; $ENV{PATH}='/bin:/usr/bin'; # secure ENV
17
umask(0002); # make sure the openwebmail group can write
18
19
use strict;
20
use Fcntl qw(:DEFAULT :flock);
21
use CGI qw(-private_tempfiles :standard);
22
use CGI::Carp qw(fatalsToBrowser carpout);
23
use MIME::Base64;
24
use MIME::QuotedPrint;
25
26
require "modules/dbm.pl";
27
require "modules/suid.pl";
28
require "modules/filelock.pl";
29
require "modules/tool.pl";
30
require "modules/datetime.pl";
31
require "modules/lang.pl";
32
require "modules/mime.pl";
33
require "modules/mailparse.pl";
34
require "modules/htmltext.pl";
35
require "auth/auth.pl";
36
require "quota/quota.pl";
37
require "shares/ow-shared.pl";
38
require "shares/iconv.pl";
39
require "shares/maildb.pl";
40
require "shares/getmsgids.pl";
41
42
# common globals
43
use vars qw(%config %config_raw);
44
use vars qw($thissession);
45
use vars qw($domain $user $userrealname $uuid $ugid $homedir);
46
use vars qw(%prefs %style %icontext);
47
48
# extern vars
49
use vars qw($_OFFSET $_FROM $_TO $_DATE $_SUBJECT $_CONTENT_TYPE $_STATUS $_SIZE $_REFERENCES $_CHARSET); # defined in maildb.pl
50
use vars qw(%lang_folders %lang_advsearchlabels %lang_text %lang_err); # defined in lang/xy
51
52
# local vars
53
use vars qw($folder);
54
55
########## MAIN ##################################################
56
openwebmail_requestbegin();
57
$SIG{PIPE}=\&openwebmail_exit; # for user stop
58
$SIG{TERM}=\&openwebmail_exit; # for user stop
59
60
userenv_init();
61
62
if (!$config{'enable_webmail'}) {
63
openwebmailerror(__FILE__, __LINE__, "$lang_text{'webmail'} $lang_err{'access_denied'}");
64
}
65
66
$folder = param('folder') || 'INBOX';
67
68
my $action = param('action')||'';
69
if ($action eq "advsearch") {
70
advsearch();
71
} else {
72
openwebmailerror(__FILE__, __LINE__, "Action $lang_err{'has_illegal_chars'}");
73
}
74
75
openwebmail_requestend();
76
########## END MAIN ##############################################
77
78
########## ADVSEARCH #############################################
79
sub advsearch {
80
my @search;
81
82
for (my $i=0; $i<3; $i++) {
83
my $text=param('searchtext'.$i); $text=~s/^\s*//; $text=~s/\s*$//;
84
push(@search, {where=>param('where'.$i)||'', type=>param('type'.$i)||'', text=>$text||''} );
85
}
86
87
my $resline = param('resline') || $prefs{'msgsperpage'} || 10;
88
my @folders = param('folders');
89
for (my $i=0; $i<=$#folders; $i++) {
90
$folders[$i]=safefoldername($folders[$i]);
91
}
92
93
my ($html, $temphtml);
94
$html = applystyle(readtemplate("advsearch.template"));
95
96
## replace @@@[email protected]@@ ##
97
$temphtml = iconlink("backtofolder.gif", "$lang_text{'backto'} ".( $lang_folders{$folder}||$folder), qq|accesskey="B" href="$config{'ow_cgiurl'}/openwebmail-main.pl?action=listmessages&amp;sessionid=$thissession&amp;folder=|.ow::tool::escapeURL($folder).qq|"|). qq| \n|;
98
$html =~ s/\@\@\@MENUBARLINKS\@\@\@/$temphtml/g;
99
100
## replace @@@[email protected]@@ ##
101
$temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail-advsearch.pl",
102
-name=>'advsearchform').
103
ow::tool::hiddens(action=>'advsearch',
104
sessionid=>$thissession);
105
$html =~ s/\@\@\@STARTADVSEARCHFORM\@\@\@/$temphtml/;
106
107
for(my $i=0; $i<=2; $i++) {
108
my %labels = ('from'=>$lang_text{'from'},
109
'to'=>$lang_text{'to'},
110
'subject'=>$lang_text{'subject'},
111
'date'=>$lang_text{'date'},
112
'attfilename'=>$lang_text{'attfilename'},
113
'header'=>$lang_text{'header'},
114
'textcontent'=>$lang_text{'textcontent'},
115
'all'=>$lang_text{'all'});
116
$temphtml = popup_menu(-name=>"where$i",
117
-values=>['from', 'to', 'subject', 'date', 'attfilename', 'header', 'textcontent' ,'all'],
118
-default=>${$search[$i]}{'where'}|| 'subject',
119
-labels=>\%labels);
120
$html =~ s/\@\@\@WHEREMENU$i\@\@\@/$temphtml/;
121
122
$temphtml = popup_menu(-name=>"type$i",
123
-values=>['contains', 'notcontains', 'is', 'isnot', 'startswith', 'endswith', 'regexp'],
124
-default=>${$search[$i]}{'type'} || 'contains',
125
-labels=>\%lang_advsearchlabels);
126
$html =~ s/\@\@\@TYPEMENU$i\@\@\@/$temphtml/;
127
128
$temphtml = textfield(-name=>"searchtext$i",
129
-default=>${$search[$i]}{'text'},
130
-size=>'40',
131
-accesskey=>$i+1,
132
-override=>'1');
133
$html =~ s/\@\@\@SEARCHTEXT$i\@\@\@/$temphtml/;
134
}
135
136
$temphtml = submit(-name=>$lang_text{'search'},
137
-accesskey=>'S',
138
-class=>"medtext");
139
$html =~ s/\@\@\@BUTTONSEARCH\@\@\@/$temphtml/;
140
141
$temphtml = textfield(-name=>'resline',
142
-default=>"$resline",
143
-size=>'5',
144
-accesskey=>'L',
145
-override=>'1');
146
$html =~ s/\@\@\@RESLINE\@\@\@/$temphtml/;
147
148
$temphtml = qq|<table cols=4 width="100%">\n|;
149
150
my (@validfolders, $inboxusage, $folderusage);
151
getfolders(\@validfolders, \$inboxusage, \$folderusage);
152
153
for(my $i=0; $i<=$#validfolders; $i++) {
154
$temphtml.=qq|<tr>| if ($i%4==0);
155
$temphtml.=qq|<td>|;
156
if($validfolders[$i] eq 'INBOX') {
157
$temphtml .= checkbox(-name=>'folders',
158
-value=>$validfolders[$i],
159
-checked=>1,
160
-label=>'').
161
$lang_folders{$validfolders[$i]};
162
} else {
163
my $folderstr=$validfolders[$i];
164
if ( defined($lang_folders{$validfolders[$i]}) ) {
165
$folderstr=$lang_folders{$validfolders[$i]};
166
}
167
$temphtml .= checkbox(-name=>'folders',
168
-value=>$validfolders[$i],
169
-label=>'').
170
$folderstr;
171
}
172
$temphtml.=qq|</td>|;
173
$temphtml.=qq|</tr>\n| if ($i%4==3);
174
}
175
$temphtml.=qq|</table>|;
176
$html =~ s/\@\@\@FOLDERLIST\@\@\@/$temphtml/;
177
178
$temphtml = end_form();
179
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/g;
180
181
$temphtml = $lang_text{'folder'};
182
$html =~ s/\@\@\@FOLDER\@\@\@/$temphtml/g;
183
$temphtml = $lang_text{'date'};
184
$html =~ s/\@\@\@DATE\@\@\@/$temphtml/g;
185
$temphtml = $lang_text{'sender'};
186
$html =~ s/\@\@\@SENDER\@\@\@/$temphtml/g;
187
$temphtml = $lang_text{'subject'};
188
$html =~ s/\@\@\@SUBJECT\@\@\@/$temphtml/g;
189
190
my ($totalfound, $resulthtml);
191
if( ${$search[0]}{'text'} eq '' && ${$search[1]}{'text'} eq '' && ${$search[2]}{'text'} eq '') {
192
$temphtml = "";
193
$html =~ s/\@\@\@TOTALFOUND\@\@\@/$temphtml/g;
194
$html =~ s/\@\@\@SEARCHRESULT\@\@\@/$temphtml/g;
195
} elsif ($#folders < 0) {
196
$temphtml = $lang_text{'nofoldersel'};
197
$html =~ s/\@\@\@TOTALFOUND\@\@\@/$temphtml/g;
198
$temphtml = "";
199
$html =~ s/\@\@\@SEARCHRESULT\@\@\@/$temphtml/g;
200
} else {
201
my $r_result = search_folders(\@search, \@folders, dotpath('search.cache'));
202
my $totalfound= $#{$r_result}+1;
203
if ($totalfound <= $resline) {
204
$html =~ s/\@\@\@TOTALFOUND\@\@\@/$totalfound/g;
205
} else {
206
my $escapedfolders;
207
foreach (@folders) {
208
$escapedfolders .= "folders=".ow::tool::escapeURL($_)."&amp;";
209
}
210
my $showall_url=qq|$config{'ow_cgiurl'}/openwebmail-advsearch.pl?sessionid=$thissession|.
211
qq|&amp;action=advsearch|.
212
qq|&amp;where0=${$search[0]}{'where'}&amp;type0=${$search[0]}{'type'}&amp;searchtext0=|.ow::tool::escapeURL(${$search[0]}{'text'}).
213
qq|&amp;where1=${$search[1]}{'where'}&amp;type1=${$search[1]}{'type'}&amp;searchtext1=|.ow::tool::escapeURL(${$search[1]}{'text'}).
214
qq|&amp;where2=${$search[2]}{'where'}&amp;type2=${$search[2]}{'type'}&amp;searchtext2=|.ow::tool::escapeURL(${$search[2]}{'text'}).
215
qq|&amp;resline=$totalfound&amp;$escapedfolders|;
216
$temphtml=qq|$totalfound &nbsp;<a href="$showall_url">[$lang_text{'showall'}]</a>|;
217
$html =~ s/\@\@\@TOTALFOUND\@\@\@/$temphtml/g;
218
}
219
220
$temphtml="";
221
for (my $i=0; $i<$totalfound; $i++) {
222
last if ($i>$resline);
223
$temphtml.=genline($i%2, split(/\@\@\@/, ${$r_result}[$i]));
224
}
225
$html =~ s/\@\@\@SEARCHRESULT\@\@\@/$temphtml/g;
226
}
227
228
httpprint([], [htmlheader(), $html, htmlfooter(2)]);
229
}
230
########## END ADVSEARCH #########################################
231
232
########## SEARCH_FOLDERS ########################################
233
sub search_folders {
234
my ($r_search, $r_folders, $cachefile)=@_;
235
my ($metainfo, $cache_metainfo, $r_result);
236
237
foreach my $search (@{$r_search}) {
238
if (${$search}{'text'} ne "") {
239
$metainfo.=join("@@@", ${$search}{'where'}, ${$search}{'type'}, ${$search}{'text'});
240
}
241
}
242
$metainfo.="@@@".join("@@@", @{$r_folders});
243
244
$cachefile=ow::tool::untaint($cachefile);
245
ow::filelock::lock($cachefile, LOCK_EX) or
246
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $cachefile");
247
if ( -e $cachefile ) {
248
open(CACHE, "$cachefile") or
249
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $cachefile! ($!)");
250
$cache_metainfo=<CACHE>; chomp($cache_metainfo);
251
close(CACHE);
252
}
253
254
if ( $cache_metainfo ne $metainfo ) {
255
open(CACHE, ">$cachefile");
256
print CACHE $metainfo, "\n";
257
$r_result=search_folders2($r_search, $r_folders);
258
print CACHE join("\n", $#{$r_result}+1, @{$r_result});
259
close(CACHE);
260
261
} else {
262
my @result;
263
open(CACHE, $cachefile);
264
$_=<CACHE>;
265
my $totalfound=<CACHE>;
266
while (<CACHE>) {
267
chomp;
268
push (@result, $_)
269
}
270
close(CACHE);
271
$r_result=\@result;
272
}
273
274
ow::filelock::lock($cachefile, LOCK_UN);
275
276
return($r_result);
277
}
278
279
sub search_folders2 {
280
my ($r_search, $r_folders)=@_;
281
my (@validsearch, %found);
282
my @result;
283
284
foreach my $search (@{$r_search}) {
285
push(@validsearch, $search) if (${$search}{'text'} ne "");
286
}
287
288
# search for the messageid in selected folder, return @result
289
foreach my $foldertosearch (@{$r_folders}) {
290
my ($folderfile, $folderdb)=get_folderpath_folderdb($user, $foldertosearch);
291
my $r_messageids=get_messageids_sorted_by_date($folderdb, 1);
292
my (%FDB, %status);
293
294
ow::dbm::open(\%FDB, $folderdb, LOCK_SH) or
295
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_locksh'} db $folderdb");
296
open (FOLDER, "$folderfile"); # used in TEXTCONTENT search
297
298
foreach my $messageid (@{$r_messageids}) {
299
# begin the search
300
my ($block, $header, $body, $r_attachments);
301
my @attr=string2msgattr($FDB{$messageid});
302
my $is_conv=is_convertable($attr[$_CHARSET], $prefs{'charset'});
303
my $state=0;
304
305
foreach my $search (@validsearch) {
306
my ($where, $type, $keyword) = (${$search}{'where'}, ${$search}{'type'}, ${$search}{'text'});
307
my $regexvalid=ow::tool::is_regex($keyword);
308
my @placetosearch;
309
if ($where eq 'all') {
310
@placetosearch=('subject', 'from', 'to', 'date', 'header', 'attfilename', 'textcontent');
311
} else {
312
push(@placetosearch, $where);
313
}
314
315
foreach $where (@placetosearch) {
316
# check subject, from, to, date
317
if ($where eq 'subject' || $where eq 'from' || $where eq 'to' || $where eq 'date') {
318
my %index=(
319
subject => $_SUBJECT,
320
from => $_FROM,
321
to => $_TO,
322
date => $_DATE
323
);
324
my $data=$attr[$index{$where}];
325
($data)=iconv($attr[$_CHARSET], $prefs{'charset'}, $data) if ($is_conv);
326
327
if ( ($type eq 'contains' && $data=~/\Q$keyword\E/i) ||
328
($type eq 'notcontains' && $data!~/\Q$keyword\E/i) ||
329
($type eq 'is' && $data=~/^\Q$keyword\E$/i) ||
330
($type eq 'isnot' && $data!~/^\Q$keyword\E$/i) ||
331
($type eq 'startswith' && $data=~/^\Q$keyword\E/i) ||
332
($type eq 'endswith' && $data=~/\Q$keyword\E$/i) ||
333
($type eq 'regexp' && $regexvalid && $data=~/$keyword/i) ) {
334
if($state == $#validsearch) {
335
$found{$messageid}=1; $state = 0;
336
} else {
337
$state++;
338
}
339
@placetosearch = ();
340
next;
341
}
342
343
# check header
344
} elsif ($where eq 'header') {
345
# check de-mimed header first since header in mail folder is raw format.
346
seek(FOLDER, $attr[$_OFFSET], 0);
347
$header="";
348
while(<FOLDER>) {
349
$header.=$_;
350
last if ($_ eq "\n");
351
}
352
$header = ow::mime::decode_mimewords($header);
353
$header=~s/\n / /g; # handle folding roughly
354
($header)=iconv($attr[$_CHARSET], $prefs{'charset'}, $header) if ($is_conv);
355
356
if (($type eq 'contains' && $header=~/\Q$keyword\E/im) ||
357
($type eq 'notcontains' && $header!~/\Q$keyword\E/im) ||
358
($type eq 'is' && $header=~/^\Q$keyword\E$/im) ||
359
($type eq 'isnot' && $header!~/^\Q$keyword\E$/im) ||
360
($type eq 'startswith' && $header=~/^\Q$keyword\E/im) ||
361
($type eq 'endswith' && $header=~/\Q$keyword\E$/im) ||
362
($type eq 'regexp' && $regexvalid && $header=~/$keyword/im)) {
363
if($state == $#validsearch) {
364
$found{$messageid}=1; $state = 0;
365
} else {
366
$state++;
367
}
368
@placetosearch = ();
369
next;
370
}
371
372
# read and parse message
373
} elsif ($where eq 'textcontent' || $where eq 'attfilename') {
374
seek(FOLDER, $attr[$_OFFSET], 0);
375
read(FOLDER, $block, $attr[$_SIZE]);
376
($header, $body, $r_attachments)=ow::mailparse::parse_rfc822block(\$block);
377
378
# check textcontent: text in body and attachments
379
if ($where eq 'textcontent') {
380
# check body
381
if ( $attr[$_CONTENT_TYPE] =~ /^text/i ||
382
$attr[$_CONTENT_TYPE] eq "N/A" ) { # read all for text/plain,text/html
383
if ($header =~ /content-transfer-encoding:\s+quoted-printable/i) {
384
$body = decode_qp($body);
385
} elsif ($header =~ /content-transfer-encoding:\s+base64/i) {
386
$body = decode_base64($body);
387
} elsif ($header =~ /content-transfer-encoding:\s+x-uuencode/i) {
388
$body = ow::mime::uudecode($body);
389
}
390
($body)=iconv($attr[$_CHARSET], $prefs{'charset'}, $body) if ($is_conv);
391
392
if (($type eq 'contains' && $body=~/\Q$keyword\E/im) ||
393
($type eq 'notcontains' && $body!~/\Q$keyword\E/im) ||
394
($type eq 'is' && $body=~/^\Q$keyword\E$/im) ||
395
($type eq 'isnot' && $body!~/^\Q$keyword\E$/im) ||
396
($type eq 'startswith' && $body=~/^\Q$keyword\E/im) ||
397
($type eq 'endswith' && $body=~/\Q$keyword\E$/im) ||
398
($type eq 'regexp' && $regexvalid && $body=~/$keyword/im)) {
399
if($state == $#validsearch) {
400
$found{$messageid}=1; $state = 0;
401
} else {
402
$state++;
403
}
404
@placetosearch = ();
405
next;
406
}
407
}
408
409
# check attachments
410
foreach my $r_attachment (@{$r_attachments}) {
411
if ( ${$r_attachment}{'content-type'} =~ /^text/i ||
412
${$r_attachment}{'content-type'} eq "N/A" ) { # read all for text/plain. text/html
413
my $content;
414
if ( ${$r_attachment}{'content-transfer-encoding'} =~ /^quoted-printable/i ) {
415
$content = decode_qp( ${${$r_attachment}{r_content}});
416
} elsif ( ${$r_attachment}{'content-transfer-encoding'} =~ /^base64/i ) {
417
$content = decode_base64( ${${$r_attachment}{r_content}});
418
} elsif ( ${$r_attachment}{'content-transfer-encoding'} =~ /^x-uuencode/i ) {
419
$content = ow::mime::uudecode( ${${$r_attachment}{r_content}});
420
} else {
421
$content=${${$r_attachment}{r_content}};
422
}
423
my $charset=${$r_attachment}{charset}||$attr[$_CHARSET];
424
if (is_convertable($charset, $prefs{'charset'})) {
425
($content)=iconv($charset, $prefs{'charset'}, $content);
426
}
427
428
if (($type eq 'contains' && $content=~/\Q$keyword\E/im) ||
429
($type eq 'notcontains' && $content!~/\Q$keyword\E/im) ||
430
($type eq 'is' && $content=~/^\Q$keyword\E$/im) ||
431
($type eq 'isnot' && $content!~/^\Q$keyword\E$/im) ||
432
($type eq 'startswith' && $content=~/^\Q$keyword\E/im) ||
433
($type eq 'endswith' && $content=~/\Q$keyword\E$/im) ||
434
($type eq 'regexp' && $regexvalid && $content=~/$keyword/im)) {
435
if($state == $#validsearch) {
436
$found{$messageid}=1; $state = 0;
437
} else {
438
$state++;
439
}
440
@placetosearch = ();
441
@{$r_attachments} = ();
442
next;
443
}
444
}
445
}
446
}
447
448
# check attfilename
449
if ($where eq 'attfilename') {
450
foreach my $r_attachment (@{$r_attachments}) {
451
my $filename=${$r_attachment}{filename};
452
my $charset=${$r_attachment}{filenamecharset}||${$r_attachment}{charset}||$attr[$_CHARSET];
453
if (is_convertable($charset, $prefs{'charset'})) {
454
($filename)=iconv($charset, $prefs{'charset'}, $filename);
455
}
456
457
if (($type eq 'contains' && $filename=~/\Q$keyword\E/im) ||
458
($type eq 'notcontains' && $filename!~/\Q$keyword\E/im) ||
459
($type eq 'is' && $filename=~/^\Q$keyword\E$/im) ||
460
($type eq 'isnot' && $filename!~/^\Q$keyword\E$/im) ||
461
($type eq 'startswith' && $filename=~/^\Q$keyword\E/im) ||
462
($type eq 'endswith' && $filename=~/\Q$keyword\E$/im) ||
463
($type eq 'regexp' && $regexvalid && $filename=~/$keyword/im)) {
464
if($state == $#validsearch) {
465
$found{$messageid}=1; $state = 0;
466
} else {
467
$state++;
468
}
469
@placetosearch = ();
470
@{$r_attachments} = ();
471
next;
472
}
473
}
474
}
475
} # end block check texcontent & attfilename
476
477
} # end block placetosearch
478
} # end block multiple text search
479
480
# generate messageid table line result if found
481
if($found{$messageid}) { # create the line to print into resultsearch
482
push(@result, join("@@@", $foldertosearch, $messageid, @attr));
483
}
484
485
} # end messageid loop
486
487
ow::dbm::close(\%FDB, $folderdb);
488
close(FOLDER);
489
ow::filelock::lock($folderfile, LOCK_UN);
490
} # end foldertosearch loop
491
492
return(\@result)
493
}
494
########## END SEARCH_FOLDERS ####################################
495
496
########## GENLINE ###############################################
497
# this routines generates one line table containing folder, msgid and @attr
498
sub genline {
499
my ($colornum, $folder, $messageid, @attr) = @_;
500
my ($escapedmessageid);
501
my ($offset, $from, $to, $dateserial, $subject, $content_type, $status, $messagesize, $references, $charset);
502
my ($bgcolor, $message_status,$temphtml,$folderstr,$escapedfolder);
503
504
if ( defined($lang_folders{$folder}) ) {
505
$folderstr = $lang_folders{$folder};
506
} else {
507
$folderstr = $folder;
508
}
509
510
if ( $colornum ) {
511
$bgcolor = $style{"tablerow_light"};
512
} else {
513
$bgcolor = $style{"tablerow_dark"};
514
}
515
516
$escapedfolder = ow::tool::escapeURL($folder);
517
$escapedmessageid = ow::tool::escapeURL($messageid);
518
($offset, $from, $to, $dateserial, $subject, $content_type, $status, $messagesize, $references, $charset) = @attr;
519
520
# convert from mesage charset to current user charset
521
if (is_convertable($charset, $prefs{'charset'})) {
522
($from, $to, $subject)=iconv($charset, $prefs{'charset'}, $from, $to, $subject);
523
}
524
525
my ($from_name, $from_address)=ow::tool::email2nameaddr($from);
526
my $escapedfrom=ow::tool::escapeURL($from);
527
$from = qq|<a href="$config{'ow_cgiurl'}/openwebmail-send.pl\?action=composemessage&amp;sessionid=$thissession&amp;composetype=sendto&amp;to=$escapedfrom" title="$from_address">$from_name </a>|;
528
529
$subject=substr($subject, 0, 64)."..." if (length($subject)>67);
530
$subject = ow::htmltext::str2html($subject);
531
if ($subject !~ /[^\s]/) { # Make sure there's SOMETHING clickable
532
$subject = "N/A";
533
}
534
535
# Round message size and change to an appropriate unit for display
536
$messagesize=lenstr($messagesize,0);
537
538
# convert dateserial(GMT) to localtime
539
my $datestr=ow::datetime::dateserial2str($dateserial,
540
$prefs{'timeoffset'}, $prefs{'daylightsaving'},
541
$prefs{'dateformat'}, $prefs{'hourformat'});
542
$temphtml = qq|<tr>|.
543
qq|<td nowrap bgcolor=$bgcolor>$folderstr&nbsp;</td>\n|.
544
qq|<td bgcolor=$bgcolor>$datestr</td>\n|.
545
qq|<td bgcolor=$bgcolor>$from</td>\n|.
546
qq|<td bgcolor=$bgcolor>|.
547
qq|<a href="$config{'ow_cgiurl'}/openwebmail-read.pl?action=readmessage&amp;|.
548
qq|sessionid=$thissession&amp;folder=$escapedfolder&amp;|.
549
qq|headers=|.($prefs{'headers'} || 'simple').qq|&amp;|.
550
qq|message_id=$escapedmessageid">\n$subject \n</a></td></tr>\n|;
551
552
return $temphtml;
553
}
554
########## END GENLINE ###########################################
555