mailboxes/0040775000567100000120000000000010446424372012535 5ustar jcameronwheelmailboxes/boxes-lib.pl0100644000567100000120000015050010444317665014756 0ustar jcameronwheel# boxes-lib.pl # Functions to parsing user mail files use POSIX; use Time::Local; # list_mails(user|file, [start], [end]) # Returns a subset of mail from a mbox format file sub list_mails { local (@rv, $h, $done); my (@index, %index, $itype); $itype = &index_type($_[0]); if ($itype == 0) { @index = &build_index($_[0]); } else { &build_dbm_index($_[0], \%index); } local ($start, $end); local $isize = $itype == 0 ? scalar(@index) : $index{'mailcount'}; if (@_ == 1 || !defined($_[1]) && !defined($_[2])) { $start = 0; $end = $isize-1; } elsif ($_[2] < 0) { $start = $isize+$_[2]-1; $end = $isize+$_[1]-1; $start = $start<0 ? 0 : $start; } else { $start = $_[1]; $end = $_[2]; $end = $isize-1 if ($end >= $isize); } $rv[$isize-1] = undef if ($isize); # force array to right size local $dash = &dash_mode($_[0]); open(MAIL, &user_mail_file($_[0])); $start = 0 if ($start < 0); for($i=$start; $i<=$end; $i++) { # Seek to mail position local $startline; if ($itype == 0) { seek(MAIL, $index[$i]->[0], 0); $startline = $index[$i]->[1]; } else { local @idx = split(/\0/, $index{$i}); seek(MAIL, $idx[0], 0); $startline = $idx[1]; } # Read the mail local $mail = &read_mail_fh(MAIL, $dash ? 2 : 1, 0); $mail->{'line'} = $startline; $mail->{'eline'} = $startline + $mail->{'lines'} - 1; $mail->{'idx'} = $i; $rv[$i] = $mail; } return @rv; } # select_mails(user|file, &indexes, headersonly) # Returns a list of messages with the given indexes sub select_mails { local (@rv); my (@index, %index, $itype); $itype = &index_type($_[0]); if ($itype == 0) { @index = &build_index($_[0]); } else { &build_dbm_index($_[0], \%index); } local $isize = $itype == 0 ? scalar(@index) : $index{'mailcount'}; open(MAIL, &user_mail_file($_[0])); foreach my $i (@{$_[1]}) { # Seek to mail position local $startline; if ($itype == 0) { seek(MAIL, $index[$i]->[0], 0); $startline = $index[$i]->[1]; } else { local @idx = split(/\0/, $index{$i}); seek(MAIL, $idx[0], 0); $startline = $idx[1]; } # Read the mail local $mail = &read_mail_fh(MAIL, $dash ? 2 : 1, $_[2]); $mail->{'line'} = $startline; $mail->{'eline'} = $startline + $mail->{'lines'} - 1; $mail->{'idx'} = $i; push(@rv, $mail); } close(MAIL); return @rv; } # search_mail(user, field, match) # Returns an array of messages matching some search sub search_mail { return &advanced_search_mail($_[0], [ [ $_[1], $_[2] ] ], 1); } # advanced_search_mail(user|file, &fields, andmode, [&limits]) # Returns an array of messages matching some search sub advanced_search_mail { local $itype = &index_type($_[0]); local (@index, %index, @rv, $i); local $dash = &dash_mode($_[0]); local @possible; # index positions of possible mails local $possible_certain = 0; # is possible list authoratative? local ($min, $max); if ($itype == 0) { # We have only a plain index .. @index = &build_index($_[0]); $min = 0; $max = scalar(@index)-1; if ($_[3] && $_[3]->{'latest'}) { $min = $max - $_[3]->{'latest'}; } @possible = ($min .. $max); } else { # We have a DBM index .. if the search includes the from and subject # fields, scan it first to cut down on the total time &build_dbm_index($_[0], \%index); # Check which fields are used in search local @dbmfields = grep { $_->[0] eq 'from' || $_->[0] eq 'subject' } @{$_[1]}; local $alldbm = (scalar(@dbmfields) == scalar(@{$_[1]})); $min = 0; $max = $index{'mailcount'}-1; if ($_[3] && $_[3]->{'latest'}) { $min = $max - $_[3]->{'latest'}; } # Only check DBM if it contains some fields, and if it contains all # fields when in 'or' mode. if (@dbmfields && ($alldbm || $_[2])) { # Scan the DBM to build up a list of 'possibles' for($i=$min; $i<=$max; $i++) { local @idx = split(/\0/, $index{$i}); local $fake = { 'header' => { 'from', $idx[2], 'subject', $idx[3] } }; local $m = &mail_matches(\@dbmfields, $_[2], $fake); push(@possible, $i) if ($m); } $possible_certain = $alldbm; } else { # None of the DBM fields are in the search .. have to scan all @possible = ($min .. $max); } } # Need to scan through possible messages to find those that match open(MAIL, &user_mail_file($_[0])); foreach $i (@possible) { # Seek to mail position local $startline; if ($itype == 0) { seek(MAIL, $index[$i]->[0], 0); $startline = $index[$i]->[1]; } else { local @idx = split(/\0/, $index{$i}); seek(MAIL, $idx[0], 0); $startline = $idx[1]; } # Read the mail local $mail = &read_mail_fh(MAIL, $dash ? 2 : 1, 0); $mail->{'line'} = $startline; $mail->{'eline'} = $startline + $mail->{'lines'} - 1; $mail->{'idx'} = $i; push(@rv, $mail) if ($possible_certain || &mail_matches($_[1], $_[2], $mail)); } return @rv; } # build_index(user|file) sub build_index { local @index; local $ifile = &user_index_file($_[0]); local $umf = &user_mail_file($_[0]); local @ist = stat($ifile); local @st = stat($umf); if (open(INDEX, $ifile)) { @index = map { /(\d+)\s+(\d+)/; [ $1, $2 ] } ; close(INDEX); } if (!@ist || !@st || $ist[9] < $st[9] || $st[7] < $config{'index_min'}) { # The mail file is newer than the index, or we are always re-indexing local $fromok = 1; local ($l, $ll); local $dash = &dash_mode($umf); if ($st[7] < $config{'index_min'}) { $fromok = 0; # Always re-index open(MAIL, $umf); } else { if (open(MAIL, $umf)) { local $il = $#index; local $i; for($i=($il>100 ? 100 : $il); $i>=0; $i--) { $l = $index[$il-$i]; seek(MAIL, $index[$il-$i]->[0], 0); $ll = ; $fromok = 0 if ($ll !~ /^From\s+(\S+).*\d+\r?\n/ || ($1 eq '-' && !$dash)); } } else { $fromok = 0; # No mail file yet } } local ($pos, $lnum); if (scalar(@index) && $fromok && $st[7] > $l->[0]) { # Mail file seems to have gotten bigger, most likely # because new mail has arrived ... only reindex the new mails $pos = $l->[0] + length($ll); $lnum = $l->[1] + 1; } else { # Mail file has changed in some other way ... do a rebuild $pos = 0; $lnum = 0; undef(@index); seek(MAIL, 0, 0); } while() { if (/^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $dash)) { push(@index, [ $pos, $lnum ]); } $pos += length($_); $lnum++; } close(MAIL); open(INDEX, ">$ifile"); print INDEX map { $_->[0]." ".$_->[1]."\n" } @index; close(INDEX); } return @index; } # build_dbm_index(user|file, &index) # Returns a reference to a DBM hash that indexes the given mail file. # Hash contains keys 0, 1, 2 .. each of which has a value containing the # position of the mail in the file, line number, subject and sender. # Special key lastchange = time index was last updated # mailcount = number of messages in index sub build_dbm_index { local $ifile = &user_index_file($_[0]); local $umf = &user_mail_file($_[0]); local @st = stat($umf); local $index = $_[1]; dbmopen(%$index, $ifile, 0600); if (!@st || $index->{'lastchange'} < $st[9] || $st[7] < $config{'index_min'}) { # The mail file is newer than the index, or we are always re-indexing local $fromok = 1; local ($ll, @idx); local $dash = &dash_mode($umf); if ($st[7] < $config{'index_min'}) { $fromok = 0; # Always re-index open(MAIL, $umf); } else { if (open(MAIL, $umf)) { # Check the last 100 messages (at most) local $il = $index->{'mailcount'}-1; local $i; for($i=($il>100 ? 100 : $il); $i>=0; $i--) { @idx = split(/\0/, $index->{$il-$i}); seek(MAIL, $idx[0], 0); $ll = ; $fromok = 0 if ($ll !~ /^From\s+(\S+).*\d+\r?\n/ || ($1 eq '-' && !$dash)); } } else { $fromok = 0; # No mail file yet } } local ($pos, $lnum, $istart); if ($index->{'mailcount'} && $fromok && $st[7] > $idx[0]) { # Mail file seems to have gotten bigger, most likely # because new mail has arrived ... only reindex the new mails $pos = $idx[0] + length($ll); $lnum = $idx[1] + 1; $istart = $index->{'mailcount'}; } else { # Mail file has changed in some other way ... do a rebuild $istart = 0; $pos = 0; $lnum = 0; seek(MAIL, 0, 0); } local ($doingheaders, @nidx); while() { if (/^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $dash)) { @nidx = ( $pos, $lnum ); $index->{$istart++} = join("\0", @nidx); $doingheaders = 1; } elsif ($_ eq "\n" || $_ eq "\r\n") { $doingheaders = 0; } elsif ($doingheaders && /^From:\s*(.{0,255})/i) { $nidx[2] = $1; $index->{$istart-1} = join("\0", @nidx); } elsif ($doingheaders && /^Subject:\s*(.{0,255})/i) { $nidx[3] = $1; $index->{$istart-1} = join("\0", @nidx); } $pos += length($_); $lnum++; } close(MAIL); $index->{'lastchange'} = time(); $index->{'mailcount'} = $istart; } } # index_type(user|file) # Returns 0 if an old-style index exists for some mailbox, 1 if not (indicating # that DBM indexing should be used) sub index_type { return 0 if (!$config{'index_dbm'}); return 1 if ($config{'index_dbm'} == 2); local $ifile = &user_index_file($_[0]); return -r $ifile ? 0 : 1; } # empty_mail(user|file) # Truncate a mail file to nothing sub empty_mail { local $umf = &user_mail_file($_[0]); local $itype = &index_type($_[0]); local $ifile = &user_index_file($_[0]); open(TRUNC, ">$umf"); close(TRUNC); if ($itype == 0) { # Truncate index too open(TRUNC, ">$ifile"); close(TRUNC); } else { # Set index size to 0 local %index; dbmopen(%index, $ifile, 0600); $index{'mailcount'} = 0; $index{'lastchange'} = time(); dbmclose(%index); } } # count_mail(user|file) # Returns the number of messages in some mail file sub count_mail { my (@index, %index, $itype); $itype = &index_type($_[0]); if ($itype == 0) { @index = &build_index($_[0]); return scalar(@index); } else { &build_dbm_index($_[0], \%index); return $index{'mailcount'}; } } # parse_mail(&mail, [&parent], [savebody]) # Extracts the attachments from the mail body sub parse_mail { return if ($_[0]->{'parsed'}++); local $ct = $_[0]->{'header'}->{'content-type'}; local (@attach, $h, $a); if ($ct =~ /multipart\/(\S+)/i && ($ct =~ /boundary="([^"]+)"/i || $ct =~ /boundary=([^;\s]+)/i)) { # Multipart MIME message local $bound = "--".$1; local @lines = split(/\r?\n/, $_[0]->{'body'}); local $l; local $max = @lines; while($l < $max && $lines[$l++] ne $bound) { # skip to first boundary } while(1) { # read attachment headers local (@headers, $attach); while($lines[$l]) { $attach->{'raw'} .= $lines[$l]."\n"; $attach->{'rawheaders'} .= $lines[$l]."\n"; if ($lines[$l] =~ /^(\S+):\s*(.*)/) { push(@headers, [ $1, $2 ]); } elsif ($lines[$l] =~ /^\s+(.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); } $l++; } $attach->{'raw'} .= $lines[$l]."\n"; $l++; $attach->{'headers'} = \@headers; foreach $h (@headers) { $attach->{'header'}->{lc($h->[0])} = $h->[1]; } if ($attach->{'header'}->{'content-type'} =~ /^([^;]+)/) { $attach->{'type'} = lc($1); } else { $attach->{'type'} = 'text/plain'; } if ($attach->{'header'}->{'content-disposition'} =~ /filename\s*=\s*"([^"]+)"/i) { $attach->{'filename'} = $1; } elsif ($attach->{'header'}->{'content-disposition'} =~ /filename\s*=\s*([^;\s]+)/i) { $attach->{'filename'} = $1; } elsif ($attach->{'header'}->{'content-type'} =~ /name\s*=\s*"([^"]+)"/i) { $attach->{'filename'} = $1; } # read the attachment body while($l < $max && $lines[$l] ne $bound && $lines[$l] ne "$bound--") { $attach->{'data'} .= $lines[$l]."\n"; $attach->{'raw'} .= $lines[$l]."\n"; $l++; } $attach->{'data'} =~ s/\n\n$/\n/; # Lose trailing blank line $attach->{'raw'} =~ s/\n\n$/\n/; # decode if necessary if (lc($attach->{'header'}->{'content-transfer-encoding'}) eq 'base64') { # Standard base64 encoded attachment $attach->{'data'} = &b64decode($attach->{'data'}); } elsif (lc($attach->{'header'}->{'content-transfer-encoding'}) eq 'x-uue') { # UUencoded attachment $attach->{'data'} = &uudecode($attach->{'data'}); } elsif (lc($attach->{'header'}->{'content-transfer-encoding'}) eq 'quoted-printable') { # Quoted-printable text attachment $attach->{'data'} = "ed_decode($attach->{'data'}); } elsif (lc($attach->{'type'}) eq 'application/mac-binhex40' && &has_command("hexbin")) { # Macintosh binhex encoded attachment local $temp = &transname(); mkdir($temp, 0700); open(HEXBIN, "| (cd $temp ; hexbin -n attach -d 2>/dev/null)"); print HEXBIN $attach->{'data'}; close(HEXBIN); if (!$?) { open(HEXBIN, "$temp/attach.data"); local $/ = undef; $attach->{'data'} = ; close(HEXBIN); local $ct = &guess_mime_type($attach->{'filename'}); $attach->{'type'} = $ct; $attach->{'header'} = { 'content-type' => $ct }; $attach->{'headers'} = [ [ 'Content-Type', $ct ] ]; } unlink("$temp/attach.data"); rmdir($temp); } $attach->{'idx'} = scalar(@attach); $attach->{'parent'} = $_[1] ? $_[1] : $_[0]; push(@attach, $attach) if (@headers || $attach->{'data'}); if ($attach->{'type'} =~ /multipart\/(\S+)/i) { # This attachment contains more attachments .. # expand them. local $amail = { 'header' => $attach->{'header'}, 'body' => $attach->{'data'} }; &parse_mail($amail, $attach); $attach->{'attach'} = [ @{$amail->{'attach'}} ]; map { $_->{'idx'} += scalar(@attach) } @{$amail->{'attach'}}; push(@attach, @{$amail->{'attach'}}); } elsif (lc($attach->{'type'}) eq 'application/ms-tnef') { # This attachment is a winmail.dat file, which may # contain multiple other attachments! local ($opentnef, $tnef); if (!($opentnef = &has_command("opentnef")) && !($tnef = &has_command("tnef"))) { $attach->{'error'} = "tnef command not installed"; } else { # Can actually decode local $tempfile = &transname(); open(TEMPFILE, ">$tempfile"); print TEMPFILE $attach->{'data'}; close(TEMPFILE); local $tempdir = &transname(); mkdir($tempdir, 0700); if ($opentnef) { system("$opentnef -d $tempdir -i $tempfile >/dev/null 2>&1"); } else { system("$tnef -C $tempdir -f $tempfile >/dev/null 2>&1"); } pop(@attach); # lose winmail.dat opendir(DIR, $tempdir); while($f = readdir(DIR)) { next if ($f eq '.' || $f eq '..'); local $data; open(FILE, "$tempdir/$f"); while() { $data .= $_; } close(FILE); local $ct = &guess_mime_type($f); push(@attach, { 'type' => $ct, 'idx' => scalar(@attach), 'header' => { 'content-type' => $ct }, 'headers' => [ [ 'Content-Type', $ct ] ], 'filename' => $f, 'data' => $data }); } closedir(DIR); unlink(glob("$tempdir/*"), $tempfile); rmdir($tempdir); } } last if ($l >= $max || $lines[$l] eq "$bound--"); $l++; } $_[0]->{'attach'} = \@attach; } elsif ($_[0]->{'body'} =~ /begin\s+([0-7]+)\s+(.*)/i) { # Message contains uuencoded file(s) local @lines = split(/\n/, $_[0]->{'body'}); local ($attach, $rest); foreach $l (@lines) { if ($l =~ /^begin\s+([0-7]+)\s+(.*)/i) { $attach = { 'type' => &guess_mime_type($2), 'idx' => scalar(@{$_[0]->{'attach'}}), 'parent' => $_[1], 'filename' => $2 }; push(@{$_[0]->{'attach'}}, $attach); } elsif ($l =~ /^end/ && $attach) { $attach = undef; } elsif ($attach) { $attach->{'data'} .= unpack("u", $l); } else { $rest .= $l."\n"; } } if ($rest =~ /\S/) { # Some leftover text push(@{$_[0]->{'attach'}}, { 'type' => "text/plain", 'idx' => scalar(@{$_[0]->{'attach'}}), 'parent' => $_[1], 'data' => $rest }); } } elsif (lc($_[0]->{'header'}->{'content-transfer-encoding'}) eq 'base64') { # Signed body section $ct =~ s/;.*$//; $_[0]->{'attach'} = [ { 'type' => lc($ct), 'idx' => 0, 'parent' => $_[1], 'data' => &b64decode($_[0]->{'body'}) } ]; } elsif (lc($_[0]->{'header'}->{'content-type'}) eq 'x-sun-attachment') { # Sun attachment format, which can contain several sections local $sun; foreach $sun (split(/----------/, $_[0]->{'body'})) { local ($headers, $rest) = split(/\r?\n\r?\n/, $sun, 2); local $attach = { 'idx' => scalar(@{$_[0]->{'attach'}}), 'parent' => $_[1], 'data' => $rest }; if ($headers =~ /X-Sun-Data-Name:\s*(\S+)/) { $attach->{'filename'} = $1; } if ($headers =~ /X-Sun-Data-Type:\s*(\S+)/) { local $st = $1; $attach->{'type'} = $st eq "text" ? "text/plain" : $st eq "html" ? "text/html" : $st =~ /\// ? $st : "application/octet-stream"; } elsif ($attach->{'filename'}) { $attach->{'type'} = &guess_mime_type($attach->{'filename'}); } else { $attach->{'type'} = "text/plain"; # fallback } push(@{$_[0]->{'attach'}}, $attach); } } else { # One big attachment (probably text) local ($type, $body); ($type = $ct) =~ s/;.*$//; $type = 'text/plain' if (!$type); if (lc($_[0]->{'header'}->{'content-transfer-encoding'}) eq 'base64') { $body = &b64decode($_[0]->{'body'}); } elsif (lc($_[0]->{'header'}->{'content-transfer-encoding'}) eq 'quoted-printable') { $body = "ed_decode($_[0]->{'body'}); } else { $body = $_[0]->{'body'}; } $_[0]->{'attach'} = [ { 'type' => lc($type), 'idx' => 0, 'parent' => $_[1], 'data' => $body } ]; } delete($_[0]->{'body'}) if (!$_[2]); } # delete_mail(user|file, &mail, ...) # Delete mail messages from a user by copying the file and rebuilding the index sub delete_mail { local @m = sort { $a->{'line'} <=> $b->{'line'} } @_[1..@_-1]; local $i = 0; local $f = &user_mail_file($_[0]); local $ifile = &user_index_file($_[0]); local $itype = &index_type($_[0]); local $lnum = 0; local %dline; local ($dpos = 0, $dlnum = 0); local (@index, %index); if ($itype == 1) { &build_dbm_index($_[0], \%index); } local $tmpf = $< == 0 ? "$f.del" : $_[0] =~ /^\/.*\/([^\/]+)$/ ? "$user_module_config_directory/$1.del" : "$user_module_config_directory/$_[0].del"; open(SOURCE, $f) || &error("Read failed : $!"); open(DEST, ">$tmpf") || &error("Open of $tmpf failed : $!"); while() { if ($i >= @m || $lnum < $m[$i]->{'line'}) { if ($itype == 0 && /^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $dash)) { push(@index, [ $dpos, $dlnum ]); } $dpos += length($_); $dlnum++; local $w = (print DEST $_); if (!$w) { local $e = "$!"; close(DEST); close(SOURCE); unlink($tmpf); &error("Write to $tmpf failed : $e"); } } elsif ($lnum == $m[$i]->{'eline'}) { $dline{$m[$i]->{'line'}}++; $i++; } $lnum++; } close(SOURCE); close(DEST) || &error("Write to $tmpf failed : $?"); local @st = stat($f); unlink($f) if ($< == 0); if ($itype == 0) { open(INDEX, ">$ifile"); print INDEX map { $_->[0]." ".$_->[1]."\n" } @index; close(INDEX); } else { # Just force a total index re-build (XXX lazy!) $index{'mailcount'} = $in{'lastchange'} = 0; } if ($< == 0) { rename($tmpf, $f); } else { system("cat ".quotemeta($tmpf)." > ".quotemeta($f). " && rm -f ".quotemeta($tmpf)); } chown($st[4], $st[5], $f); chmod($st[2], $f); } # modify_mail(user|file, old, new, textonly) # Modify one email message in a mailbox by copying the file and rebuilding # the index. sub modify_mail { local $f = &user_mail_file($_[0]); local $ifile = &user_index_file($_[0]); local $itype = &index_type($_[0]); local $lnum = 0; local ($sizediff, $linesdiff); local (@index, %index); if ($itype == 0) { @index = &build_index($_[0]); } else { &build_dbm_index($_[0], \%index); } # Replace the email that gets modified local $tmpf = $< == 0 ? "$f.del" : $_[0] =~ /^\/.*\/([^\/]+)$/ ? "$user_module_config_directory/$1.del" : "$user_module_config_directory/$_[0].del"; open(SOURCE, $f); open(DEST, ">$tmpf"); while() { if ($lnum < $_[1]->{'line'} || $lnum > $_[1]->{'eline'}) { # before or after the message to change local $w = (print DEST $_); if (!$w) { local $e = "$?"; close(DEST); close(SOURCE); unlink($tmpf); &error("Write to $tmpf failed : $e"); } } elsif ($lnum == $_[1]->{'line'}) { # found start of message to change .. put in the new one close(DEST); local @ost = stat($tmpf); local $nlines = &send_mail($_[2], $tmpf, $_[3], 1); local @nst = stat($tmpf); local $newsize = $nst[7] - $ost[7]; $sizediff = $newsize - $_[1]->{'size'}; $linesdiff = $nlines - ($_[1]->{'eline'} - $_[1]->{'line'} + 1); open(DEST, ">>$tmpf"); } $lnum++; } close(SOURCE); close(DEST) || &error("Write failed : $!"); # Now update the index and delete the temp file if ($itype == 0) { # Update old-style index foreach $i (@index) { if ($i->[1] > $_[1]->{'line'}) { # Shift mails after the modified $i->[0] += $sizediff; $i->[1] += $linesdiff; } } } else { # Update DBM index for($i=0; $i<$index{'mailcount'}; $i++) { local @idx = split(/\0/, $index{$i}); if ($idx[1] > $_[1]->{'line'}) { $idx[0] += $sizediff; $idx[1] += $linesdiff; $index{$i} = join("\0", @idx); } } $index{'lastchange'} = time(); } local @st = stat($f); unlink($f); if ($itype == 0) { open(INDEX, ">$ifile"); print INDEX map { $_->[0]." ".$_->[1]."\n" } @index; close(INDEX); } if ($< == 0) { rename($tmpf, $f); } else { system("cat $tmpf >$f && rm -f $tmpf"); } chown($st[4], $st[5], $f); chmod($st[2], $f); } # send_mail(&mail, [file], [textonly], [nocr], [smtp-server], # [smtp-user], [smtp-pass], [smtp-auth-mode], # [¬ify-flags]) # Send out some email message or append it to a file. # Returns the number of lines written. sub send_mail { return 0 if (&is_readonly_mode()); local (%header, $h); local $lnum = 0; local $sm = $_[4] || $config{'send_mode'}; local $eol = $_[3] || !$sm ? "\n" : "\r\n"; foreach $h (@{$_[0]->{'headers'}}) { $header{lc($h->[0])} = $h->[1]; } local @tm = localtime(time()); push(@{$_[0]->{'headers'}}, [ 'Date', strftime("%a, %d %b %Y %H:%M:%S %Z", @tm) ]) if (!$header{'date'}); local @from = &address_parts($header{'from'}); local $esmtp = $_[8] ? 1 : 0; if ($_[1]) { # Just append the email to a file using mbox format open(MAIL, ">>$_[1]") || &error("Write failed : $!"); $lnum++; print MAIL $_[0]->{'fromline'} ? $_[0]->{'fromline'}."\n" : strftime("From $from[0] %a %b %e %H:%M:%S %Y\n", @tm); } elsif ($sm) { # Connect to SMTP server &open_socket($sm, 25, MAIL); &smtp_command(MAIL); if ($esmtp) { &smtp_command(MAIL, "ehlo ".&get_system_hostname()."\r\n"); } else { &smtp_command(MAIL, "helo ".&get_system_hostname()."\r\n"); } # Get username and password from parameters, or from module config local $user = $_[5] || $userconfig{'smtp_user'} || $config{'smtp_user'}; local $pass = $_[6] || $userconfig{'smtp_pass'} || $config{'smtp_pass'}; local $auth = $_[7] || $userconfig{'smtp_auth'} || $config{'smtp_auth'} || "Cram-MD5"; if ($user) { # Send authentication commands eval "use Authen::SASL"; if ($@) { &error("Perl module Authen::SASL is needed for SMTP authentication"); } my $sasl = Authen::SASL->new('mechanism' => uc($auth), 'callback' => { 'auth' => $user, 'user' => $user, 'pass' => $pass } ); &error("Failed to create Authen::SASL object") if (!$sasl); local $conn = $sasl->client_new("smtp", &get_system_hostname()); local $arv = &smtp_command(MAIL, "auth $auth\r\n", 1); if ($arv =~ /^(334)\s+(.*)/) { # Server says to go ahead $extra = $2; local $initial = $conn->client_start(); local $auth_ok; if ($initial) { local $enc = &encode_base64($initial); $enc =~ s/\r|\n//g; $arv = &smtp_command(MAIL, "$enc\r\n", 1); if ($arv =~ /^(\d+)\s+(.*)/) { if ($1 == 235) { $auth_ok = 1; } else { &error("Unknown SMTP authentication response : $arv"); } } $extra = $2; } while(!$auth_ok) { local $message = &decode_base64($extra); local $return = $conn->client_step($message); local $enc = &encode_base64($return); $enc =~ s/\r|\n//g; $arv = &smtp_command(MAIL, "$enc\r\n", 1); if ($arv =~ /^(\d+)\s+(.*)/) { if ($1 == 235) { $auth_ok = 1; } elsif ($1 == 535) { &error("SMTP authentication failed : $arv"); } $extra = $2; } else { &error("Unknown SMTP authentication response : $arv"); } } } } &smtp_command(MAIL, "mail from: <$from[0]>\r\n"); local $notify = $_[8] ? " NOTIFY=".join(",", @{$_[8]}) : ""; local $u; foreach $u (&address_parts($header{'to'}.",".$header{'cc'}. ",".$header{'bcc'})) { &smtp_command(MAIL, "rcpt to: <$u>$notify\r\n"); } &smtp_command(MAIL, "data\r\n"); } elsif (defined(&send_mail_program)) { # Use specified mail injector local $cmd = &send_mail_program($from[0]); $cmd || &error("No mail program was found on your system!"); open(MAIL, "| $cmd >/dev/null 2>&1"); } elsif ($config{'qmail_dir'}) { # Start qmail-inject open(MAIL, "| $config{'qmail_dir'}/bin/qmail-inject"); } elsif ($config{'postfix_control_command'}) { # Start postfix's sendmail wrapper local $cmd = -x "/usr/lib/sendmail" ? "/usr/lib/sendmail" : &has_command("sendmail"); $cmd || &error($text{'send_ewrapper'}); open(MAIL, "| $cmd -t -f$from[0] >/dev/null 2>&1"); } else { # Start sendmail &has_command($config{'sendmail_path'}) || &error(&text('send_epath', "$config{'sendmail_path'}")); open(MAIL, "| $config{'sendmail_path'} -t -f$from[0] >/dev/null 2>&1"); } local $ctype = "multipart/mixed"; local $msg_id; foreach $h (@{$_[0]->{'headers'}}) { if (defined($_[0]->{'body'}) || $_[2]) { print MAIL $h->[0],": ",$h->[1],$eol; $lnum++; } else { if ($h->[0] !~ /^(MIME-Version|Content-Type)$/i) { print MAIL $h->[0],": ",$h->[1],$eol; $lnum++; } elsif (lc($h->[0]) eq 'content-type') { $ctype = $h->[1]; } } if (lc($h->[0]) eq 'message-id') { $msg_id++; } } if (!$msg_id) { # Add a message-id header if missing print MAIL "Message-Id: <",time().".".$$."\@". &get_system_hostname(),">",$eol; } # Work out first attachment content type local $ftype; if (@{$_[0]->{'attach'}} >= 1) { local $first = $_[0]->{'attach'}->[0]; $ftype = "text/plain"; foreach my $h (@{$first->{'headers'}}) { if (lc($h->[0]) eq "content-type") { $ftype = $h->[1]; } } } if (defined($_[0]->{'body'})) { # Use original mail body print MAIL $eol; $lnum++; $_[0]->{'body'} =~ s/\r//g; $_[0]->{'body'} =~ s/\n\.\n/\n\. \n/g; $_[0]->{'body'} =~ s/\n/$eol/g; $_[0]->{'body'} .= $eol if ($_[0]->{'body'} !~ /\n$/); (print MAIL $_[0]->{'body'}) || &error("Write failed : $!"); $lnum += ($_[0]->{'body'} =~ tr/\n/\n/); } elsif (!$_[2] || $ftype !~ /text\/plain/i) { # Sending MIME-encoded email if ($ctype !~ /multipart\/report/i) { $ctype =~ s/;.*$//; } print MAIL "MIME-Version: 1.0",$eol; local $bound = "bound".time(); print MAIL "Content-Type: $ctype; boundary=\"$bound\"",$eol; print MAIL $eol; $lnum += 3; # Send attachments print MAIL "This is a multi-part message in MIME format.",$eol; $lnum++; foreach $a (@{$_[0]->{'attach'}}) { print MAIL $eol; print MAIL "--",$bound,$eol; $lnum += 2; local $enc; foreach $h (@{$a->{'headers'}}) { print MAIL $h->[0],": ",$h->[1],$eol; $enc = $h->[1] if (lc($h->[0]) eq 'content-transfer-encoding'); $lnum++; } print MAIL $eol; $lnum++; if (lc($enc) eq 'base64') { local $enc = &encode_base64($a->{'data'}); $enc =~ s/\r//g; $enc =~ s/\n/$eol/g; print MAIL $enc; $lnum += ($enc =~ tr/\n/\n/); } else { $a->{'data'} =~ s/\r//g; $a->{'data'} =~ s/\n\.\n/\n\. \n/g; $a->{'data'} =~ s/\n/$eol/g; print MAIL $a->{'data'}; $lnum += ($a->{'data'} =~ tr/\n/\n/); if ($a->{'data'} !~ /\n$/) { print MAIL $eol; $lnum++; } } } print MAIL $eol; (print MAIL "--",$bound,"--",$eol) || &error("Write failed : $!"); print MAIL $eol; $lnum += 3; } else { # Sending text-only mail from first attachment local $a = $_[0]->{'attach'}->[0]; print MAIL $eol; $lnum++; $a->{'data'} =~ s/\r//g; $a->{'data'} =~ s/\n/$eol/g; (print MAIL $a->{'data'}) || &error("Write failed : $!"); $lnum += ($a->{'data'} =~ tr/\n/\n/); if ($a->{'data'} !~ /\n$/) { print MAIL $eol; $lnum++; } } if ($sm && !$_[1]) { &smtp_command(MAIL, ".$eol"); &smtp_command(MAIL, "quit$eol"); } if (!close(MAIL)) { # Only bother to report an error on close if writing to a file if ($_[1]) { &error("Write failed : $!"); } } return $lnum; } # mail_size(&mail, [textonly]) # Returns the size of an email message in bytes sub mail_size { local ($mail, $textonly) = @_; local $temp = &transname(); &send_mail($mail, $temp, $textonly); local @st = stat($temp); unlink($temp); return $st[7]; } # b64decode(string) # Converts a string from base64 format to normal sub b64decode { local($str) = $_[0]; local($res); $str =~ tr|A-Za-z0-9+=/||cd; $str =~ s/=+$//; $str =~ tr|A-Za-z0-9+/| -_|; while ($str =~ /(.{1,60})/gs) { my $len = chr(32 + length($1)*3/4); $res .= unpack("u", $len . $1 ); } return $res; } # can_read_mail(user) sub can_read_mail { return 1 if ($_[0] && $access{'sent'} eq $_[0]); local @u = getpwnam($_[0]); return 0 if (!@u); return 0 if ($_[0] =~ /\.\./); return 0 if ($access{'mmode'} == 0); return 1 if ($access{'mmode'} == 1); local $u; if ($access{'mmode'} == 2) { foreach $u (split(/\s+/, $access{'musers'})) { return 1 if ($u eq $_[0]); } return 0; } elsif ($access{'mmode'} == 4) { return 1 if ($_[0] eq $remote_user); } elsif ($access{'mmode'} == 5) { return $u[3] eq $access{'musers'}; } elsif ($access{'mmode'} == 3) { foreach $u (split(/\s+/, $access{'musers'})) { return 0 if ($u eq $_[0]); } return 1; } elsif ($access{'mmode'} == 6) { return ($_[0] =~ /^$access{'musers'}$/); } elsif ($access{'mmode'} == 7) { return (!$access{'musers'} || $u[2] >= $access{'musers'}) && (!$access{'musers2'} || $u[2] <= $access{'musers2'}); } return 0; # can't happen! } # from_hostname() sub from_hostname { local ($d, $masq); local $conf = &get_sendmailcf(); foreach $d (&find_type("D", $conf)) { if ($d->{'value'} =~ /^M\s*(\S*)/) { $masq = $1; } } return $masq ? $masq : &get_system_hostname(); } # mail_from_queue(qfile, [dfile|"auto"]) # Reads a message from the Sendmail mail queue sub mail_from_queue { local $mail = { 'file' => $_[0] }; $mail->{'quar'} = $_[0] =~ /\/hf/; $mail->{'lost'} = $_[0] =~ /\/Qf/; if ($_[1] eq "auto") { $mail->{'dfile'} = $_[0]; $mail->{'dfile'} =~ s/\/(qf|hf|Qf)/\/df/; } elsif ($_[1]) { $mail->{'dfile'} = $_[1]; } $mail->{'lfile'} = $_[0]; $mail->{'lfile'} =~ s/\/(qf|hf|Qf)/\/xf/; local $_; local @headers; open(QF, $_[0]) || return undef; while() { s/\r|\n//g; if (/^M(.*)/) { $mail->{'status'} = $1; } elsif (/^H\?[^\?]*\?(\S+):\s+(.*)/ || /^H(\S+):\s+(.*)/) { push(@headers, [ $1, $2 ]); $mail->{'rawheaders'} .= "$1: $2\n"; } elsif (/^\s+(.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); $mail->{'rawheaders'} .= $_."\n"; } } close(QF); $mail->{'headers'} = \@headers; foreach $h (@headers) { $mail->{'header'}->{lc($h->[0])} = $h->[1]; } if ($mail->{'dfile'}) { # Read the mail body open(DF, $mail->{'dfile'}); while() { $mail->{'body'} .= $_; } close(DF); } local $datafile = $mail->{'dfile'}; if (!$datafile) { ($datafile = $mail->{'file'}) =~ s/\/(qf|hf|Qf)/\/df/; } local @st0 = stat($mail->{'file'}); local @st1 = stat($datafile); $mail->{'size'} = $st0[7] + $st1[7]; return $mail; } # wrap_lines(text, width) # Given a multi-line string, return an array of lines wrapped to # the given width sub wrap_lines { local @rv; local $w = $_[1]; foreach $rest (split(/\n/, $_[0])) { if ($rest =~ /\S/) { while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) { push(@rv, $1); $rest = $2; } } else { # Empty line .. keep as it is push(@rv, $rest); } } return @rv; } # smtp_command(handle, command, no-error) sub smtp_command { local ($m, $c) = @_; print $m $c; local $r = <$m>; if ($r !~ /^[23]\d+/ && !$_[2]) { &error(&text('send_esmtp', "".&html_escape($c)."", "".&html_escape($r)."")); } $r =~ s/\r|\n//g; if ($r =~ /^(\d+)\-/) { # multi-line ESMTP response! while(1) { local $nr = <$m>; $nr =~ s/\r|\n//g; if ($nr =~ /^(\d+)\-(.*)/) { $r .= "\n".$2; } elsif ($nr =~ /^(\d+)\s+(.*)/) { $r .= "\n".$2; last; } } } return $r; } # address_parts(string) # Returns the email addresses in a string sub address_parts { local @rv; local $rest = $_[0]; while($rest =~ /([^<>\s,'"\@]+\@[A-z0-9\-\.\!]+)(.*)/) { push(@rv, $1); $rest = $2; } return wantarray ? @rv : $rv[0]; } # link_urls(text, separate) sub link_urls { local $r = $_[0]; local $tar = $_[1] ? "target=link".int(rand()*100000) : ""; $r =~ s/((http|ftp|https|mailto):[^><"'\s]+[^><"'\s\.\)])/$1<\/a>/g; return $r; } # link_urls_and_escape(text, separate) # HTML escapes some text, as well as properly linking URLs in it sub link_urls_and_escape { local $l = $_[0]; local $rv; local $tar = $_[1] ? " target=link".int(rand()*100000) : ""; while($l =~ /^(.*?)((http|ftp|https|mailto):[^><"'\s]+[^><"'\s\.\)])(.*)/) { local ($before, $url, $after) = ($1, $2, $4); $rv .= &eucconv_and_escape($before)."". &html_escape($url).""; $l = $after; } $rv .= &eucconv_and_escape($l); return $rv; } # uudecode(text) sub uudecode { local @lines = split(/\n/, $_[0]); local ($l, $data); for($l=0; $lines[$l] !~ /begin\s+([0-7]+)\s/i; $l++) { } while($lines[++$l]) { $data .= unpack("u", $lines[$l]); } return $data; } sub simplify_date { local $u = &parse_mail_date($_[0]); if ($u) { local $fmt = $userconfig{'date_fmt'} || $config{'date_fmt'} || "dmy"; local $strf = $fmt eq "dmy" ? "%d/%m/%Y" : $fmt eq "mdy" ? "%m/%d/%Y" : "%Y/%m/%d"; local $ENV{'TZ'} = $userconfig{'date_tz'} || $config{'date_tz'} || $ENV{'TZ'}; delete($ENV{'TZ'}) if (!$ENV{'TZ'}); return strftime("$strf %H:%M", localtime($u)); } elsif ($_[0] =~ /^(\S+),\s+0*(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+)/) { return "$2/$3/$4 $5:$6"; } elsif ($_[0] =~ /^0*(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+)/) { return "$1/$2/$3 $4:$5"; } return $_[0]; } # simplify_from(from) # Simplifies a From: address for display in the mail list. Only the first # address is returned. sub simplify_from { local $rv = &eucconv(&decode_mimewords($_[0])); local @sp = &split_addresses($rv); if (!@sp) { return $text{'mail_nonefrom'}; } else { local $first = &html_escape($sp[0]->[1] ? $sp[0]->[1] : $sp[0]->[2]); if (length($first) > 80) { return substr($first, 0, 80)." .."; } else { return $first.(@sp > 1 ? " , ..." : ""); } } } # simplify_subject(subject) sub simplify_subject { local $rv = &eucconv(&decode_mimewords($_[0])); $rv = substr($rv, 0, 80)." .." if (length($rv) > 80); return $rv =~ /\S/ ? &html_escape($rv) : "
"; } # quoted_decode(text) sub quoted_decode { local $t = $_[0]; $t =~ s/=\n//g; $t =~ s/=([a-zA-Z0-9]{2})/pack("c",hex($1))/ge; return $t; } # quoted_encode(text) sub quoted_encode { local $t = $_[0]; $t =~ s/([=\177-\377])/sprintf("=%2.2X",ord($1))/ge; return $t; } sub decode_mimewords { my $encstr = shift; my %params = @_; my @tokens; $@ = ''; ### error-return ### Collapse boundaries between adjacent encoded words: $encstr =~ s{(\?\=)\r?\n[ \t](\=\?)}{$1$2}gs; pos($encstr) = 0; ### print STDOUT "ENC = [", $encstr, "]\n"; ### Decode: my ($charset, $encoding, $enc, $dec); while (1) { last if (pos($encstr) >= length($encstr)); my $pos = pos($encstr); ### save it ### Case 1: are we looking at "=?..?..?="? if ($encstr =~ m{\G # from where we left off.. =\?([^?]*) # "=?" + charset + \?([bq]) # "?" + encoding + \?([^?]+) # "?" + data maybe with spcs + \?= # "?=" }xgi) { ($charset, $encoding, $enc) = ($1, lc($2), $3); $dec = (($encoding eq 'q') ? _decode_Q($enc) : _decode_B($enc)); push @tokens, [$dec, $charset]; next; } ### Case 2: are we looking at a bad "=?..." prefix? ### We need this to detect problems for case 3, which stops at "=?": pos($encstr) = $pos; # reset the pointer. if ($encstr =~ m{\G=\?}xg) { $@ .= qq|unterminated "=?..?..?=" in "$encstr" (pos $pos)\n|; push @tokens, ['=?']; next; } ### Case 3: are we looking at ordinary text? pos($encstr) = $pos; # reset the pointer. if ($encstr =~ m{\G # from where we left off... ([\x00-\xFF]*? # shortest possible string, \n*) # followed by 0 or more NLs, (?=(\Z|=\?)) # terminated by "=?" or EOS }xg) { length($1) or die "MIME::Words: internal logic err: empty token\n"; push @tokens, [$1]; next; } ### Case 4: bug! die "MIME::Words: unexpected case:\n($encstr) pos $pos\n\t". "Please alert developer.\n"; } return join('',map {$_->[0]} @tokens); } # _decode_Q STRING # Private: used by _decode_header() to decode "Q" encoding, which is # almost, but not exactly, quoted-printable. :-P sub _decode_Q { my $str = shift; $str =~ s/_/\x20/g; # RFC-1522, Q rule 2 $str =~ s/=([\da-fA-F]{2})/pack("C", hex($1))/ge; # RFC-1522, Q rule 1 $str; } # _decode_B STRING # Private: used by _decode_header() to decode "B" encoding. sub _decode_B { my $str = shift; &decode_base64($str); } # user_mail_file(user|file, [other details]) sub user_mail_file { if ($_[0] =~ /^\//) { return $_[0]; } elsif ($config{'mail_dir'}) { return &mail_file_style($_[0], $config{'mail_dir'}, $config{'mail_style'}); } elsif (@_ > 1) { return "$_[7]/$config{'mail_file'}"; } else { local @u = getpwnam($_[0]); return "$u[7]/$config{'mail_file'}"; } } # mail_file_style(user, basedir, style) sub mail_file_style { if ($_[2] == 0) { return "$_[1]/$_[0]"; } elsif ($_[2] == 1) { return $_[1]."/".substr($_[0], 0, 1)."/".$_[0]; } elsif ($_[2] == 2) { return $_[1]."/".substr($_[0], 0, 1)."/". substr($_[0], 0, 2)."/".$_[0]; } else { return $_[1]."/".substr($_[0], 0, 1)."/". substr($_[0], 1, 1)."/".$_[0]; } } # user_index_file(user|file) sub user_index_file { local $us = $_[0]; $us =~ s/\//_/g; local $f; local $hn = &get_system_hostname(); if ($_[0] =~ /^\/.*\/([^\/]+)$/) { # A file .. the index file is in ~/.usermin/mailbox or # /etc/webmin/mailboxes if ($user_module_config_directory && $config{'shortindex'}) { # Use short name for index file $f = "$user_module_config_directory/$1.findex"; } else { $f = $user_module_config_directory ? "$user_module_config_directory/$us.findex" : "$module_config_directory/$us.findex"; } } else { # A username .. the index file is in /etc/webmin/mailboxes $f = $user_module_config_directory ? "$user_module_config_directory/$_[0].index" : "$module_config_directory/$_[0].index"; } return -r $f && !-r "$f.$hn" ? $f : "$f.$hn"; } # extract_mail(data) # Converts the text of a message into mail object. sub extract_mail { local $text = $_[0]; $text =~ s/^\s+//; local ($amail, @aheaders, $i); local @alines = split(/\n/, $text); while($i < @alines && $alines[$i]) { if ($alines[$i] =~ /^(\S+):\s*(.*)/) { push(@aheaders, [ $1, $2 ]); $amail->{'rawheaders'} .= $alines[$i]."\n"; } elsif ($alines[$i] =~ /^\s+(.*)/) { $aheaders[$#aheaders]->[1] .= $1 unless($#aheaders < 0); $amail->{'rawheaders'} .= $alines[$i]."\n"; } $i++; } $amail->{'headers'} = \@aheaders; foreach $h (@aheaders) { $amail->{'header'}->{lc($h->[0])} = $h->[1]; } splice(@alines, 0, $i); $amail->{'body'} = join("\n", @alines)."\n"; return $amail; } # split_addresses(string) # Splits a comma-separated list of addresses into [ email, real-name, original ] # triplets sub split_addresses { local (@rv, $str = $_[0]); while(1) { if ($str =~ /^[\s,]*(([^<>\(\)\s]+)\s+\(([^\(\)]+)\))(.*)$/) { # An address like foo@bar.com (Fooey Bar) push(@rv, [ $2, $3, $1 ]); $str = $4; } elsif ($str =~ /^[\s,]*("([^"]+)"\s*<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>]+)\s+<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>]+)<([^\s<>,]+)>)(.*)$/ || $str =~ /^[\s,]*(([^<>\[\]]+)\s+\[mailto:([^\s\[\]]+)\])(.*)$/|| $str =~ /^[\s,]*(()<([^<>,]+)>)(.*)/ || $str =~ /^[\s,]*(()([^\s<>,]+))(.*)/) { # Addresses like "Fooey Bar" # Fooey Bar # Fooey Bar [mailto:foo@bar.com] # # # foo@bar.com push(@rv, [ $3, $2, $1 ]); $str = $4; } else { last; } } return @rv; } $match_ascii = '\x1b\([BHJ]([\t\x20-\x7e]*)'; $match_jis = '\x1b\$[@B](([\x21-\x7e]{2})*)'; sub eucconv { local($_) = @_; if ($current_lang eq 'ja_JP.euc') { s/$match_jis/&j2e($1)/geo; s/$match_ascii/$1/go; } $_; } sub j2e { local($_) = @_; tr/\x21-\x7e/\xa1-\xfe/; $_; } # eucconv_and_escape(string) sub eucconv_and_escape { return &html_escape(&eucconv($_[0])); } # list_maildir(file, [start], [end]) # Returns a subset of mail from a maildir format directory sub list_maildir { local (@rv, $i, $f); local @files = &get_maildir_files($_[0]); local ($start, $end); if (!defined($_[1])) { $start = 0; $end = @files - 1; } elsif ($_[2] < 0) { $start = @files + $_[2] - 1; $end = @files + $_[1] - 1; $start = 0 if ($start < 0); } else { $start = $_[1]; $end = $_[2]; $end = @files-1 if ($end >= @files); } foreach $f (@files) { if ($i < $start || $i > $end) { # Skip files outside requested index range push(@rv, undef); $i++; next; } local $mail = &read_mail_file($f); $mail->{'idx'} = $i++; push(@rv, $mail); } return @rv; } # select_maildir(file, &indexes, headersonly) # Returns a list of messages with the given indexes, from a maildir directory sub select_maildir { local @files = &get_maildir_files($_[0]); local @rv; foreach my $i (@{$_[1]}) { local $mail = &read_mail_file($files[$i], $_[2]); $mail->{'idx'} = $i; push(@rv, $mail); } return @rv; } # Get ordered list of message files (with caching, as this can be slow) # get_maildir_files(directory) sub get_maildir_files { local @st = stat($_[0]); local @files; if (defined($main::list_maildir_cache{$_[0]}) && $main::list_maildir_cache_time{$_[0]} == $st[7]) { # Use the cache @files = @{$main::list_maildir_cache{$_[0]}}; } else { # Really read foreach $d ("$_[0]/cur", "$_[0]/new") { opendir(DIR, $d); while($f = readdir(DIR)) { push(@files, "$d/$f") if ($f !~ /^\./); } closedir(DIR); } @files = sort { $a =~ /([^\/]+)$/; local $an = $1; $b =~ /([^\/]+)$/; local $bn = $1; $an cmp $bn } @files; $main::list_maildir_cache{$_[0]} = \@files; $main::list_maildir_cache_time{$_[0]} = $st[7]; } return @files; } # search_maildir(file, field, what) # Search for messages in a maildir directory, and return the results sub search_maildir { return &advanced_search_maildir($_[0], [ [ $_[1], $_[2] ] ], 1); } # advanced_search_maildir(user|file, &fields, andmode, [&limit]) # Search for messages in a maildir directory, and return the results sub advanced_search_maildir { local @rv; local ($min, $max); if ($_[3] && $_[3]->{'latest'}) { $min = -1; $max = -$_[3]->{'latest'}; } foreach $mail (&list_maildir($_[0], $min, $max)) { push(@rv, $mail) if ($mail && &mail_matches($_[1], $_[2], $mail)); } return @rv; } # delete_maildir(&mail, ...) # Delete messages from a maildir directory sub delete_maildir { local $m; foreach $m (@_) { unlink($m->{'file'}); } } # modify_maildir(&oldmail, &newmail, textonly) # Replaces a message in a maildir directory sub modify_maildir { unlink($_[0]->{'file'}); &send_mail($_[1], $_[0]->{'file'}, $_[2], 1); } # write_maildir(&mail, directory, textonly) # Adds some message in maildir format to a directory sub write_maildir { local $now = time(); local $hn = &get_system_hostname(); local $mf; mkdir($_[1], 0755); mkdir("$_[1]/cur", 0755); do { $mf = "$_[1]/cur/$now.$$.$hn"; $now++; } while(-r $mf); &send_mail($_[0], $mf, $_[2], 1); } # empty_maildir(file) # Delete all messages in an maildir directory sub empty_maildir { local $d; foreach $d ("$_[0]/cur", "$_[0]/new") { local $f; opendir(DIR, $d); while($f = readdir(DIR)) { unlink("$d/$f") if ($f ne '.' && $f ne '..'); } closedir(DIR); } } # count_maildir(dir) # Returns the number of messages in a maildir directory sub count_maildir { local $d; local $count = 0; foreach $d ("$_[0]/cur", "$_[0]/new") { opendir(DIR, $d); local @files = grep { $_ !~ /^\./ } readdir(DIR); $count += scalar(@files); closedir(DIR); } return $count; } # list_mhdir(file, [start], [end]) # Returns a subset of mail from an MH format directory sub list_mhdir { local ($start, $end, $f, $i, @rv); opendir(DIR, $_[0]); local @files = map { "$_[0]/$_" } sort { $a <=> $b } grep { /^\d+$/ } readdir(DIR); closedir(DIR); if (!defined($_[1])) { $start = 0; $end = @files - 1; } elsif ($_[2] < 0) { $start = @files + $_[2] - 1; $end = @files + $_[1] - 1; $start = 0 if ($start < 0); } else { $start = $_[1]; $end = $_[2]; $end = @files-1 if ($end >= @files); } foreach $f (@files) { if ($i < $start || $i > $end) { # Skip files outside requested index range push(@rv, undef); $i++; next; } local $mail = &read_mail_file($f); $mail->{'idx'} = $i++; push(@rv, $mail); } return @rv; } # select_mhdir(file, &indexes, headersonly) # Returns a list of messages with the given indexes, from an mhdir directory sub select_mhdir { local @rv; opendir(DIR, $_[0]); local @files = map { "$_[0]/$_" } sort { $a <=> $b } grep { /^\d+$/ } readdir(DIR); closedir(DIR); foreach my $i (@{$_[1]}) { local $mail = &read_mail_file($files[$i], $_[2]); $mail->{'idx'} = $i; push(@rv, $mail); } return @rv; } # search_mhdir(file|user, field, what) # Search for messages in an MH directory, and return the results sub search_mhdir { return &advanced_search_mhdir($_[0], [ [ $_[1], $_[2] ] ], 1); } # advanced_search_mhdir(file|user, &fields, andmode, &limit) # Search for messages in an MH directory, and return the results sub advanced_search_mhdir { local @rv; local ($min, $max); if ($_[3] && $_[3]->{'latest'}) { $min = -1; $max = -$_[3]->{'latest'}; } foreach $mail (&list_mhdir($_[0], $min, $max)) { push(@rv, $mail) if ($mail && &mail_matches($_[1], $_[2], $mail)); } return @rv; } # delete_mhdir(&mail, ...) # Delete messages from an MH directory sub delete_mhdir { local $m; foreach $m (@_) { unlink($m->{'file'}); } } # modify_mhdir(&oldmail, &newmail, textonly) # Replaces a message in a maildir directory sub modify_mhdir { unlink($_[0]->{'file'}); &send_mail($_[1], $_[0]->{'file'}, $_[2], 1); } # max_mhdir(dir) # Returns the maximum message ID in the directory sub max_mhdir { local $max = 1; opendir(DIR, $_[0]); foreach $f (readdir(DIR)) { $max = $f if ($f =~ /^\d+$/ && $f > $max); } closedir(DIR); return $max; } # empty_mhdir(file) # Delete all messages in an MH format directory sub empty_mhdir { local $f; opendir(DIR, $_[0]); foreach $f (readdir(DIR)) { unlink("$_[0]/$f") if ($f =~ /^\d+$/); } closedir(DIR); } # count_mhdir(file) # Returns the number of messages in an MH directory sub count_mhdir { opendir(DIR, $_[0]); local @files = grep { /^\d+$/ } readdir(DIR); closedir(DIR); return scalar(@files); } # read_mail_file(file, [headersonly]) # Read a single message from a file sub read_mail_file { local (@headers, $mail); # Open and read the mail file open(MAIL, $_[0]) || return undef; $mail = &read_mail_fh(MAIL, 0, $_[1]); $mail->{'file'} = $_[0]; close(MAIL); local @st = stat($_[0]); $mail->{'size'} = $st[7]; return $mail; } # read_mail_fh(handle, [end-mode], [headersonly]) # Reads an email message from the given file handle, either up to end of # the file, or a From line. End mode 0 = EOF, 1 = From without -, # 2 = From possibly with - sub read_mail_fh { local ($fh, $endmode, $headeronly) = @_; local (@headers, $mail); # Read the headers local $lnum = 0; while(1) { $lnum++; local $line = <$fh>; $mail->{'size'} += length($line); $line =~ s/\r|\n//g; last if ($line eq ''); if ($line =~ /^(\S+):\s*(.*)/) { push(@headers, [ $1, $2 ]); $mail->{'rawheaders'} .= $line."\n"; } elsif ($line =~ /^\s+(.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); $mail->{'rawheaders'} .= $line."\n"; } elsif ($line =~ /^From\s+(\S+).*\d+/ && ($1 ne '-' || $endmode == 2)) { $mail->{'fromline'} = $line; } } $mail->{'headers'} = \@headers; foreach $h (@headers) { $mail->{'header'}->{lc($h->[0])} = $h->[1]; } if (!$headersonly) { # Read the mail body if ($endmode == 0) { # Till EOF while(read($fh, $buf, 1024) > 0) { $mail->{'size'} += length($buf); $mail->{'body'} .= $buf; } close(MAIL); } else { # Tell next From line while(1) { $line = <$fh>; last if (!$line || $line =~ /^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $endmode == 2)); $lnum++; $mail->{'size'} += length($line); $mail->{'body'} .= $line; } $mail->{'lines'} = $lnum; } } elsif ($endmode) { # Not reading the body, but we still need to search till the next # From: line in order to get the size while(1) { $line = <$fh>; last if (!$line || $line =~ /^From\s+(\S+).*\d+\r?\n/ && ($1 ne '-' || $endmode == 2)); $mail->{'size'} += length($line); } } return $mail; } # dash_mode(user|file) # Returns 1 if the messages in this folder are separated by lines like # From - instead of the usual From foo@bar.com sub dash_mode { open(DASH, &user_mail_file($_[0])) || return 0; # assume no local $line = ; close(DASH); return $line =~ /^From\s+(\S+).*\d/ && $1 eq '-'; } # mail_matches(&fields, andmode, &mail) # Returns 1 if some message matches a search sub mail_matches { local $count = 0; local $f; foreach $f (@{$_[0]}) { local $field = $f->[0]; local $what = $f->[1]; local $neg = ($field =~ s/^\!//); if ($field eq 'body') { $count++ if (!$neg && $_[2]->{'body'} =~ /\Q$what\E/i || $neg && $_[2]->{'body'} !~ /\Q$what\E/i); } elsif ($field eq 'size') { $count++ if (!$neg && $_[2]->{'size'} > $what || $neg && $_[2]->{'size'} < $what); } elsif ($field eq 'headers') { local $headers = $_[2]->{'rawheaders'} || join("", map { $_->[0].": ".$_->[1]."\n" } @{$_[2]->{'headers'}}); $count++ if (!$neg && $headers =~ /\Q$what\E/i || $neg && $headers !~ /\Q$what\E/i); } elsif ($field eq "status") { $count++ if (!$neg && $_[2]->{$field} =~ /\Q$what\E/i|| $neg && $_[2]->{$field} !~ /\Q$what\E/i); } else { $count++ if (!$neg && $_[2]->{'header'}->{$field} =~ /\Q$what\E/i|| $neg && $_[2]->{'header'}->{$field} !~ /\Q$what\E/i); } return 1 if ($count && !$_[1]); } return $count == @{$_[0]}; } # search_fields(&fields) # Returns an array of headers/fields from a search sub search_fields { local @rv; foreach $f (@{$_[0]}) { $f->[0] =~ /^\!?(.*)$/; push(@rv, $1); } return &unique(@rv); } # parse_delivery_status(text) # Returns the fields from a message/delivery-status attachment sub parse_delivery_status { local @lines = split(/[\r\n]+/, $_[0]); local (%rv, $l); foreach $l (@lines) { if ($l =~ /^(\S+):\s*(.*)/) { $rv{lc($1)} = $2; } } return \%rv; } # parse_mail_date(string) # Converts a mail Date: header into a unix time sub parse_mail_date { open(OLDSTDERR, ">&STDERR"); # suppress STDERR from Time::Local close(STDERR); my $rv = eval { if ($_[0] =~ /^\s*(\S+),\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+):\s?(\d+):\s?(\d+)\s+(\S+)/) { # Format like Mon, 13 Dec 2004 14:40:41 +0100 # or Mon, 13 Dec 2004 14:18:16 GMT # or Tue, 14 Sep 04 02:45:09 GMT local $tm = timegm($7, $6, $5, $2, &month_to_number($3), $4 < 50 ? $4+100 : $4 < 1000 ? $4 : $4-1900); local $tz = $8; if ($tz =~ /^(\-|\+)?\d+$/) { local $tz = int($tz); $tz = $tz/100 if ($tz >= 50 || $tz <= -50); $tm -= $tz*60*60; } return $tm; } elsif ($_[0] =~ /^\s*(\S+),\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+):\s?(\d+):\s?(\d+)/) { # Format like Mon, 13 Dec 2004 14:40:41 # No timezone, so assume local local $tm = timegm($7, $6, $5, $2, &month_to_number($3), $4 < 50 ? $4+100 : $4 < 1000 ? $4 : $4-1900); return $tm; } elsif ($_[0] =~ /^\s*(\S+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/) { # Format like Tue Dec 7 12:58:52 2004 local $tm = timelocal($6, $5, $4, $3, &month_to_number($2), $7 < 50 ? $7+100 : $7 < 1000 ? $7 : $7-1900); return $tm; } elsif ($_[0] =~ /^(\d{4})\-(\d+)\-(\d+)\s+(\d+):(\d+)/) { # Format like 2004-12-07 12:53 local $tm = timelocal(0, $4, $4, $3, $2-1, $1 < 50 ? $1+100 : $1 < 1000 ? $1 : $1-1900); } elsif ($_[0] =~ /^(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\S+)/) { # Format like 30 Jun 2005 21:01:01 -0000 local $tm = timegm($6, $5, $4, $1, &month_to_number($2), $3 < 50 ? $3+100 : $3 < 1000 ? $3 : $3-1900); local $tz = $7; if ($tz =~ /^(\-|\+)?\d+$/) { $tz = int($tz); $tz = $tz/100 if ($tz >= 50 || $tz <= -50); $tm -= $tz*60*60; } return $tm; } else { return undef; } }; open(STDERR, ">&OLDSTDERR"); close(OLDSTDERR); if ($@) { return undef; } return $rv; } 1; mailboxes/images/0040775000567100000120000000000010026752414013775 5ustar jcameronwheelmailboxes/images/icon.gif0100644000567100000120000000055710014606572015416 0ustar jcameronwheelGIF89a00fff!Made with GIMP!,00I8ͻ`(di@A.8][7ϭ+PĢhJ.ǏIevlz[IKV'zn't>euh^bz}8vUOKE_Cd2Yqņ^1̶վc8\:^OmCXC*.(3jܨQǏ CI ;mailboxes/images/smallicon.gif0100664000567100000120000000027610411704666016453 0ustar jcameronwheelGIF87a@,sI8ͩBW}^ؑ+tmɻ${g 0~@@("L"@pB;B%XbQ\x_8-b]Lns?ONlwuh]V vv;mailboxes/images/attach.gif0100644000567100000120000000011510026752414015720 0ustar jcameronwheelGIF89a +!, D zK4˪I1Չ '$&hg;mailboxes/images/boxes.gif0100644000567100000120000000055710026752414015606 0ustar jcameronwheelGIF89a00fff!Made with GIMP!,00I8ͻ`(di@A.8][7ϭ+PĢhJ.ǏIevlz[IKV'zn't>euh^bz}8vUOKE_Cd2Yqņ^1̶վc8\:^OmCXC*.(3jܨQǏ CI ;mailboxes/images/p1.gif0100644000567100000120000000006710026752414015002 0ustar jcameronwheelGIF89a !, Lf[ӵn;mailboxes/images/p2.gif0100664000567100000120000000006710026752414015005 0ustar jcameronwheelGIF89a !, Lf[ӵn;mailboxes/images/read.gif0100664000567100000120000000007710026752414015400 0ustar jcameronwheelGIF89a !,  މ7qsA;mailboxes/images/special.gif0100664000567100000120000000007610026752414016104 0ustar jcameronwheelGIF89a !, NTҦ.5=,;mailboxes/images/error.gif0100644000567100000120000000071110026752207015607 0ustar jcameronwheelGIF89a00fff!,00I8SÍIZIN,,4ho;P/UİZcr53ωtUos-/gy=EX[sT%lÓU>e}ry]Qq\k_Z@c,wqH}HZIjOklȱΝS̵χۮ޿eȯ✾k~% `"؅qB f|Ϣǁwy>FH#y#2b8U~d-e '͏er9F_H7qiCEqb=6eSU 4ٳh#> heD&n+y &̊tڝH+} /;mailboxes/lang/0040775000567100000120000000000010443355731013455 5ustar jcameronwheelmailboxes/lang/de0100664000567100000120000003677210354756772014017 0ustar jcameronwheelacl_all=Alle acl_any=Jede Adresse acl_apath=Beschränke Dateien und Programme auf Verzeichnis acl_asame=Verwende Benutzernamen acl_attach=Maximale Gesamtdateianhanggröße acl_canattach=Darf Dateien vom Serverdateisystem anhängen? acl_candetach=Darf Dateianhänge im Serverdateisystem speichern? acl_dir=Darf E-Mail-Dateien lesen in Verzeichnis acl_dirauto=Entscheide automatisch (überall, wenn alle Benutzer sichtbar sind, ansonsten nirgends) acl_faddrs=Aufgeführte Adressen acl_fdom=Jede Adresse @ Domain acl_fdoms=Mailbox @ Domains acl_from=Adressen, die für Absenderadressen (FROM) erlaubt sind acl_fromname=Realname für die Absenderadresse (FROM) acl_none=Kein acl_read=Benutzer, deren Post gelesen werden kann acl_same=Benutzer mit dem gleichen Namen acl_sec=Sekundäre Gruppen einbeziehen? acl_sent=Speichere versendete E-Mail in E-Mailbox acl_users=Nur diese Benutzer acl_userse=Alle, außer diese Benutzer acl_usersg=Mitglieder der Gruppen acl_usersm=Benutzer passend zu/auf acl_usersu=Mit UID im Bereich black_already=Die E-Mail-Adresse $1 befindet sich bereits auf der Liste der durch SpamAssassin abgewiesenen Adressen black_done=Die E-Mail-Adresse wurde der Liste der durch SpamAssassin abgewiesenen Adressen hinzugefügt. black_title=Absender verbieten compose_title=Schreibe E-Mail confirm_ok=Lösche jetzt confirm_title=Löschen bestätigen confirm_warn=Sind Sie sicher, daß Sie die ausgewählten $1 E-Mails löschen wollen? confirm_warn2=Aufgrund der Größe und des Formates Ihrer E-Mailbox wird dies ein wenig dauern. Während des Löschvorganges sollten keine anderen Aktionen stattfinden. Bitte ein wenig Geduld ... confirm_warn3=Sind Sie sicher, daß Sie diese E-Mail löschen wollen? confirm_warn4=Während des Löschvorganges sollten keine anderen Aktionen stattfinden. Bitte ein wenig Geduld ... confirm_warnall=Sind Sie sicher, daß Sie alle E-Mails in diesem Ordner löschen wollen? delete_ebnone=Es wurde keine E-Mail zum Ablehnen ausgewählt delete_ecannot=Sie dürfen keine E-Mails von diesem Benutzer löschen delete_ecopycannot=Sie dürfen keine E-Mails zu dem ausgewählten Benutzer kopieren delete_ecopynone=Es wurde keine E-Mail für den Kopiervorgang ausgewählt. delete_ecopyuser=Der Benutzer, zu dem Sie E-Mails kopieren wollen, existiert nicht delete_efnone=Es wurde keine E-Mail für den Weiterleitungsvorgang ausgewählt. delete_ehnone=Keine E-Mail wurde für den Report als Nicht-Spam ausgewählt delete_emnone=Es wurde keine E-Mail für den Markierungsvorgang ausgewählt. delete_emovecannot=Sie dürfen keine E-Mails zu dem ausgewählten Benutzer verschieben delete_emovenone=Es wurde keine E-Mail für den Verschiebevorgang ausgewählt. delete_emoveuser=Der Benutzer, zu dem Sie E-Mails verschieben wollen, existiert nicht delete_enone=Es wurde keine E-Mail für den Löschvorgang ausgewählt. delete_ereport=Konnte nicht als Spam melden : $1 delete_ernone=Es wurde keine E-Mail für den Spam-Report ausgewählt delete_errc=Konte E-Mail nicht kopieren delete_errm=Konnte E-Mail nicht verschieben delete_ewnone=Keine E-Mail wurde für die Whitelist ausgewählt delete_nobutton=Es wurde kein Button angeklickt delete_ok=Jetzt löschen delete_rusure=Sind Sie sicher, daß Sie die ausgewählten $1 E-Mails aus/von $2 löschen wollen? Aufgrund der Größe und des Formates dieser E-Mailbox wird dies ein wenig dauern. Während des Löschvorganges sollten keine anderen Aktionen stattfinden. Bitte ein wenig Geduld ... delete_rusure2=Sind Sie sicher, daß Sie diese E-Mail aus/von $1 löschen wollen? Aufgrund der Größe und des Formates dieser E-Mailbox wird dies ein wenig dauern. Während des Löschvorganges sollten keine anderen Aktionen stattfinden. Bitte ein wenig Geduld ... delete_title=E-Mail löschen detach_edir=Es wurden weder Datei noch ein Verzeichnis für den Speichervorgang ausgewählt. detach_eopen=Fehler beim Öffnen von $1 : $2 detach_err=Konnte Datei nicht abhängen/löschen detach_ewrite=Fehler beim Schreibvorgang zu $1 : $2 detach_ok=Der Dateianhang wurde auf dem Server in die folgende Datei gespeichert $1 ($2). detach_title=Dateianhang speichern emodified=Dieser Order wurde seit dem aktuellen Einlesen verändert! Kehren Sie zur Liste der E-Mails zurück und starten Sie erneut. enew_title=E-Mail bearbeiten find_enone=Es wurden keine Benutzer gefunden, die der Suchanfrage entsprechen find_group=Gruppe find_home=Heimatverzeichnis find_real=Realname find_results=Benutzer, die auf das Suchmuster $1 passen ... find_size=E-Mail-Größe find_title=Suchergebnisse find_user=Benutzername folder_drafts=Entwürfe folder_inbox=Posteingang folder_sent=Versendete E-Mail folder_trash=Papierkorb forward_title=E-Mail weiterleiten ham_report=Diese Nachricht wird als Nicht-Spam an Razor und andere SpamAssassin-Datenbanken gemeldet .. ham_title=Als Nicht-Spam melden index_contains=beinhaltet index_empty=Keine E-Mail index_eperl=Das Perl-Modul $1, welches für den ausgewählten SMTP-Authentisierungsmodus nötig ist, ist nicht installiert oder es fehlt ein zur Ausführung abhängiges Modul. Klicken Sie hier um dieses zu installieren. index_equals=ist gleich index_esystem=Keiner der unterstützten E-Mailserver (Qmail, Postfix und Sendmail) wurde auf Ihrem System gefunden. Sie müssen die Modulkonfiguration manuell anpassen und dort den E-Mailserver und die zugehörigen Serverpfade eintragen. index_esystem2=Der in der Modulkonfiguration gesetzte E-Mailserver wurde auf ihrem System nicht gefunden. Sie müssen dort die Konfiguration so anpassen, daß der richtige E-Mailserver benutzt wird. index_file=Lese E-Mail in Datei: index_find=Finde Benutzer deren Benutzername index_header=Benutzer-E-Mailboxen index_none=Sie dürfen die E-Mails der Benutzer auf diesem System nicht lesen. index_return=Benutzerliste index_system0=E-Mailserver: Postfix index_system1=E-Mailserver: Sendmail index_system2=E-Mailserver: Qmail index_title=Lese Benutzer-E-Mail index_toomany=Es gibt mehr Benutzer auf Ihrem System, als hier angezeigt werden können. ldap_econn=Fehler beim Verbinden zum LDAP-Server $1 Port $2 ldap_elogin=Konnte nicht zum LDAP-Server $1 als $2 verbinden : $3 ldap_emod=Das fehlende Perl-Modul $1 wird benötigt, um sich via LDAP zu verbinden log_copymail=Es wurden $1 E-Mails von $2 nach $3 kopiert log_delmail=Es wurden $1 E-Mails von $2 gelöscht log_movemail=Es wurden $1 E-Mails von $2 nach $3 kopiert log_read=Lese E-Mail für $1 log_send=Es wurde eine E-Mail nach $1 versandt. mail_addresses=Adressbuch bearbeiten mail_advanced=Erweiterte Suche mail_all=Alle auswählen mail_bcc=Bcc mail_black=Absender blockieren mail_body=Textkörper mail_cc=Cc mail_compose=Schreiben mail_copy=Kopieren nach: mail_crypt=GnuPG-Verschlüsselung für: mail_date=Datum mail_delall=Alle löschen mail_delete=Löschen mail_deleteall=Alles löschen mail_deltrash=Papierkorb leeren mail_ecannot=Sie dürfen die E-Mails von diesem Benutzer nicht lesen mail_eexists=Die E-Mail existiert nicht mehr. Eventuell wurde Sie in der Zwischenzeit via POP3 abgerufen oder anderweitig von einem berechtigtem Benutzer gelöscht/verschoben. mail_efile=Die E-Mail-Datei existiert nicht mail_err=Beim Auflisten der E-Mails in diesem Ordner ist ein Fehler aufgetreten : $1 mail_fchange=Ändern mail_folder=Ordner mail_folders=Ordner bearbeiten mail_for=In $1 mail_for2=Für Benutzer $1 mail_forward=Weiterleiten mail_from=Von mail_fromsrch=Gleicher Absender .. mail_high=Hoch mail_highest=Höchste mail_indexlink=Zurück zur E-Mailbox mail_invert=Auswahl umkehren mail_jump=Springe zu Seite : mail_login=Login mail_logindesc=Sie müssen Benutzername und Passwort eingeben,
um Ihren Posteingang auf dem E-Mailserver $1 einsehen zu können. mail_loginheader=POP3-Server-Login mail_loginmailbox=IMAP E-Mailbox mail_loginpass=Passwort mail_loginuser=Benutzername mail_logout=Ändere POP3-Login mail_logout2=Ändere IMAP-Login mail_low=Niedrig mail_lowest=Niedrigste mail_mark=Markiere als: mail_mark0=Ungelesen mail_mark1=Gelesen mail_mark2=Spezial mail_match=passt auf mail_move=Verschieben nach: mail_nocrypt=<Nicht verschlüsseln> mail_none=Dieser Benutzer hat keine E-Mails in $1 mail_nonefrom=Kein mail_normal=Normal mail_nosign=<Nicht signieren> mail_of=von mail_ok=Suche mail_pos=E-Mails $1 bis $2 von $3 in $4 mail_pri=Priorität mail_replyto=Antworten an mail_reset=Löschen mail_return=Benutzer-E-Mailbox mail_return2=Benutzer-E-Mail mail_rfc=From-Zeile mail_samecrypt=<Schlüssel der Zieladressen> mail_search=Finde E-Mails wo mail_search2=Suche nach: mail_sent=In <Versendete E-Mail<-Liste mail_sig=Bearbeite Signatur mail_sign=Unterschreibe mit GnuPG-Schlüssel mail_size=Größe mail_subject=Betreff mail_subsrch=Gleicher Betreff .. mail_title=Benutzer-E-Mail mail_to=An mail_tosrch=Gleicher Empfänger .. mail_white=Erlaube Absender razor_deleted=.. erledigt. Die E-Mail wurde gelöscht. razor_done=.. erledigt razor_err=.. gescheitert! Oben sehen Sie warum. razor_report=Diese Nachricht wird sowohl der Razor- als auch anderen durch SpamAssassin genutzten Anti-Spam-Datenbanken gemeldet. razor_title=Als Spam melden reply_attach=Weitergeleitete Anhänge reply_attach2=Client- und serverseitige Anhänge reply_body=E-Mail-Text reply_draft=Speichern als Entwurf reply_ecannot=Sie dürfen keine E-Mails im Namen dieses Benutzers versenden reply_errc=Konnte E-Mail nicht kopieren reply_errm=Konnte E-Mail nicht verschieben reply_headers=E-Mail-Header reply_mailforward=Weitergeleitete E-Mails reply_send=E-Mail versenden reply_spell=Auf Rechtschreibfehler prüfen? reply_title=Auf E-Mail antworten search_all=In allen Ordnern search_allstatus=Jede search_ecannot=Sie dürfen die E-Mail dieses Benutzers nicht durchsuchen search_efield=Sie müssen eine Such-/Abfrageart angeben. search_elatest=Fehlende oder ungültige Anzahl an E-Mails für die Suche search_ematch=Sie müssen einen Text für die Suche/Abfrage angeben. search_enone=Sie haben keinerlei Suchkriterien angegeben search_ewhat=Sie haben keinen Text für die Suche/Abfrage der Spalte $1 angeben. search_latest=Zu durchsuchende E-Mails search_latestnum=Nur die neuesten search_limit=(der letzten $1 E-Mails) search_local=In lokalen Ordnern search_nolatest=Alle im Ordner search_none=Es wurden keine E-Mails gefunden. search_onestatus=Nur Status search_results2=$1 E-Mails passen auf $2 search_results3=$1 E-Mails passen nicht auf $2 search_results4=$1 E-Mails passen auf Ihre Suchanfrage search_status=Mit Status search_title=Suchergebnisse search_withstatus=, mit Status $1 send_draft=Die E-Mail an $1 wurde als Entwurf gespeichert. send_eattach=Die Dateianhänge dürfen zusammen nicht mehr als $1 KiB groß sein. send_eattachsize=Die Dateianhänge überschreiten die maximal erlaubte Größe von $1 bytes. send_ecannot=Sie dürfen im Namen dieses Benutzers keine E-Mail versenden send_ecrypt=Konnte E-Mail nicht verschlüsseln : $1 send_efile=Konnte Dateianhänge nicht lesen $1 : $2 send_efrom=Fehlende Absenderadresse (FROM) send_ekey=Konnte den Schlüssel für die E-Mail-Adresse $1 nicht finden send_eline=In Zeile $1: send_epass=Sie können diese E-Mail nicht signieren, da Sie noch keine Passphrase im GnuPG-Modul hinterlegt haben. send_epath=Das Sendmail-Binary $1 existiert nicht. send_eperms=Benutzer $1 kann $2 nicht lesen send_eperms2=Sie dürfen die Datei $1 nicht versenden send_err=Konnte E-Mail nicht versenden send_esign=Konnte E-Mail nicht signieren : $1 send_esmtp=SMTP-Kommando $1 gescheitert : $2 send_espell=Die folgenden Rechtschreibefehler wurden in Ihrer E-Mail gefunden .. send_eto=Fehlende Empfängeradresse (TO) send_eword=Falsch geschriebenes Wort $1 send_eword2=Falsch geschriebenes Wort $1 - Mögliche Korrektur $2 send_ok=E-Mail erfolgreich versandt an $1 send_title=E-Mail versandt sform_all=<Alle Ordner> sform_and=Finde E-Mails bei denen folgende Kriterien zutreffen ... sform_body=E-Mail-Textkörper sform_cc=Cc:-Zeile sform_date=Datum:-Zeile sform_folder=in Ordner(n) sform_from=From:-Zeile sform_headers=Jegliche Header-Zeile sform_local=<Lokale Ordner> sform_neg0=beinhaltet sform_neg1=beinhaltet nicht sform_ok=Jetzt suchen sform_or=Finde E-Mails, wo irgendeine der folgenden Kritierien zutreffen .. sform_return=Erweitertes Suchformular sform_size=Nachrichtengröße sform_subject=Betreff:-Zeile sform_text=den Text sform_title=Erweiterte Suche sform_to=To:-Zeile sform_where=Wo view_allheaders=Zeige alle E-Mail-Header an view_ashtml=Zeige E-Mail als HTML an (Kann gefährlich sein!) view_astext=Zeige E-Mail als Text an (Explizit empfohlen) view_attach=Dateianhänge view_black=Diesen Absender in die Blacklist aufnehmen! view_body=E-Mail-Text view_crypt=GnuPG-E-Mail-Entschlüsselung view_crypt_1=Diese E-Mail ist verschlüsselt, jedoch wurde GnuPG nicht gefunden oder es ist nicht richtig installiert. view_crypt_2=Konnte E-Mail nicht entschlüsseln : $1 view_crypt_3=E-Mail erfolgreich entschlüsselt. view_crypt_4=Der verschlüsselte Anteil dieser E-Mail wurde erfolgreich entschlüsselt. view_dall=<Alle Dateien> view_delete=Löschen view_desc=E-Mail $1 in $2 view_desc2=E-Mail $1 des Benutzers $2 view_desc3=E-Mails $1 view_detach=Dateianhang speichern: view_diagnostic-code=Grund des Fehlers view_dir= in eine Serverdatei oder -Verzeichnis: view_dstatus=Status des gescheiterten Versands view_dstatusok=Erfolgreicher Übertragungsstatus view_ecannot=Sie dürfen die E-Mails dieses Benutzers nicht lesen view_egone=Die E-Mail existiert nicht mehr. Eventuell wurde Sie in der Zwischenzeit via POP3 abgerufen oder anderweitig von einem berechtigtem Benutzer gelöscht/verschoben. view_enew=Als neu bearbeiten view_final-recipient=Entgültiger Empfänger view_folder=Zurück zur E-Mailbox view_forward=Weiterleiten view_gnupg=GnuPG-Signatur-Überprüfung view_gnupg_0=Die Signatur von $1 ist gültig. view_gnupg_1=Die Signatur von $1 ist gültig, aber es konnte kein Vertrauensstatus erkannt werden. view_gnupg_2=Die Signatur von $1 ist NICHT gültig. view_gnupg_3=Die Schlüssel-ID $1 ist nicht in Ihrer Liste, ergo kann keine GnuPG-Signatur-Überprüfung statfinden. view_gnupg_4=Konnte Signatur nicht überprüfen : $1 view_ham=Als Nicht-Spam melden view_headers=E-Mail-Header view_mark=Markiere als: view_mark0=Ungelesen view_mark1=Gelesen view_mark2=Spezial view_noheaders=Einfache Headeranzeige view_print=Drucken view_qdesc=E-Mail $1 in Warteschlange view_raw=Zeige Nachricht im Rohformat an view_razor=Als Spam melden view_razordel=Spam-Report und Löschen view_recv=Hole Schlüssel-ID $1 vom Keyserver. view_remote-mta=Entfernter E-Mail-Server view_reply=Anworten view_reply2=Allen antworten view_reporting-mta=Berichtender E-Mail-Server view_return=Original-E-Mail view_sent=E-Mail $1 in "Versendete E-Mail"-Liste view_strip=Entferne Dateianhänge view_sub=Angehängte E-Mail(s) view_title=E-Mail lesen view_white=Erlaube Absender white_already=Die E-Mail-Adresse $1 befindet sich bereits in der Whitelist von SpamAssassin. white_done=Die E-Mail-Adresse $1 wurde der Whitelist von SpamAssassin hinzugefügt. white_title=Erlaube Absender mailboxes/lang/en0100664000567100000120000003272010435240103013766 0ustar jcameronwheelindex_title=Read User Mail index_none=You are not allowed to read email for any users on this system. index_header=User mailboxes index_empty=No mail index_return=user list index_esystem=None of the supported mail servers (Qmail, Postfix and Sendmail) were detected on your system. You will need to adjust the module configuration to set the mail server and possibly mail paths manually. index_esystem2=The mail server set in the module configuration was not found on your system. You will need to adjust the configuration to use the correct server. index_esystem3=An error occurred contacting the mail system set in the module configuration : $2. index_system2=Mail server: Qmail index_system1=Mail server: Sendmail index_system0=Mail server: Postfix index_toomany=There are too many users on your system to display on one page. index_find=Find users where username index_equals=equals index_contains=contains index_eperl=The Perl module $1 needed for the selected SMTP authentication mode is not installed or is missing a dependent module. Click here to install it now. index_file=Read Mail in File: index_nousers=No users were found! index_nousersmail=No users with email were found. mail_title=User Email mail_from=From mail_date=Date mail_subject=Subject mail_to=To mail_cc=Cc mail_bcc=Bcc mail_pri=Priority mail_highest=Highest mail_high=High mail_normal=Normal mail_low=Low mail_lowest=Lowest mail_for=In $1 mail_for2=For user $1 mail_sent=In sent mail list mail_size=Size mail_level=Score mail_delete=Delete mail_compose=Compose mail_open=Open mail_return=user mailbox mail_pos=Messages $1 to $2 of $3 in $4 mail_none=This user has no messages in $1 mail_ecannot=You are not allowed to read this user's email mail_all=Select all. mail_invert=Invert selection. mail_nosort=Reset sorting. mail_search=Find messages where mail_body=Body mail_match=matches mail_ok=Search mail_nonefrom=None mail_mark=Mark as: mail_mark0=Unread mail_mark1=Read mail_mark2=Special mail_forward=Forward mail_move=Move to: mail_copy=Copy to: mail_rfc=From line mail_eexists=Message no longer exists! mail_fchange=Change mail_indexlink=Return to mailbox mail_deleteall=Delete All mail_black=Deny Senders mail_white=Allow Senders mail_efile=Mail file does not exist mail_fromsrch=Same sender.. mail_subsrch=Same subject.. mail_tosrch=Same recipient.. mail_unknown=Unknown mail_sign=Sign with key: mail_nosign=<Don't sign> mail_crypt=Encrypt for: mail_nocrypt=<Don't encrypt> mail_samecrypt=<Keys from destination addresses> mail_addresses=Manage Address Book mail_folders=Manage Folders mail_err=An error occurred listing mail in this folder : $1 mail_loginheader=POP3 server login mail_logindesc=You must enter a username and password to access mail
in your inbox on the mail server $1. mail_loginuser=Username mail_loginpass=Password mail_loginmailbox=IMAP mailbox mail_login=Login mail_reset=Clear mail_logout=Change POP3 login mail_logout2=Change IMAP login mail_sig=Edit Signature mail_jump=Jump to page : mail_of=of mail_replyto=Reply to mail_folder=Folder mail_delall=Delete All mail_deltrash=Empty Trash mail_search2=Search for: mail_search3=Find with score above: mail_advanced=Advanced Search mail_return2=User Email mail_esystem=An error occurred contacting the mail system : $1. This must be fixied by the system administrator. view_title=Read Email view_desc=Message $1 in $2 view_desc2=Message $1 for user $2 view_desc3=Message $1 view_sent=Message $1 in sent mail list view_qdesc=Queued message $1 view_headers=Mail headers view_body=Message text view_allheaders=View all headers view_noheaders=View basic headers view_attach=Attachments view_reply=Reply view_reply2=Reply to all view_enew=Edit as new view_forward=Forward view_delete=Delete view_print=Print view_strip=Remove Attachments view_ecannot=You are not allowed to read this user's email view_mark=Mark as: view_mark0=Unread view_mark1=Read view_mark2=Special view_return=original email view_sub=Attached Email view_egone=This message no longer exists view_eugone=This user does not exist view_gnupg=GnuPG signature verification view_gnupg_0=Signature by $1 is valid. view_gnupg_1=Signature by $1 is valid, but trust chain could not be established. view_gnupg_2=Signature by $1 is NOT valid. view_gnupg_3=Key ID $1 is not in your list, so signature could not be verified. view_gnupg_4=Failed to verify signature : $1 view_crypt=GnuPG mail decryption view_crypt_1=Message is encrypted, but GnuPG support is not installed. view_crypt_2=Failed to decrypt message : $1 view_crypt_3=Mail was successfully decrypted. view_crypt_4=Encrypted portion of message was successfully decrypted. view_recv=Fetch key ID $1 from keyserver. view_folder=Return to mailbox view_detach=Detach file: view_dall=<All files> view_dir=to server file or directory: view_black=Deny Sender view_white=Allow Sender view_razor=Report As Spam view_ham=Report As Ham view_razordel=Report and Delete view_dstatus=Failed delivery status view_dstatusok=Successful delivery status view_final-recipient=Final recipient view_diagnostic-code=Reason for failure view_remote-mta=Remote mail server view_reporting-mta=Reporting mail server view_astext=View as text view_ashtml=View as HTML view_raw=View raw message compose_title=Compose Email reply_title=Reply to Email forward_title=Forward Email enew_title=Edit Email reply_headers=Mail headers reply_attach=Forwarded attachments reply_mailforward=Forwarded messages reply_attach2=Client and server-side attachments reply_send=Send Mail reply_ecannot=You are not allowed to send mail as this user reply_body=Message text reply_errc=Failed to copy mail reply_errm=Failed to move mail reply_return=compose mail reply_efwdnone=None of the forwarded messages exist reply_spell=Check for spelling errors? reply_draft=Save as Draft send_err=Failed to send mail send_eto=Missing To address send_efrom=Missing From address send_esubject=Missing email subject send_title=Mail Sent send_ok=Mail sent successfully to $1 send_sending=Sending mail to $1 .. send_ecannot=You are not allowed to send mail as this user send_esmtp=SMTP command $1 failed : $2 send_eattach=Attachments cannot total more that $1 kB in size. send_eperms=User $1 cannot read $2 send_eperms2=You are not allowed to send file $1 send_epath=Sendmail executable $1 does not exist. send_efile=Failed to read attachment $1 : $2 send_done=.. done. send_epass=You cannot sign a message because your passphrase has not be setup yet in the GnuPG module. send_esign=Failed to sign message : $1 send_ekey=Couldn't find key for email address $1 send_ecrypt=Failed to encrypt message : $1 send_eword=Misspelt word $1 send_eword2=Misspelt word $1 - possible corrections $2 send_eline=In line $1 : send_espell=The following spelling errors were found in your message .. send_draft=Mail to $1 saved in drafts folder. send_drafting=Saving mail to $1 in drafts folder .. send_eattachsize=The mail attachment exceeded the maximum allowed size of $1 bytes delete_title=Delete Mail delete_rusure=Are you sure you want to delete the $1 selected messages from $2? This may take some time for a large mail file. Until the deletion has finished, no other action should be performed. delete_rusure2=Are you sure you want to delete this message from $1? This may take some time for a large mail file. Until the deletion has finished, no other action should be performed. delete_ok=Delete Now delete_ecannot=You are now allowed to delete mail from this user delete_enone=No mail selected to delete delete_emnone=No mail selected to mark delete_efnone=No mail selected to forward delete_ebnone=No mail selected to deny delete_ewnone=No mail selected to allow delete_ernone=No mail selected to report as spam delete_ehnone=No mail selected to report as ham delete_emoveuser=User to move mail to does not exist delete_ecopyuser=User to copy mail to does not exist delete_emovecannot=You are not allowed to move mail to the specified user delete_ecopycannot=You are not allowed to copy mail to the specified user delete_emovenone=No mail selected to move delete_ecopynone=No mail selected to copy delete_nobutton=No button clicked delete_ereport=Failed to report as spam : $1 delete_errc=Failed to copy mail delete_errm=Failed to move mail confirm_title=Confirm Delete confirm_warn=Are you sure you want to delete the $1 selected messages? confirm_warn2=Because of the size and format of your mailbox, this may take some time. Until the deletion has finished, no other action should be performed. confirm_warn3=Are you sure you want to delete this message? confirm_warn4=Until the deletion has finished, no other action should be performed. confirm_ok=Delete Now confirm_warnall=Are you sure you want to delete all of the messages in this folder? search_title=Search Results search_ecannot=You are not allowed to search this user's email search_ematch=You must enter text to match against. search_escore=Missing or invalid spam score search_efield=You must select a search type. search_ewhat=No text to match against entered for row $1 search_enone=No search criteria entered search_none=No messages found. search_results2=$1 mail messages matching $2 search_results3=$1 mail messages not matching $2 search_results4=$1 mail messages matching your search search_results5=$1 mail messages where $2 matches $3 search_msg2=Search results for $1 search_msg4=Search results search_msg5=Search results for spam with score $1 search_local=In local folders search_all=In all folders search_limit=(from last $1 messages) search_status=With status search_allstatus=Any search_onestatus=Only status search_latest=Messages to search search_nolatest=All in folder search_latestnum=Only latest search_elatest=Missing or invalid number of messages to search search_withstatus=, with status $1 folder_inbox=Inbox folder_sent=Sent mail folder_drafts=Drafts folder_trash=Trash detach_err=Failed to detach file detach_edir=No file or directory to save to entered detach_eopen=Failed to open $1 : $2 detach_ewrite=Failed to write to $1 : $2 detach_title=Detach File detach_ok=Wrote attachment to server-side file $1 ($2). sform_title=Advanced Search sform_and=Find messages matching all criteria below .. sform_or=Find messages matches any criteria below .. sform_neg0=contains sform_neg1=doesn't contain sform_ok=Search Now sform_folder=in folder(s) sform_all=<All folders> sform_local=<Local folders> sform_where=Where sform_text=the text sform_from=From: header sform_subject=Subject: header sform_to=To: header sform_cc=Cc: header sform_date=Date: header sform_body=message body sform_headers=any header sform_size=message size sform_return=advanced search form find_enone=No users matching your search were found find_title=Search Results find_results=Users matching search for $1 .. find_user=Username find_real=Real name find_group=Group find_home=Home directory find_size=Mail size find_incount=Emails find_sentcount=Sent acl_none=None acl_same=User with same name acl_all=All acl_read=Users whose mail can be read acl_users=Only users acl_userse=All except users acl_usersg=Members of groups acl_from=Allowable From addresses acl_any=Any address acl_fdoms=Mailbox @ domains acl_faddrs=Listed addresses acl_fdom=Any address @ domain acl_fromname=Real name for From address acl_apath=Limit files and program to directory acl_attach=Maximum total attachments size acl_unlimited=Unlimited acl_sent=Store sent mail in mailbox acl_canattach=Can attach server-side files? acl_candetach=Can detach files to server? acl_usersm=Users matching acl_asame=Same as username acl_usersu=With UID in range acl_sec=Include secondary groups? acl_dir=Can read mail files in directory acl_dirauto=Decide automatically (anywhere if all users are visible, nowhere otherwise) log_delmail=Deleted $1 messages from $2 log_movemail=Moved $1 messages from $2 to $3 log_copymail=Copied $1 messages from $2 to $3 log_send=Sent mail to $1 log_read=Read mail for $1 emodified=This folder has been modified since it was last viewed! Return to the mail list and try again. razor_title=Reporting As Spam razor_title2=Reporting As Ham razor_report=Reporting this message to Razor and other SpamAssassin spam-blocking databases .. razor_report2=Reporting the selected messages to Razor and other SpamAssassin spam-blocking databases .. razor_report3=Un-reporting the seleected messages to Razor and other SpamAssassin spam-blocking databases .. razor_done=.. done razor_err=.. failed! See the error message above for the reason why. razor_deleted=.. done, and deleted message too. ham_title=Reporting As Ham ham_report=Reporting this message as non-spam to Razor and other SpamAssassin databases .. black_title=Denying Sender black_done=Added the email address $1 to SpamAssassin's denied addresses list. black_already=The email address $1 is already on SpamAssassin's denied addresses list. white_title=Allowing Sender white_done=Added the email address $1 to SpamAssassin's allowed addresses list. white_already=The email address $1 is already on SpamAssassin's allowed addresses list. ldap_emod=Missing Perl module $1 needed for connecting to LDAP ldap_econn=Failed to connect to LDAP server $1 port $2 ldap_elogin=Failed to bind to LDAP server $1 as $2 : $3 ldap_ehost=No LDAP server set in module configuration ldap_eport=No valid LDAP server port set in module configuration ldap_euser=No LDAP login set in module configuration ldap_ebase=No LDAP base DN set in module configuration delall_title=Delete All Mail delall_rusure=Are you sure you want to delete all email from $1? $2 messages totalling $3 will be deleted forever. delall_ok=Delete Now mailboxes/lang/ca0100664000567100000120000003610410424446674013772 0ustar jcameronwheelindex_title=Lectura del Correu d'Usuaris index_none=NO tens perms per llegir el correu de cap usuari d'aquest sistema. index_header=Bsties d'usuaris index_empty=No hi ha correu index_return=a la llista d'usuaris index_esystem=No s'ha detectat al sistema cap dels servidors de correu suportats (Qmail, Postfix i Sendmail). Haurs d'ajustar la configuraci del mdul per configurar manualment el servidor de correu i possiblement els camins del correu. index_esystem2=No s'ha trobat al sistema el servidor de correu establert a la configuraci del mdul. Haurs de modificar la configuraci per que faci servir el servidor correcte. index_esystem3=S'ha produt un error en contactar el sistema de correu establert a la configuraci del mdul: $2. index_system2=Servidor de correu: Qmail index_system1=Servidor de correu: Sendmail index_system0=Servidor de correu: Postfix index_toomany=Hi ha massa usuaris al sistema com per mostrar-los en una sola pgina. index_find=Busca usuaris tals que el nom d'usuari index_equals=sigui igual que index_contains=contingui index_eperl=El mdul Perl $1 necessari per al mode d'autenticaci SMTP seleccionat no est installat o est mancat d'un mdul dependent. Fes clic aqu per installar-lo ara. index_file=Llegeix el Correu del Fitxer: index_nousers=No s'ha trobat cap usuari! index_nousersmail=No s'ha trobat cap usuari amb correu. mail_title=Correu de l'Usuari mail_from=De mail_date=Data mail_subject=Tema mail_to=A mail_cc=Cc mail_bcc=Bcc mail_pri=Prioritat mail_highest=Altssima mail_high=Alta mail_normal=Normal mail_low=Baixa mail_lowest=Baixssima mail_for=A $1 mail_for2=Per a l'usuari $1 mail_sent=A la llista de correu enviat mail_size=Mida mail_delete=Suprimeix mail_compose=Redacta mail_open=Obre mail_return=a la bstia de l'usuari mail_pos=Missatges $1 a $2 de $3 a $4 mail_none=Aquest usuari no t cap missatge a $1 mail_ecannot=No tens perms per llegir el correu d'aquest usuari mail_all=Selecciona-ho tot. mail_invert=Inverteix la selecci. mail_nosort=Reinicia l'ordenaci. mail_search=Busca missatges tals que mail_body=El cos mail_match=coincideixi amb mail_ok=Busca mail_nonefrom=Cap mail_mark=Marca com: mail_mark0=No llegit mail_mark1=Llegit mail_mark2=Especial mail_forward=Reenvia mail_move=Desplaa a: mail_copy=Copia a: mail_rfc=Des de la lnia mail_eexists=El missatge ja no existeix! mail_fchange=Canvia mail_indexlink=Torna a la bstia mail_deleteall=Suprimeix-los Tots mail_black=Denega els Remitents mail_white=Permet els Remitents mail_efile=El fitxer de correu no existeix mail_fromsrch=El mateix remitent... mail_subsrch=El mateix assumpte... mail_tosrch=El mateix destinatari... mail_sign=Signa amb la clau: mail_nosign=<No el signis> mail_crypt=Xifratge de: mail_nocrypt=<No el xifris> mail_samecrypt=<Claus de les adreces de destinaci> mail_addresses=Gestiona la Llibreta d'Adreces mail_folders=Gestiona les Carpetes mail_err=S'ha produt un error en llistar el correu d'aquesta carpeta: $1 mail_loginheader=Entrada al servidor POP3 mail_logindesc=Has d'introduir un usuari i una contrasenya per accedir al correu
d'entrada del servidor de correu $1. mail_loginuser=Usuari mail_loginpass=Contrasenya mail_loginmailbox=Bstia IMAP mail_login=Entrada mail_reset=Neteja mail_logout=Canvia l'entrada POP3 mail_logout2=Canvia l'entrada IMAP mail_sig=Edita la Signatura mail_jump=Salta a la pgina: mail_of=de mail_replyto=Respon a mail_folder=Carpeta mail_delall=Suprimeix-ho tot mail_deltrash=Buida la Paperera mail_search2=Busca: mail_advanced=Recerca Avanada mail_return2=al Correu de l'Usuari mail_esystem=S'ha produt un error en contactar amb el sistema de correu: $1. Aix ha de ser corregit per l'administrador del sistema. view_title=Lectura del Correu view_desc=Missatge $1 a $2 view_desc2=Missatge $1 per a l'usuari $2 view_desc3=Missatge $1 view_sent=Missatge $1 al la llista de correu enviat view_qdesc=Missatge $1 en cua view_headers=Capaleres de correu view_body=Text del missatge view_allheaders=Mostra totes les capaleres view_noheaders=Mostra les capaleres bsiques view_attach=Adjuncions view_reply=Respon view_reply2=Respon a tots view_enew=Edita coma nou view_forward=Reenvia view_delete=Suprimeix view_print=Imprimeix view_strip=Treu les Adjuncions view_ecannot=No tens perms per llegir el correu d'aquest usuari view_mark=Marca com: view_mark0=No llegit view_mark1=Llegit view_mark2=Especial view_return=al correu original view_sub=Correu Adjunt view_egone=Aquest missatge ja no existeix view_eugone=Aquest usuari no existeix view_gnupg=Verificaci de la signatura GnuPG view_gnupg_0=La signatura de $1 s vlida. view_gnupg_1=La signatura de $1 s vlida, per no s'ha pogut establir la cadena de fiabilitat. view_gnupg_2=La signatura de $1 NO s vlida. view_gnupg_3=L'ID de clau $1 no s a la teva llista, aix que no es pot verificar la signatura. view_gnupg_4=No he pogut verificar la signatura: $1 view_crypt=Desxifratge de correu GnuPG view_crypt_1=El missatge est xifrat, per el suport GnuPG no est installat. view_crypt_2=No he pogut desxifrar el missatge: $1 view_crypt_3=El correu s'ha desxifrat correctament. view_crypt_4=La part xifrada del missatge s'ha desxifrat correctament. view_recv=Obtingues l'ID de clau $1 del servidor de claus. view_folder=Torna a la bstia view_detach=Separa el fitxer: view_dall=<Tots els fitxers> view_dir=al fitxer o directori del servidor: view_black=Denega el Remitent view_white=Permet el Remitent view_razor=Informa com a Spam view_ham=Informa com a Ham view_razordel=Informa i Suprimeix view_dstatus=L'estat del lliurament ha fallat view_dstatusok=Estat de lliurament correcte view_final-recipient=Destinatari final view_diagnostic-code=Motiu de l'error view_remote-mta=Servidor de correu remot view_reporting-mta=Servidor de correu d'informes view_astext=Mostra com a text view_ashtml=Mostra com a HTML view_raw=Mostra el missatge tal com s compose_title=Redacci de Correu reply_title=Resposta de Correu forward_title=Reenviament de Correu enew_title=Edici de Correu reply_headers=Capaleres de correu reply_attach=Adjuncions reenviades reply_mailforward=Missatges reenviats reply_attach2=Adjuncions de la part del client i del servidor reply_send=Envia el Correu reply_ecannot=No tens perms per enviar correu amb aquest usuari reply_body=Text del missatge reply_errc=No he pogut copiar el correu reply_errm=No he pogut desplaar el correu reply_return=a la redacci del correu reply_spell=Comprova l'ortografia reply_draft=Desa com a Esborrany send_err=No he pogut enviar el correu send_eto=Hi falta l'adrea To send_efrom=Hi falta l'adrea From send_esubject=Hi falta l'asssumpte del correu send_title=Correu Enviat send_ok=Correu enviat correctament a to $1 send_sending=Enviant el correu a $1... send_ecannot=No tens perms per enviar correu amb aquest usuari send_esmtp=L'ordre SMTP $1 ha fallat: $2 send_eattach=Les adjuncions no poden fer ms de $1 Kb. send_eperms=L'usuari $1 no pot llegir $2 send_eperms2=No tens perms per enviar el fitxer $1 send_epath=L'executable de Sendmail $1 no existeix. send_efile=No he pogut llegir l'adjunci $1: $2 send_done=...fet. send_epass=No pots signar cap missatge perqu la teva frase de contrasenya encara no est configurada al mdul de GnuPG. send_esign=No he pogut signar el missatge: $1 send_ekey=No he pogut trobar la clau per a l'adrea de correu $1 send_ecrypt=No he pogut xifrar el missatge: $1 send_eword=Paraula '$1' incorrecta send_eword2=Paraula '$1' incorrecta - possible correcci: $2 send_eline=A la lnia $1: send_espell=S'han trobat els error ortogrfics segents al missatge... send_draft=El correu per a $1 s'ha desat a la carpeta d'esborranys. send_drafting=Desant el correu per a $1 a la carpeta d'esborranys... send_eattachsize=L'adjunci de correu excedeix la mida mxima permesa de $1 bytes delete_title=Supressi de Correu delete_rusure=Segur que vols suprimir les $1 missatges seleccionats de $2? Aix pot trigar una mica si el fitxer de correu s gros. No es podr realitzar cap altra acci fins que no s'hagi acabat la supressi. delete_rusure2=Segur que voleu suprimir aquest missatge de $1? Aix pot trigar una mica si el fitxer de correu s gros. No es podr realitzar cap altra acci fins que no s'hagi acabat la supressi. delete_ok=Suprimeix Ara delete_ecannot=No tens perms per suprimir correus d'aquest usuari delete_enone=No has seleccionat cap correu per suprimir delete_emnone=No has seleccionat cap correu per marcar delete_efnone=No has seleccionat cap correu per reenviar delete_ebnone=No has seleccionat cap correu per denegar delete_ewnone=No has seleccionat cap correu per permetre delete_ernone=No has seleccionat cap correu per informar-lo com a spam delete_ehnone=No has seleccionat cap correu per informar-lo com a ham delete_emoveuser=L'usuari per desplaar-hi el correu no existeix delete_ecopyuser=L'usuari per copiar-hi el correu no existeix delete_emovecannot=No tens perms per desplaar els correus a l'usuari especificat delete_ecopycannot=No tens perms per copiar els correus a l'usuari especificat delete_emovenone=No has seleccionat cap correu per desplaar delete_ecopynone=No has seleccionat cap correu per copiar delete_nobutton=No has fet clic a cap bot delete_ereport=No he pogut informar com a spam: $1 delete_errc=No he pogut copiar el correu delete_errm=No he pogut desplaar el correu confirm_title=Confirmaci de Supressi confirm_warn=Segur que vols suprimir els $1 missatges seleccionats? confirm_warn2=Degut a la mida i el format de la bstia, aix pot trigar una mica. No es podr realitzar cap altra acci fins que no s'hagi acabat la supressi. confirm_warn3=Segur que vols suprimir aquest missatge? confirm_warn4=No es podr realitzar cap altra acci fins que no s'hagi acabat la supressi. confirm_ok=Suprimeix Ara confirm_warnall=Segur que vols suprimir tots els missatges d'aquesta carpeta? search_title=Resultats de la Recerca search_ecannot=No tens perms per buscar dins del correu d'aquest usuari search_ematch=Has d'introduir un text de recerca. search_efield=Has de seleccionar un tipus de recerca. search_ewhat=No has introdut cap text de recerca per a la fila $1 search_enone=No has introdut cap criteri de recerca search_none=No s'ha trobat cap missatge. search_results2=$1 missatges de correu que coincideixen amb $2 search_results3=$1 missatges de correu que no coincideixen amb $2 search_results4=$1 missatges de correu que coincideixen amb la teva recerca search_msg2=Resultats de la recerca per a $1 search_msg4=Resultats de la recerca search_local=A les carpetes locals search_all=A totes les carpetes search_limit=(dels darrers $1 missatges) search_status=Amb estat search_allstatus=Qualsevol search_onestatus=Noms l'estat search_latest=Missatges a buscar search_nolatest=Tots els de la carpeta search_latestnum=Noms els darrers search_elatest=Hi falta el nombre de missatges a buscar o b s invlid search_withstatus=, amb estat $1 folder_inbox=Entrada folder_sent=Enviat folder_drafts=Drafts folder_trash=Trash detach_err=No he pogut separar el fitxer detach_edir=No has introdut cap fitxer o directori per desar detach_eopen=No he pogut obrir $1: $2 detach_ewrite=No he pogut gravar a $1: $2 detach_title=Alliberament de Fitxer detach_ok=He gravat l'adjunci al fitxer del servidor $1 ($2). sform_title=Recerca Avanada sform_and=Busca missatges que coincideixin amb els criteris de recerca de sota... sform_or=Busca missatges que coincideixin amb qualsevol dels criteris de recerca de sota... sform_neg0=cont sform_neg1=no cont sform_ok=Busca Ara sform_folder=a les carpetes sform_all=<Totes les carpetes> sform_local=<Carpetes locals> sform_where=Tal que sform_text=el text sform_from=la capalera From: sform_subject=la capalera Subject: sform_to=la capalera To: sform_cc=la capalera Cc: sform_date=la capalera Date: sform_body=el cos del missatge sform_headers=qualsevol capalera sform_size=la mida del missatge sform_return=al formulari de recerca avanada find_enone=No s'ha trobat cap usuari que coincideixi amb la teva recerca find_title=Resultats de la Recerca find_results=Usuaris que coincideixin amb la recerca per a $1... find_user=Usuari find_real=Nom real find_group=Grup find_home=Director i arrel find_size=Mida del correu find_incount=Correus find_sentcount=Enviats acl_none=Cap acl_same=Usuari amb el mateix nom acl_all=Tots acl_read=Usuaris el correu dels quals es pot llegir acl_users=Noms els usuaris acl_userse=Tots excepte els usuaris acl_usersg=Membres dels grups acl_from=Adreces From permissibles acl_any=Qualsevol adrea acl_fdoms=Dominis @ de bsties acl_faddrs=Adreces llistades acl_fdom=Qualsevol domini @ d'adrea acl_fromname=Nom real per a l'adrea From acl_apath=Limita els fitxers i el programa al directori acl_attach=Mida mxima total de les adjuncions acl_unlimited=Illimitada acl_sent=Emmagatzema el correu enviat a la bstia acl_canattach=Pot adjuntar fitxers del servidor acl_candetach=Pot separar fitxers al servidor acl_usersm=Usuaris que coincideixin amb acl_asame=Igual que el nom d'usuari acl_usersu=Amb UID en el rang acl_sec=Inclou grups secundaris acl_dir=Pot llegir els fitxer de correu del directori acl_dirauto=Decideix automticament (qualsevol lloc si tots els usuaris sn visibles, enlloc altrament) log_delmail=He suprimit $1 missatges de $2 log_movemail=He desplaat $1 missatges de $2 a $3 log_copymail=He copiat $1 missatges de $2 a $3 log_send=He enviat el correu a $1 log_read=He llegit el correu de $1 emodified=Aquesta carpeta s'ha modificat des de la darrera visualitzaci! Torna a la llista de correu i torna-ho a provar. razor_title=Informant com a Spam razor_title2=Informant com a Ham razor_report=Informant aquest missatge a Razor i altres bases de dades de blocatge de spam de SpamAssassin... razor_report2=Informant dels missatges seleccionats a Razor i altres bases de dades SpamAssassin de blocatge de spam... razor_report3=Desinformant els missatges seleccionats a Razor i altres bases de dades SpamAssassin de blocatge de spam... razor_done=... fet. razor_err=... ha fallat! Mira el missatge d'error de sobre per saber-ne el motiu. razor_deleted=...fet, i tamb he suprimit el missatge. ham_title=Informant com a Ham ham_report=Informant aquest missatges com a no spam a Razor i altres base de dades SpamAssassin... black_title=Denegant el Remitent black_done=He afegit l'adrea de correu $1 a la llista d'adreces denegades de SpamAssassin. black_already=L'adrea de correu $1 ja s a la llista d'adreces denegades de SpamAssassin. white_title=Permetent Remitent white_done=He afegit l'adrea de correu $1 a la llista d'adreces permeses de SpamAssassin. white_already=L'adrea de correu $1 ja s a la llista d'adreces permeses de SpamAssassin. ldap_emod=Falta el mdul Perl $1 necessari per connectar amb LDAP ldap_econn=No he pogut connectar amb el servidor LDAP $1 port $2 ldap_elogin=No he pogut lligar el servidor LDAP $1 com a $2: $3 ldap_ehost=No hi ha cap servidor LDAP establert a la configuraci del mdul ldap_eport=No hi ha cap port de servidor vlid LDAP establert a la configuraci del mdul ldap_euser=No hi ha cap entrada LDAP establerta a la configuraci del mdul ldap_ebase=No hi ha cap DN base establert a la configuraci del mdul mailboxes/lang/es0100664000567100000120000000704410316102527014001 0ustar jcameronwheelmail_title=Correo de Usuario mail_from=Desde mail_date=Fecha mail_subject=Asunto mail_to=Para mail_pri=Prioridad mail_highest=La mayor mail_high=Alta mail_low=Baja mail_lowest=La más baja mail_for=En $1 mail_for2=Para usuario $1 mail_sent=En lista de correo enviado mail_size=Medida mail_delete=Borrar mensajes seleccionados mail_compose=Componer nuevo correo mail_return=correo de usuario mail_ecannot=No estás autorizado a leer el correo de este usuario mail_all=Seleccionar todos mail_invert=Invertir selección mail_search=Hallar mensajes donde mail_body=Cuerpo mail_match=que coincida con mail_ok=Buscar mail_nonefrom=Ninguno mail_mark=Marcar los seleccionados como: mail_mark0=No leídos mail_mark1=Leídos mail_mark2=Especiales mail_forward=Remitir seleccionado mail_rfc=Desde línea view_title=Leer Correo view_desc=Mensaje $1 en $2 view_desc2=Mensaje $1 para usuario $2 view_desc3=Mensaje $1 view_sent=Mensaje $1 en lista de corre enviado view_qdesc=Mensaje en cola $1 view_headers=Cabeceras de Correo view_allheaders=Ver todas las cabeceras view_noheaders=Ver cabeceras básicas view_attach=Adjuntados view_reply=Responder view_reply2=Reponder a todos view_enew=Editar como nuevo view_forward=Remitir a view_delete=Borrar view_strip=Quitar Adjuntados view_ecannot=No estás autorizado a leer el correo de este usuario view_mark0=No leído view_mark1=Leído view_mark2=Especial view_return=correo original view_sub=Correo Adjunto compose_title=Componer Correo reply_title=Responder a Correo forward_title=Remitir Correo reply_headers=Cabeceras de Correo reply_attach=Adjuntados remitidos reply_mailforward=Mensajes remitidos reply_attach2=Adjuntados desde cliente y servidor reply_send=Enviar Correo reply_ecannot=No estás autorizado a enviar correo a este usuario send_err=Error al enviar correo send_eto=Dirección 'A' sin poner send_efrom=Dirección 'De' sin poner send_title=Correo enviado send_ok=Correo enviado correctamente a $1 send_ecannot=No estás autorizado a enviar correo como este usuario send_esmtp=Ha fallado el comando SMTP $1 : $2 send_eattach=Los archivos incluídos no pueden exceder más de 1kB de medida send_eperms=El usuario $1 no puede leer $2 send_eperms2=No estás autorizado a enviar archivo $1 send_epath=El ejecutable de Sendmail $1 no existe. delete_ecannot=No estás autorizado a borrar correo de este usuario delete_enone=No se ha seleccionado correo para ser borrado delete_emnone=No hay correo seleccionado para marcar search_title=Resultados de la búsqueda search_ecannot=No estás autorizado a buscar en este correo de usuario search_ematch=Debes de digitar un texto que coincida con algo. search_none=No se han encontrado mensajes. search_results3=$1 mensajes de correo no coinciden con $2 acl_none=Ninguno acl_same=Usuario con mismo nombre acl_all=Todos acl_read=Usuarios cuyo correo puede ser leído acl_users=Usuarios acl_userse=Todos excepto los usuarios acl_usersg=Miembros de grupo acl_from=Direcciones 'desde' autorizadas acl_any=Cualquier dirección acl_fdoms=Buzones en dominios acl_faddrs=Direcciones listadas acl_fdom=Cualquier dirección en dominio acl_fromname=Nombre real para dirección remitente acl_apath=Limitar archivos y programa a directorio acl_attach=Medida máxima total de archivos a incluir acl_sent=Almacenar correo enviado en buzón acl_canattach=¿Puede adjuntar archivos del lado servidor? acl_usersm=Usuarios que coincidan acl_asame=Igual que nombre de usuario log_delmail=Borrados $1 mensajes de $2 log_send=Enviado correo a $1 mailboxes/lang/fr0100664000567100000120000000756410176143320014010 0ustar jcameronwheelacl_all=Tous acl_any=De toutes les adresses acl_faddrs=Adresses listées acl_fdom=Toutes les adresses d'un domaines acl_fdoms=Boîte aux lettres des domaines acl_from=Des adresses acl_none=Aucun acl_read=Usagers dont les courriers peuvent être lu acl_users=Seulement les usagers acl_userse=Tous compose_title=Écrire un Courrier confirm_ok=Effacer maintenant confirm_title=Confirmer la suppression confirm_warn=Etes vous sur de vouloir supprimer les $1 messages sélectionnées? confirm_warn3=Etes vous sur de vouloir supprimer ce message? confirm_warn4=Jusqu'à la fin de l'effacement, aucune autre action ne peut êtes faite. confirm_warnall=Etes vous sûr de vouloir supprimer tous les messages de ce dossier? delete_ecannot=Vous n'êtes pas autorisé à supprimer les courriers de cet usager delete_ecopynone=Aucun message à copier sélectionner delete_efnone=Aucun message à transmettre sélectionné delete_emnone=Aucun message à marquer sélectionné delete_emovenone=Aucun message à déplacer sélectionné delete_enone=Aucun mail à effacer sélectionné delete_ernone=Aucun mail à raporter comme spam sélectionné delete_ok=Effacer maintenant delete_title=Effacer le message detach_title=Sauver les fichiers enew_title=Editer le message find_size=Taille du message forward_title=Rediriger un Courrier index_header=Boîtes aux lettres des usagers index_return=liste des utilisateurs index_system0=Serveur mail : Postfix index_system1=Serveur mail : Sendmail index_system2=Serveur mail : Qmail index_title=Lire les mails des usagers mail_all=Selectionner tout mail_cc=Copie carbone mail_compose=Écrire un nouveau courrier mail_copy=Copier vers: mail_delall=Tout supprimer mail_delete=Supprimer les messages sélectionnés mail_deleteall=Tout supprimer mail_ecannot=Vous n'êtes pas autorisé à lire les courriers des usagers mail_for=Dans $1 mail_forward=Transmettre mail_from=De mail_invert=Selectioner l'inverse mail_mark=Marqué comme: mail_mark0=Non lu mail_mark1=Lu mail_mark2=Spécial mail_move=Déplacer vers: mail_of=sur mail_ok=Chercher mail_pri=Priorité mail_replyto=Répondre à mail_reset=Effacer mail_return=courrier de l'usager mail_size=Taille mail_subject=Sujet mail_title=Courrier de l'Usager mail_to=À razor_done=.. fait razor_title=Rapporter comme Spam reply_attach=Attachement envoyé reply_attach2=Attachements reply_body=Corps du message reply_draft=Sauver comme brouillon reply_ecannot=Vous n'êtes pas autorisé à envoyer un courrier de cet usager reply_headers=Entêtes du courrier reply_send=Envoyer reply_title=Répondre au Courrier send_ecannot=Vous n'êtes pas autorisé à envoyer un courrier de cet usager send_efrom=Adresse de l'émetteur manquant send_err=Impossible d'envoyer le courrier send_esmtp=Impossible d'exécuter la commande SMTP $1 : $2 send_eto=Adresse du destinataire manquante send_ok=Courrier envoyé avec succès à $1 send_title=Courrier Envoyé view_allheaders=Voir toutes les entêtes view_ashtml=Voir en HTML view_astext=Voir en Texte view_attach=Attachements view_black=Refuser l'expéditeur view_delete=Supprimer view_desc=Courrier $1 dans $2 view_detach=Sauver les fichiers: view_dir=dans le répertoire: view_ecannot=Vous n'êtes pas autorisé à lire les courriers des usagers view_forward=Renvoyer view_headers=Entêtes du courrier view_mark=Marqué comme: view_mark0=Non lu view_mark1=Lu view_mark2=Spécial view_print=Imprimer view_qdesc=Courrier $1 de la file d'attente view_razor=Rapporter comme Spam view_razordel=Rapporter et Supprimer view_reply=Répondre view_reply2=Répondre à tous view_return=email original view_strip=Supprimer les pièces jointes view_title=Lire un Courrier mailboxes/lang/ja_JP.euc0100664000567100000120000000452710067670055015144 0ustar jcameronwheelmail_title=桼 E ᡼ mail_from= mail_date= mail_subject=̾ mail_to= mail_pri=ͥ mail_highest=ͥ mail_high= mail_normal=ɸ mail_low= mail_lowest=Ǹ mail_for=$1 mail_sent=Ѥߥ᡼ ꥹ mail_size= mail_delete=򤵤줿å mail_compose=᡼ mail_return=桼 E ᡼ mail_ecannot=Υ桼Υ᡼ɤޤ mail_all=٤ mail_invert=ȿž mail_search=åθ mail_body=ʸ mail_match= mail_ok= mail_nonefrom=ʤ view_title=E ᡼ɤ view_desc=$2Υå $1 view_sent=Ѥߥ᡼ ꥹȤΥå $1 view_qdesc=塼줿å $1 view_headers=᡼ إå view_attach=źեե view_reply=ֿ view_reply2=ֿ view_enew=ȤԽ view_forward=ž view_delete= view_ecannot=Υ桼Υ᡼ɤޤ compose_title=E ᡼κ reply_title=E ᡼ؤֿ forward_title=E ᡼ž reply_headers=᡼ إå reply_attach=ž줿źեե reply_attach2=źեե reply_send= reply_ecannot=Υ桼ȤƤϥ᡼Ǥޤ send_err=᡼ǤޤǤ send_eto=To ʰ˥ɥ쥹ޤ send_efrom=From () ɥ쥹ޤ send_title=줿᡼ send_ok=$1 ؤΥ᡼λޤ send_ecannot=Υ桼ȤƤϥ᡼Ǥޤ send_esmtp=SMTP ޥ $1 Ԥޤ: $2 send_eattach=źեեΥ $1 KB ۤޤ send_eperms=桼 $1 $2 ɤ߼ޤ send_eperms2=ե $1 Ǥޤ delete_ecannot=Υ桼Υ᡼Ǥޤ delete_enone=å򤵤Ƥޤ search_title= search_ecannot=Υ桼Υ᡼ϸǤޤ search_ematch=ˤϥƥȤϤɬפޤ search_none=åĤޤǤ acl_none=ʤ acl_same=Ʊ̾Υ桼 acl_all=٤ acl_read=᡼ɤ߼桼 acl_users=Υ桼Τ acl_userse=Υ桼ʳ٤ acl_usersg=롼פΥС acl_from=ɥ쥹 acl_any=ǤդΥɥ쥹 acl_fdoms=᡼ܥå @ ɥᥤ acl_faddrs=ꥹȤ줿ɥ쥹 acl_fdom=ǤդΥɥ쥹 @ ɥᥤ acl_apath=ǥ쥯ȥؤΥեȥץ acl_attach=źեեιץκ acl_sent=Ѥߥ᡼᡼ܥå¸ log_delmail=$1 å $2 ޤ log_send=$1 ˥᡼ޤ mailboxes/lang/ja_JP.jis0100664000567100000120000000452710032203513015134 0ustar jcameronwheelmail_title=[U E [ mail_from=M mail_date=t mail_subject= mail_to= mail_pri=Dx mail_highest=ŗD mail_high= mail_normal=W mail_low= mail_lowest=Ō mail_for=$1 mail_sent=Mς݃[ Xg mail_size=TCY mail_delete=IꂽbZ[W폜 mail_compose=VK[쐬 mail_return=[U E [ mail_ecannot=̃[U[̃[͓ǂ߂܂ mail_all=ׂđI mail_invert=I̔] mail_search=bZ[W̌ mail_body={ mail_match=v mail_ok= mail_nonefrom=Ȃ view_title=E [ǂ view_desc=$2̃bZ[W $1 view_sent=Mς݃[ Xg̃bZ[W $1 view_qdesc=L[ꂽbZ[W $1 view_headers=[ wb_ view_attach=Ytt@C view_reply=ԐM view_reply2=SɕԐM view_enew=VKƂĕҏW view_forward=] view_delete=폜 view_ecannot=̃[U[̃[͓ǂ߂܂ compose_title=E [̍쐬 reply_title=E [ւ̕ԐM forward_title=E [̓] reply_headers=[ wb_ reply_attach=]ꂽYtt@C reply_attach2=Ytt@C reply_send=M reply_ecannot=̃[UƂĂ̓[𑗐Mł܂ send_err=[𑗐Mł܂ł send_eto=To ijAhX܂ send_efrom=From (M) AhX܂ send_title=Mꂽ[ send_ok=$1 ւ̃[̑M܂ send_ecannot=̃[UƂĂ̓[𑗐Mł܂ send_esmtp=SMTP R}h $1 s܂: $2 send_eattach=Ytt@C̃TCY $1 KB z܂B send_eperms=[U $1 $2 ǂݎ܂ send_eperms2=t@C $1 ͑Mł܂ delete_ecannot=̃[Ũ[폜ł܂ delete_enone=폜郁bZ[WIĂ܂ search_title= search_ecannot=̃[Ũ[͌ł܂ search_ematch=ɂ̓eLXg͂Kv܂B search_none=bZ[W‚܂łB acl_none=Ȃ acl_same=̃[U acl_all=ׂ acl_read=[ǂݎ郆[U acl_users=̃[Û acl_userse=̃[UȊOׂ acl_usersg=O[ṽo[ acl_from=AhX狖 acl_any=Cӂ̃AhX acl_fdoms=[{bNX @ hC acl_faddrs=XgꂽAhX acl_fdom=Cӂ̃AhX @ hC acl_apath=fBNgւ̃t@CƃvO𐧌 acl_attach=Ytt@C̍vTCY̍ől acl_sent=Mς݃[[{bNXɕۑ log_delmail=$1 bZ[W $2 폜܂ log_send=$1 Ƀ[𑗐M܂ mailboxes/lang/ko_KR.euc0100664000567100000120000000434610032203523015145 0ustar jcameronwheelmail_title= mail_from=߽ mail_date=¥ mail_subject= mail_to= mail_cc= mail_bcc= mail_pri=켱 mail_highest= mail_high= mail_normal= mail_low= mail_lowest= mail_for=$1 mail_sent=߽ mail_size=ũ mail_delete= ޽ mail_compose= ۼ mail_return= mail_ecannot= ϴ mail_all= mail_invert=ݴ mail_search=޽ ˻ ġ mail_body= mail_match=ġ mail_ok=˻ mail_nonefrom= view_title= б view_desc=$2 ִ ޽ $1 view_sent=߽ Ͽ ִ ޽ $1 view_qdesc=⿭ ִ ޽ $1 view_headers= view_attach=÷ view_reply=ȸ view_reply2=ü ȸ view_enew= Ϸ view_forward= view_delete= view_ecannot= ϴ compose_title= ۼ reply_title= Ͽ ȸ forward_title= reply_headers= reply_attach=޵ ÷ reply_attach2=÷ reply_send= reply_ecannot= ڷ ϴ send_err= ߽ϴ send_eto= ּ send_efrom= ߽ ּ send_title= Ϸ send_ok=$1 ߽ϴ. send_ecannot= ڷ ϴ send_esmtp=SMTP $1 : $2 send_eattach=÷ ũ $1KB ʰ ϴ. send_eperms= $1() $2() ϴ send_eperms2= $1() ϴ delete_ecannot= ڷκ ϴ delete_enone= ʾҽϴ search_title=˻ search_ecannot= ˻ ϴ search_ematch=˻ ؽƮ Էؾ մϴ. search_none=޽ ϴ. acl_none= acl_same≠ acl_all= acl_read= ִ acl_users=ڸ acl_userse=ڸ acl_usersg=׷ acl_from= ߽ ּ acl_any= ּ acl_fdoms=缭@ acl_faddrs= ּ acl_fdom= ּ@ acl_apath=丮 α׷ acl_attach=ü ÷ ִ ũ acl_sent=缭Կ ߽ log_delmail=$2 $1 ޽ log_send=$1 Ϸ mailboxes/lang/it0100775000567100000120000003201710336063277014021 0ustar jcameronwheelindex_title=Read Utente Mail index_none=You are not allowed to read email for any utenti on questo system. index_header=Utente mailboxes index_empty=No mail index_return=utente list index_esystem=None of the supported mail servers (Qmail, Postfix and Sendmail) were detected on your system. You will need to adjust the module configuration to set the mail server and possibly mail paths manually. index_esystem2=The mail server set in the module configuration was not found on your system. You will need to adjust the configuration to use the correct server. index_system2=Mail server: Qmail index_system1=Mail server: Sendmail index_system0=Mail server: Postfix index_toomany=There are too many utenti on your system to display on one pagina. index_find=Cerca utenti where nome utente index_equals=uguale index_contains=contiene index_eperl=The Perl module $1 needed for the selected SMTP authentication mode is not installed or is missing a dependent module. Click here to install it now. index_file=Leggi posta nel file: mail_title=Utente Email mail_from=Da mail_date=Data mail_subject=Oggetto mail_to=To mail_cc=Cc mail_bcc=Bcc mail_pri=Priorità mail_highest=Più alta mail_high=Alta mail_normal=Normale mail_low=Bassa mail_lowest=Più bassa mail_for=In $1 mail_for2=For utente $1 mail_sent=Nella lista inviate mail_size=Dimensione mail_delete=Elimina mail_compose=Scrivi mail_open=Apri mail_return=utente mailbox mail_pos=Messaggi da $1 a $2 di $3 in $4 mail_none=questo utente non ha messaggi in $1 mail_ecannot=non hai i permessi per leggere la posta di questo utente mail_all=Seleziona tutti mail_invert=Selezione invertita mail_nosort=Annulla ordinamento mail_search=Cerca messaggi dove mail_body=Corpo mail_match=corrisponde mail_ok=Cerca mail_nonefrom=nessuno mail_mark=Segna come: mail_mark0=Non letto mail_mark1=Letto mail_mark2=Speciale mail_forward=inoltra mail_move=sposta in: mail_copy=copia in : mail_rfc=da linea mail_eexists=il messaggio non esiste più! mail_fchange=cambia mail_indexlink=torna alla casella di posta mail_deleteall=elimina tutto mail_black=blocca mittenti mail_white=accetta mittenti mail_efile=il file di Mail non esiste mail_fromsrch=stesso mittente.. mail_subsrch=stesso oggetto.. mail_tosrch=stesso destinatario mail_sign=firma con chiave: mail_nosign=<non firmare> mail_crypt=crpita per: mail_nocrypt=<non criptare> mail_samecrypt=<chiave per destinatari> mail_addresses=gestione Rubrica mail_folders=gestione cartelle mail_err=errore elencando i mesaggi in questa cartella : $1 mail_loginheader=POP3 server login mail_logindesc=inserisci nome utente e password per accedere alla posta
nella tua casella del server mail $1. mail_loginuser=nome utente mail_loginpass=password mail_loginmailbox=casella di posta IMAP mail_login=login mail_reset=pulisci mail_logout=cambia POP3 login mail_logout2=cambia IMAP login mail_sig=modifica firma mail_jump=vai a pagina: mail_of=of mail_replyto=rispondi a mail_folder=cartella mail_delall=elimina tutti mail_deltrash=svuota cestino mail_search2=cerca : mail_advanced=ricerca Avanzata mail_return2=utente Email view_title=leggi email view_desc=messaggio $1 di $2 view_desc2=messaggio $1 per utente $2 view_desc3=messaggio $1 view_sent=messaggio $1 in elenco posta inviata view_qdesc=messaggio accodato $1 view_headers=intestazione mail view_body=testo del messaggio view_allheaders=vedi tutte le intestazioni view_noheaders=vedi intestazioni base view_attach=allegati view_reply=rispondi view_reply2=rispondi a tutti view_enew=modifica come nuovo view_forward=inoltra view_delete=elimina view_print=stampa view_strip=elimina allegati view_ecannot=non hai i permessi di leggere la posta di questo utente view_mark=segna come view_mark0=non letto view_mark1=letto view_mark2=speciale view_return=email originale view_sub=email allegata view_egone=questo messaggio non esiste più view_gnupg=verifica firma GnuPG view_gnupg_0=la firma di $1 è valida view_gnupg_1=la firma di $1 è valida, ma il trust chain no è stato stabilito view_gnupg_2=la firma di $1 NON È valida view_gnupg_3=Key ID $1 is not in your list, so signature could not be verified. view_gnupg_4=Failed to verify signature : $1 view_crypt=GnuPG mail decryption view_crypt_1=Message is encrypted, but GnuPG support is not installed. view_crypt_2=Failed to decrypt messaggio : $1 view_crypt_3=Mail was successfully decrypted. view_crypt_4=Encrypted portion of messaggio was successfully decrypted. view_recv=Fetch key ID $1 da keyserver. view_folder=torna a mailbox view_detach=Detach file: view_dall=<All files> view_dir=a file server o directory view_black=blocca mittente view_white=sblocca mittente view_razor=segnala come spam view_ham=seganana come ham view_razordel=segnana ed elimina view_dstatus=errore stato di consegna view_dstatusok=stato di consegna ok view_final-recipient=Final recipient view_diagnostic-code=dettagli errore view_remote-mta=mail server remoto view_reporting-mta=segnalazione a mail server view_astext=vedi messaggio formato raw testo view_ashtml=vedi messaggio formato HTML view_raw=vedi messaggio formato raw compose_title=scrivi Email reply_title=rispondi a email forward_title=inoltra email enew_title=Modifica Email reply_headers=intestazioni Mail reply_attach=Inoltrato allegati reply_mailforward=Inoltrato messaggi reply_attach2=Client and server-side allegati reply_send=invia email reply_ecannot=non hai i permessi per inviare messaggi come questo utente reply_body=testo del messaggio reply_errc=errore nella copia reply_errm=errore nello spostare il messaggio reply_return=scrivi mail reply_spell=controllo ortografico? reply_draft=salva come bozza send_err=errore nell'invio email send_eto=inserire il destinatario send_efrom=inserire il mittente send_title=Mail inviata send_ok=Mail inviata a $1 send_sending=invio posta a $1 .. send_ecannot=Non hai i permessi per inviare mail a questo utente send_esmtp=SMTP command $1 failed : $2 send_eattach=gli allegati non possono essere superiori a $1 kB in dimensione. send_eperms=utente $1 non può leggere $2 send_eperms2=non hai i permessi per inviare file $1 send_epath=Sendmail executable $1 does not exist. send_efile=errore nel leggere allegato $1 : $2 send_done=.. fatto send_epass=non è possibile firmare il messaggio perchè la tua passphrase non risulta imposta nel modulo GnuPG send_esign=errore nella firma del messaggio : $1 send_ekey=Couldn't find key for email indirizzo $1 send_ecrypt=Failed to encrypt messaggio : $1 send_eword=errore grammaticale $1 send_eword2=errore grammaticale $1 - correzioni possibili $2 send_eline=a riga $1 : send_espell=i seguenti errori grammaticali sono stati trovati nel messaggio .. send_draft=messaggio a $1 salvato nella cartella bozze send_drafting=salvataggio mail to $1 nella cartella bozze send_eattachsize=l'allegato di posta supera il limite massimo consentito di $1 bytes delete_title=elimina Mail delete_rusure=confermi eliminazione dei $1 messaggi selezionati da $2? Questa operazione potrebbe richiedere tempo. Non eseguire altre operazioni fino al messaggio di conferma. delete_rusure2=confermi eliminazione di questo messaggio da $1? Questa operazione potrebbe richiedere tempo. Non eseguire altre operazioni fino al messaggio di conferma. delete_ok=elimina ora delete_ecannot=non hai i permessi per eliminare da questo utente delete_enone=non risultano selezionate email da eliminare delete_emnone=non risultano selezionate email da segnare delete_efnone=non risultano selezionate email da inoltrare delete_ebnone=non risultano selezionate email da bloccare delete_ewnone=non risultano selezionate email da sbloccare delete_ernone=non risultano selezionate email da segnalare come span delete_ehnone=non risultano selezionate email da segnalare come ham delete_emoveuser=utente a cui spostare mail non esiste delete_ecopyuser=utente a cui copiare mail non esiste delete_emovecannot=non hai i permessi per spostare mail all'utente indicato delete_ecopycannot=non hai i permessi per copiare mail all'utente indicato delete_emovenone=non risultano selezionate email da spostare delete_ecopynone=non risultano selezionate email da copiare delete_nobutton=nessun bottone clicked delete_ereport=errore nella segnalazione spam : $1 delete_errc=errore nella copia mail delete_errm=errore nello spostamento mail confirm_title=conferma elimina confirm_warn=confermi eliminazione dei $1 messaggi selezionati? confirm_warn2=Because of the dimensione and format of your mailbox, questo may take some time. Until the deletion has finished, no other action should be performed. confirm_warn3=Are you sure you want to delete questo messaggio? confirm_warn4=Until the deletion has finished, no other action should be performed. confirm_ok=Elimina Now confirm_warnall=Are you sure you want to delete all of the messaggi in questo cartella? search_title=esito ricerca search_ecannot=non hai i permessi per cercare mail di questo utente search_ematch=inserisci un testo per il confronto search_efield=seleziona tipo di ricerca search_ewhat=No text to match against entered for row $1 search_enone=inserisci un criterio di ricerca search_none=nessun messaggio trovato search_results2=$1 messaggi corrispondenti a $2 search_results3=$1 messaggi non corrispondenti $2 search_results4=$1 messaggi corrispondenti alla ricerca search_msg2=esito ricerca per $1 search_msg4=esito ricerca search_local=nella cartelle locali search_all=in tutte le cartelle search_limit=(da last $1 messaggi) search_status=con status search_allstatus=tutti search_onestatus=solo status search_latest=Messaggi da cercare search_nolatest=tutto in cartella search_latestnum=più recenti search_elatest=inserisci un numero valido di messaggio da cercare search_withstatus=, con status $1 folder_inbox=arrivo folder_sent=inviata folder_drafts=bozze folder_trash=cestino detach_err=errore in detach file detach_edir=No file or directory to save to entered detach_eopen=errore di lettura $1 : $2 detach_ewrite=erroe di scrittura su $1 : $2 detach_title=Detach File detach_ok=scritto allegato al file server-side $1 ($2). sform_title=Ricerca avanzata sform_and=Cerca messaggi con tutti i criteri sotto sform_or=Cerca messaggi con ogni criterio sotto sform_neg0=contiene sform_neg1=non contiene sform_ok=Cerca ora sform_folder=in cartella(s) sform_all=<tuttel el cartelle> sform_local=<cartelle locali> sform_where=Dove sform_text=il testo sform_from=Da: intestazione sform_subject=Oggetto: intestazione sform_to=To: intestazione sform_cc=Cc: intestazione sform_date=Date: intestazione sform_body=messaggio corpo sform_headers=ogni intestazione sform_size=messaggio dimensione sform_return=form ricerca avanzata find_enone=Nessun utente corrisponde alla ricerca effettuata find_title=Cerca risultati find_results=utenti corrispondenti alla ricerca per $1 .. find_user=Nome utente find_real=Nome reale find_group=Gruppo find_home=Home directory find_size=dimensione mail find_incount=Messaggi find_sentcount=Inviati acl_none=Nessuno acl_same=Utente con stesso nome acl_all=tutti acl_read=utenti ai quali la posta può essere letta acl_users=Solo utenti acl_userse=Tutto tranne utenti acl_usersg=Membri dei gruppi acl_from=Disponibile da indirizzi acl_any=Ogni indirizzo acl_fdoms=Mailbox @ domini acl_faddrs=indirizzi elencati acl_fdom=ogni indirizzo @ dominio acl_fromname=Nome reale per Da indirizzo acl_apath=Limite file e programi per directory acl_attach=dimesione totale massima degli allegati acl_sent=archivia posta inviata in cartella mailbox acl_canattach=puoi/può allegare file server-side? acl_candetach=puoi/può detach files al server? acl_usersm=corrispondenza utente acl_asame=Stesso come nome utente acl_usersu=With UID in range acl_sec=Include secondary gruppi? acl_dir=puoi/può leggere mail nella directory acl_dirauto=scelta automatica (ovunque se tutti gli utenti sono visibili, al contrario da nessuna parte) log_delmail=eliminati $1 messaggi da $2 log_movemail=spostati $1 messaggi da $2 a $3 log_copymail=copiati $1 messaggi da $2 a $3 log_send=mail inviata a to $1 log_read=leggi/letta mail per $1 emodified=questa cartella è stata modificata dall'ultima visita! torna a lista mail e riprova razor_title=segnala come spam razor_report=sto segnalando questo messaggio a Razor o altri SpamAssassin spam-blocking databases .. razor_done=.. fatto razor_err=.. errore! vedi dettagli sopra razor_deleted=.. fatto , il messaggio è stato eliminato ham_title=Reporting As Ham ham_report=Reporting questo messaggio as non-spam to Razor and other SpamAssassin databases .. black_title=Denying Sender black_done=Added the email indirizzo $1 to SpamAssassin's denied indirizzi list. black_already=The email indirizzo $1 is already on SpamAssassin's denied indirizzi list. white_title=Allowing Sender white_done=Added the email indirizzo $1 to SpamAssassin's allowed indirizzi list. white_already=The email indirizzo $1 is already on SpamAssassin's allowed indirizzi list. ldap_emod=Missing Perl module $1 needed for connecting to LDAP ldap_econn=Failed to connect to LDAP server $1 port $2 ldap_elogin=Failed to bind to LDAP server $1 as $2 : $3 mailboxes/lang/pl0100664000567100000120000000625210032203535014001 0ustar jcameronwheelmail_title=Poczta uytkownika mail_from=Od mail_date=Wysano mail_subject=Temat mail_to=Do mail_cc=DW mail_bcc=UDW mail_pri=Priorytet mail_highest=Najwyszy mail_high=Wysoki mail_normal=Zwyky mail_low=Niski mail_lowest=Najniszy mail_for=W $1 mail_for2=Dla uytkownika $1 mail_sent=Na licie poczty wysanej mail_size=Rozmiar mail_delete=Skasuj wybrane wiadomoci mail_compose=Utwrz now wiadomo mail_return=skrzynki uytkownika mail_ecannot=Nie masz uprawnie do czytania poczty tego uytkownika mail_all=Wybierz wszystko mail_invert=Odwr zaznaczenia mail_search=Znajd wiadomoci, w ktrych mail_body=Tre mail_match=zawiera mail_ok=Szukaj mail_nonefrom=Brak mail_mark=Zaznacz wybrane jako: mail_mark0=Nie przeczytane mail_mark1=Przeczytane mail_mark2=Specjalne view_title=Czytaj poczt view_desc=Wiadomo $1 w $2 view_desc2=Wiadomo $1 dla uytkownika $2 view_desc3=Wiadomo $1 view_sent=Wiadomo $1 na licie poczty wysanej view_qdesc=Wiadomo w kolejce $1 view_headers=Nagwki wiadomoci view_attach=Zaczniki view_reply=Odpowiedz view_reply2=Odpowiedz wszystkim view_enew=Edytuj jako now view_forward=Przeka dalej view_delete=Skasuj view_strip=Usu zaczniki view_ecannot=Nie masz uprawnie do czytania poczty tego uytkownika view_mark0=Nie przeczytan view_mark1=Przeczytan view_mark2=Specjaln view_return=pierwotnego adresu e-mail compose_title=Utwrz wiadomo reply_title=Odpowiedz na wiadomo forward_title=Przeka dalej reply_headers=Nagwki wiadomoci reply_attach=Przekazywane zaczniki reply_attach2=Zaczniki reply_send=Wylij reply_ecannot=Nie masz uprawnie do czytania poczty jako ten uytkownik send_err=Nie udao si wysa wiadomoci send_eto=Brak adresu docelowego send_efrom=Brak adresu rdowego send_title=Wiadomo wysana send_ok=Wiadomo pomylnie wysana do $1 send_ecannot=Nie masz uprawnie do wysyania poczty jako ten uytkownik send_esmtp=Polecenie SMTP $1 zakoczyo sie bdem : $2 send_eattach=czny rozmiar zacznikw nie moe przekracza $1 kB. send_eperms=Uytkownik $1 nie ma uprawnie do czytania $2 send_eperms2=Nie masz uprawnie do wysania pliku $1 delete_ecannot=Nie masz uprawnie do kasowania poczty tego uytkownika delete_enone=Nie wybrano wiadomoci do skasowania delete_emnone=Nie wybrano wiadomoci do zaznaczenia search_title=Wyniki poszukiwania search_ecannot=Nie masz uprawnie do przeszukiwania poczty tego uytkownika search_ematch=Musisz wprowadzi poszukiwany tekst search_none=Nie znaleziono adnej wiadomoci acl_none=adne acl_same=Uytkownika o tej samej nazwie acl_all=Wszystkie acl_read=Uytkownicy, ktrych poczta moe by czytana acl_users=Tylko uytkownicy acl_userse=Oprcz uytkownikw acl_usersg=Czonkowie grupy acl_from=Dozwolone adresy rdowe acl_any=Dowolny adres acl_fdoms=Skrzynka @ domeny acl_faddrs=Wymienione adresy acl_fdom=Dowolny adres @ domena acl_fromname=Rzeczywista nazwa dla adresu rdowego acl_apath=Ograniczy pliki i&npsp;programy do umieszczonych w&npsp;katalogu acl_attach=Maksymalny czny rozmiar zacznikw acl_sent=Przechowywa wysan poczt w skrzynce acl_canattach=Moe docza pliki z serwera? log_delmail=Usunito $1 wiadomoci z $2 log_send=Wysano wiadomo do $1 mailboxes/lang/pt0100664000567100000120000000224210032203541014001 0ustar jcameronwheelmail_title=Email do Utilizador mail_from=De mail_date=Data mail_subject=Assunto mail_to=Para mail_for=Em $1 mail_compose=Compor novo correio mail_return=email do utilizador mail_ecannot=Voc no est autorizado para ler o correio deste utilizador view_title=Ler Correio view_desc=Mensagem $1 em $2 view_qdesc=Mensagem em lista de espera $1 view_headers=Cabaalhos de correio view_attach=Anexos view_reply=Responder ao autor view_reply2=Responder a todos view_forward=Reenviar view_delete=Apagar view_ecannot=Voc no est autorizado para ler o correio deste utilizador compose_title=Compor Email reply_title=Responder ao Email forward_title=Reenviar Email reply_headers=Cabealhos de Correio reply_attach=Anexos Reenviados reply_attach2=Anexos reply_send=Enviar reply_ecannot=Voc no est autorizado para enviar correio como sendo este utilizador send_err=Erro ao enviar correio send_eto=Falta o endereo do destinatrio send_title=Correio enviado send_ok=O correio foi enviado com sucesso para $1 send_ecannot=Voc no est autorizado para enviar correio como sendo este utilizador acl_none=Nenhum acl_all=Todos acl_read=Utilizadores cujo correio pode ser lido acl_users=Utilizadores mailboxes/lang/zh_TW.UTF-80100664000567100000120000002175510420075004015227 0ustar jcameronwheelacl_all=全部 acl_any=任何郵件位址 acl_apath=限制檔案和程式到目錄 acl_asame=與使用者相同 acl_attach=最大附件總大小 acl_canattach=可以附加伺服器檔嗎? acl_candetach=可以附帶檔案到伺服器? acl_faddrs=列出的郵件位址 acl_fdom=任何郵件位址在網域 acl_fdoms=信箱在網域 acl_from=依據郵件位址允許 acl_fromname=來源地址的真實名稱 acl_none=無 acl_read=可以讀取哪些使用者的郵件 acl_same=同名的使用者 acl_sent=在郵箱中儲存已發送的郵件 acl_users=只有使用者 acl_userse=全部, 除了使用者 acl_usersg=組的成員 acl_usersm=符合的使用者 acl_usersu=在UID範圍內 compose_title=寫作電子郵件 confirm_ok=現在刪除 confirm_title=確認刪除 confirm_warn=您確定要刪除 $1 封選取的訊息? confirm_warn2=因為您的信箱大小與格式,需要一點時間,直到刪除完成後,不會執行其他動作 confirm_warn3=您確定要刪除訊息 confirm_warn4=直到刪除完成,不會執行其他動作。 confirm_warnall=您確定要刪除資料夾中所有訊息? delete_ecannot=您不被允許刪除這個使用者的郵件 delete_ecopycannot=您不被允許複製郵件到特定的使用者 delete_ecopynone=未選取複製郵件 delete_ecopyuser=複製郵件使用者不存在 delete_efnone=未選取轉寄郵件 delete_emnone=沒有選擇要標記的郵件 delete_emovecannot=您不被允許移動郵件到特定的使用者 delete_emovenone=未選移動寄郵件 delete_emoveuser=使用者移動郵件不存在 delete_enone=沒有選擇要刪除的郵件 delete_nobutton=未按按鈕 delete_ok=現在刪除 delete_rusure=您確定要從$2刪除 $1 封選取的訊息?大檔案的郵件需要一些時間,直到刪除完成,不會執行其他動作。 delete_rusure2=您確定要刪除 $1 封選取的訊息?大檔案的郵件需要一些時間,直到刪除完成,不會執行其他動作。 delete_title=刪除郵件 detach_edir=沒有輸入儲存的檔案或目錄 detach_eopen=開始$1失敗:$2 detach_err=附加檔案失敗 detach_ewrite=寫給$1失敗:$2 detach_ok=從伺服端附加檔案$1($2) detach_title=附加檔案 enew_title=編輯郵件 find_enone=沒有您搜尋所符合的使用者 find_group=群組 find_home=家目錄 find_real=真實名稱 find_results=搜尋$1符合的使用者.. find_size=郵件大小 find_title=搜尋結果 find_user=使用者名稱 folder_drafts=草稿 folder_inbox=收件夾 folder_sent=傳送郵件 folder_trash=垃圾桶 forward_title=轉寄到電子郵件 index_contains=包含 index_empty=無郵件 index_equals=等於 index_esystem=在您的系統上找不到支援的郵件伺服器(Qmail, Postfix 和 Sendmail),您可以手動調整模組組態來設定郵件伺服器和郵件路徑 index_esystem2=在您的系統上找不到模組組態中設定的郵件伺服器,您需要調整正確的伺服器組態。 index_find=在使用者名稱中找尋使用者 index_header=使用者信箱 index_none=您不被允許任何此系統上使用者讀取郵件 index_return=Sendmail 組態 index_system0=郵件伺服器:Postfix index_system1=郵件伺服器:Sendmail index_system2=郵件伺服器:Qmail index_title=Sendmail 組態 index_toomany=在您的系統上有太多的使用者,所以無法同時顯示在一頁上 log_copymail=從 $2 到 $3 複製$1封訊息 log_delmail=已從 $2 刪除 $1郵件 log_movemail=從 $2 到 $3 移動$1封訊息 log_send=已發送郵件到 $1 mail_addresses=管理聯絡人 mail_advanced=進階搜尋 mail_all=選擇全部 mail_bcc=隱藏副本 mail_body=本體 mail_cc=副本抄送 mail_compose=寫作新郵件 mail_copy=複製到: mail_crypt=GnuPG加密給: mail_date=日期 mail_delall=全部刪除 mail_delete=刪除選擇的郵件 mail_deltrash=空垃圾桶 mail_ecannot=您不被允許讀取這個使用者的郵件 mail_eexists=訊息不存在了! mail_err=此資料夾中郵件列表發生一個錯誤 : $1 mail_fchange=變更 mail_folder=資料夾 mail_folders=管理資料夾 mail_for=在 $1 mail_for2=用於使用者$1 mail_forward=轉寄已選擇的 mail_from=寄件人 mail_high=高 mail_highest=最高 mail_invert=反向選取 mail_jump=跳至頁面: mail_login=登入 mail_logindesc=您必須在郵件主機$1上
輸入使用者名稱和密碼來進入信箱 mail_loginheader=POP3登入伺服器 mail_loginmailbox=IMAP信箱 mail_loginpass=密碼 mail_loginuser=使用者名稱 mail_logout=變更POP3登入 mail_logout2=變更IMAP登入 mail_low=低 mail_lowest=最低 mail_mark=將選取的郵件標記為: mail_mark0=未閱讀 mail_mark1=閱讀 mail_mark2=特別 mail_match=符合 mail_move=移至: mail_nocrypt=<不編碼> mail_none=信箱中沒有郵件 mail_nonefrom=無 mail_normal=一般 mail_nosign=<不簽證> mail_of=的 mail_ok=搜尋 mail_pos=郵件 $1 到 $2 共 $3 mail_pri=優先值 mail_replyto=回至 mail_reset=清除 mail_return=使用者電子郵件 mail_return2=使用者郵件 mail_rfc=寄件人 mail_samecrypt=<金鑰從目的位置> mail_search=找尋郵件, 其中 mail_search2=搜尋: mail_sent=在發送郵件列表中 mail_sig=編輯簽名 mail_sign=GnuPG加密: mail_size=大小 mail_subject=主題 mail_title=使用者電子郵件 mail_to=收件人 reply_attach=轉寄附件夾帶 reply_attach2=附件夾帶 reply_body=訊息文字 reply_draft=存至草稿 reply_ecannot=您不被允許以這個使用者名稱送出郵件 reply_headers=郵件標頭 reply_mailforward=已轉寄的郵件 reply_send=送出 reply_spell=拼字檢查? reply_title=回覆到電子郵件 search_all=在所有資料夾 search_ecannot=您不被允許搜尋這個使用者的郵件 search_efield=您必須選取搜尋類型 search_ematch=您必須輸入搜尋的條件 search_enone=未輸入條件 search_ewhat=未輸入列$1符合文字 search_local=在本地資料夾 search_none=找不到符合的郵件. search_results2=$1郵件符合$2 search_results3=$1郵件不符合$2 search_results4=$1封郵件訊息符合您的搜尋 search_title=搜尋結果 send_draft=寄給$1儲存到草稿資料夾 send_eattach=附件大小總合不能超過 $1 kB。 send_eattachsize=郵件附加檔超過允許最大的大小$1 位元組 send_ecannot=您不被允許以這個使用者名稱送出郵件 send_ecrypt=訊息編碼失敗:$1 send_efile=閱讀附帶檔$1失敗 : $2 send_efrom=遺失寄件人郵件位址 send_ekey=在郵件$1找不到金鑰 send_eline=在線$1上: send_epass=您不能對訊息作數位簽章,因為您尚未設定GunPG模組裡的通行碼 send_epath=Sendmail程式 $1不存在。 send_eperms=使用者 $1 不能閱讀 $2 send_eperms2=您不被允許發送檔$1 send_err=郵件送出失敗 send_esign=數位簽章訊息失敗: $1 send_esmtp=SMTP 命令 $1 失敗: $2 send_espell=在您的訊息中找到下列拼字錯誤 .. send_eto=遺失收件人郵件位址 send_eword=錯字$1 send_eword2=錯字$1 - 可能正確的是 $2 send_ok=郵件成功的送給 $1 send_title=送出郵件 sform_all=<所有資料夾> sform_and=找到下列符合所有條件訊息 .. sform_body=訊息內容 sform_cc=副本: 檔頭 sform_date=日期:檔頭 sform_folder=在資料夾 sform_from=從:檔頭 sform_headers=任何檔頭 sform_local=<本地資料夾> sform_neg0=包含 sform_neg1=不包含 sform_ok=接受 sform_or=找到下列符合任一條件訊息 .. sform_return=進階搜尋 sform_size=訊息大小 sform_subject=主旨: 檔頭 sform_text=在文字 sform_title=進階搜尋 sform_to=收件人: 檔頭 sform_where=哪裡 view_allheaders=查看所有郵件檔頭 view_ashtml=檢視HTML view_astext=檢視文字 view_attach=附件夾帶 view_black=封鎖寄件者 view_body=訊息文字 view_crypt=GnuPG郵件解密 view_crypt_1=訊息已加密,但GnuPG支援尚未安裝 view_crypt_2=解密訊息失敗: $1 view_crypt_3=郵件成功解密 view_crypt_4=加密保護郵件成功解密 view_dall=<所有檔案> view_delete=刪除 view_desc=郵件 $1 在 $2 view_desc2=使用者$2的郵件$1 view_desc3=郵件$1 view_detach=附加檔案: view_diagnostic-code=失敗原因 view_dir=到伺服器檔案或目錄 view_dstatus=傳送狀態失敗 view_ecannot=您不被允許讀取這個使用者的郵件 view_egone=訊息不存在 view_enew=編輯新郵件 view_final-recipient=最後收件者 view_folder=返回信箱 view_forward=轉寄 view_gnupg=GnuPG認證簽章 view_gnupg_0=$1簽章確認 view_gnupg_1=$1簽章有效,但無法建立垃圾桶 view_gnupg_2=$1簽章尚未確認 view_gnupg_3=您的清單中無金鑰$1,所以簽章無效 view_gnupg_4=確認簽章 view_headers=郵件標頭 view_mark=標記為: view_mark0=未閱讀 view_mark1=閱讀 view_mark2=特別 view_noheaders=察看基本郵件檔頭 view_print=列印 view_qdesc=佇列中的郵件 $1 view_raw=檢視原始訊息 view_razor=回報給Razor view_recv=從金鑰主機取得金鑰$1. view_remote-mta=遠端郵件伺服器 view_reply=回覆 view_reply2=回覆給全部 view_reporting-mta=回報郵件伺服器 view_return=原始郵件 view_sent=已發送郵件列表中的郵件$1 view_strip=移除附件 view_sub=附帶的郵件 view_title=讀取電子郵件 mailboxes/lang/sv0100664000567100000120000000441110032203565014014 0ustar jcameronwheelmail_title=Anvndar-e-post mail_from=Frn mail_date=Datum mail_subject=rende mail_to=Till mail_cc=Kopia till mail_bcc=Osynlig kopia till mail_pri=Prioritet mail_highest=Hgsta mail_high=Hg mail_low=Lg mail_lowest=Lgsta mail_for=I $1 mail_size=Storlek mail_delete=Radera angivna brev mail_compose=Skriv nytt brev mail_return=anvndarpost mail_ecannot=Du fr inte lsa e-post till denna anvndare mail_all=Vlj allt mail_invert=Vlj allt utom redan valt mail_search=Sk meddelanden dr mail_body=Brevkroppen mail_match=innehller mail_ok=Sk mail_nonefrom=Ingen view_title=Ls e-post view_desc=Brev $1 i $2 view_qdesc=Kad e-post $1 view_headers=Rubriker view_attach=Bilagor view_reply=Svara view_reply2=Svara till alla view_forward=Skicka vidare view_delete=Radera view_ecannot=Du fr inte lsa e-post till denna anvndare compose_title=Skriv brev reply_title=Svara p brev forward_title=Skicka vidare brev reply_headers=Rubriker reply_attach=Vidaresnda bilagor reply_attach2=Bilagor reply_send=Skicka reply_ecannot=Du fr inte skicka e-post som denna anvndare send_err=Det gick inte att skicka brevet send_eto=Mottagaradress saknas send_efrom=Avsndaradress saknas send_title=Skickat brev send_ok=Brevet skickat till $1 send_ecannot=Du fr inte skicka e-post som denna anvndare send_esmtp=SMTP-kommando $1 misslyckades: $2 send_eattach=Den sammanlagda storleken p bilagorna fr inte vara strre n $1 kB send_eperms=Anvndare $1 kan inte lsa $2 send_eperms2=Du fr inte skicka filen $1 delete_ecannot=Du fr inte radera e-post frn denna anvndare delete_enone=Du har inte angivit vilket meddelande som ska tas bort search_title=Skresultat search_ecannot=Du fr inte ska i denna anvndares e-post search_ematch=Du mste ange en text som brevet ska innehlla search_none=Inget brev passade in p angivna villkor acl_none=Inga acl_same=Anvndare med samma namn acl_all=Alla acl_read=Anvndare vars e-post fr lsas acl_users=Endast anvndare acl_userse=Alla utom anvndare acl_usersg=Medlemmar i grupp acl_from=Tilltna avsndaradresser acl_any=Alla acl_fdoms=brevlda@domner acl_faddrs=Angivna adresser acl_fdom=valfri adress@domn acl_apath=Begrnsa filer och program till katalog acl_attach=Maximal sammanlagd storlek p bilagor log_delmail=Tog bort $1 brev frn $2 log_send=Skickade e-post till $1 mailboxes/lang/tr0100664000567100000120000000433510032203570014012 0ustar jcameronwheelmail_title=Kullanc E-Posta mail_from=Nereden mail_date=Tarih mail_subject=Konu mail_to=Nereye mail_pri=ncelik mail_highest=En yksek mail_high=Yksek mail_low=Dk mail_lowest=en dk mail_for=$1'de mail_size=Boyut mail_delete=Seilen mesajlar sil mail_compose=Yeni posta olutur mail_return=Kullanc e-posta mail_ecannot=Bu kullancnn e-postasn okumak iin izininiz yoktur mail_all=Hepsini se mail_invert=Seimi ters evir mail_search=Mesajlarn aranlaca yer mail_body=Mesaj ierii mail_ok=Ara view_title=E-posta oku view_desc=Mesaj $1, $2'de view_qdesc=Kuyrua konulmu mesaj $1 view_headers=Posta balklar view_attach=Ekler view_reply=Geri gnder view_reply2=Hepsine geri gnder view_forward=Dndr view_delete=Sil view_ecannot=Bu kullancnn e-postasn okumak iin izininiz yoktur compose_title=E-posta Gnder reply_title=E-postay Geri Gnder forward_title=E-postay Dndr reply_headers=Posta balklar reply_attach=Dndrlm ekler reply_attach2=Ekler reply_send=Gnder reply_ecannot=Bu kullanc olarak e-posta gndermek iin izininiz yoktur send_err=Postann gnderilmesinde hata olutu send_eto=Nereye adresini girmelisiniz send_efrom=Nereden adresini girmelisiniz send_title=Posta Gnder send_ok=Posta $1'e baaryla gnderildi send_ecannot=Bu kullanc olarak e-posta gndermek iin izininiz yoktur send_esmtp=SMTP komutu $1'de hata olutu : $2 send_eattach=Ek dosyalarn boyutu $1 KB'den daha byk olmamaldrlar. send_eperms=$1 kullancs $2'yi okuyamaz delete_ecannot=Bu kullanc olarak e-posta silmek iin izininiz yoktur delete_enone=Silmek iin posta silinmedi search_title=Arama sonular search_ecannot=Bu kullanc e-postalarn aramak iin izininiz yoktur search_ematch=Takip eden kutuya bir yaz girmelisiniz search_none=Mesaj bulunamad. acl_none=Hibiri acl_all=Hepsi acl_read=Kullanclarn okuyabilecekleri postalar acl_users=Sadece kullanclar acl_userse=Kullanclardan baka herkes acl_from=zin verilebilir From: adresleri acl_any=Herhangi bir adres acl_fdoms=Posta kutusu @ alanlar acl_faddrs=Listelenmi alanlar acl_fdom=Herhangi adres @ alan acl_apath=Dizin iin program ve dosya limitleri acl_attach=En ok toplam posta ek dosyalar boyutu log_delmail=$2'den $1 mesaj silindi log_send=$1'e posta gnderildi mailboxes/lang/zh_CN0100664000567100000120000000476510153206061014377 0ustar jcameronwheelmail_title=ûʼ mail_from= mail_date= mail_subject= mail_to= mail_cc=ת mail_bcc= mail_pri=ȼ mail_highest= mail_high= mail_normal=һ mail_low= mail_lowest= mail_for= $1 mail_for2=û$1 mail_sent=ڷʼб mail_size=С mail_delete=ɾѡʼ mail_compose=дʼ mail_return=û mail_ecannot=ûĶûʼȨ mail_all=ȫѡ mail_invert=ѡȡ mail_search=Ѱʼ mail_body= mail_match=ƥ mail_ok= mail_nonefrom= mail_mark=ѡеʼΪ mail_mark0=δĶ mail_mark1=Ķ mail_mark2=ر mail_forward=תѡ mail_rfc=ļ view_title=Ķʼ view_desc=$2еʼ$1 view_desc2=û$2ʼ$1 view_desc3=ʼ$1 view_sent=ѷʼбеʼ$1 view_qdesc=ʼ $1 view_headers=ʼͷ view_allheaders=鿴ʼͷ view_noheaders=쿴ʼͷ view_attach= view_reply=ظ view_reply2=ظ view_enew=༭ʼ view_forward=ת view_delete=ɾ view_strip=Ƴ view_ecannot=ûĶûʼȨ view_mark0=δĶ view_mark1=Ķ view_mark2=ر view_return=ԭ view_sub=иʼ compose_title=дʼ reply_title=ظʼ forward_title=תʼ reply_headers=ʼͷ reply_attach=תĸ reply_mailforward=תʼ reply_attach2=ͻ˺ͷĸ reply_send= reply_ecannot=ûûݷʼȨ send_err=޷ʼ send_eto=δ롰ַ send_efrom=ʧԡַ send_title=ѷ͵ʼ send_ok=ʼѳɹ͵ $1 send_ecannot=ûûݷʼȨ send_esmtp=SMTP $1 ʧܣ$2 send_eattach=Сܳ $1 kB send_eperms=û $1 Ķ $2 send_eperms2=ûзļ$1Ȩ send_epath=Sendmail $1ڡ delete_ecannot=ûɾûʼȨ delete_enone=ûѡҪɾʼ delete_emnone=ûѡҪǵʼ search_title= search_ecannot=ûûʼȨ search_ematch=ٴƥı search_none=Ҳʼ search_results2=$1ʼƥ$2 search_results3=$1ʼƥ$2 acl_none= acl_same=ͬû acl_all= acl_read=Ķʼû acl_users=û acl_userse=û acl_usersg=ijԱ acl_from=ԡַ acl_any=κεַ acl_fdoms= @ acl_faddrs=гĵַ acl_fdom=κεַ @ acl_fromname=Դַ acl_apath=ļͳĿ¼ acl_attach=󸽼ܴС acl_sent=дѷ͵ʼ acl_canattach=ճļ acl_usersm=ƥû acl_asame=ûͬ log_delmail=Ѵ $2 ɾ $1ʼ log_send=ѷʼ $1 mailboxes/lang/zh_TW.Big50100664000567100000120000001642710153206067015222 0ustar jcameronwheelacl_all= acl_any=l} acl_apath=ɮשM{ؿ acl_asame=PϥΪ̬ۦP acl_attach=̤j`jp acl_canattach=iH[AɶܡH acl_candetach=iHaɮרA? acl_faddrs=CXl} acl_fdom=l}b acl_fdoms=Hcb acl_from=̾ڶl}\ acl_fromname=ӷa}uW acl_none=L acl_read=iHŪǨϥΪ̪l acl_same=PWϥΪ acl_sent=blcxswoel acl_users=uϥΪ acl_userse=, FϥΪ acl_usersg=ժ acl_usersm=ŦXϥΪ acl_usersu=bUIDd compose_title=g@qll confirm_ok={bR confirm_title=T{R confirm_warn=zTwnR $1 ʿT? confirm_warn2=]zHcjpP榡Aݭn@IɶARA|Lʧ@ confirm_warn3=zTwnRT confirm_warn4=RA|Lʧ@C confirm_warnall=zTwnRƧҦT? delete_ecannot=zQ\RoӨϥΪ̪l delete_ecopycannot=zQ\ƻslSwϥΪ delete_ecopynone=ƻsl delete_ecopyuser=ƻslϥΪ̤sb delete_efnone=Hl delete_emnone=SܭnаOl delete_emovecannot=zQ\ʶlSwϥΪ delete_emovenone=ﲾʱHl delete_emoveuser=ϥΪ̲ʶl󤣦sb delete_enone=SܭnRl delete_nobutton=s delete_ok={bR delete_rusure=zTwnq$2R $1 ʿT?jɮתlݭn@ǮɶARA|Lʧ@C delete_rusure2=zTwnR $1 ʿT?jɮתlݭn@ǮɶARA|Lʧ@C delete_title=Rl detach_edir=SJxsɮשΥؿ detach_eopen=}l$1:$2 detach_err=[ɮץ detach_ewrite=g$1:$2 detach_ok=qAݪ[ɮ$1($2) detach_title=[ɮ enew_title=sl find_enone=SzjMҲŦXϥΪ find_group=s find_home=aؿ find_real=uW find_results=jM$1ŦXϥΪ.. find_size=ljp find_title=jMG find_user=ϥΪ̦W folder_drafts=Z folder_inbox= folder_sent=ǰel folder_trash=U forward_title=Hqll index_contains=]t index_empty=Ll index_equals= index_esystem=bztΤW䤣䴩lA(Qmail, Postfix M Sendmail)AziHʽվҲղպAӳ]wlAMl| index_esystem2=bztΤW䤣ҲղպA]wlAAzݭnվ㥿TAպAC index_find=bϥΪ̦W٤MϥΪ index_header=ϥΪ̫Hc index_none=zQ\󦹨tΤWϥΪŪl index_return=Sendmail պA index_system0=lA:Postfix index_system1=lA:Sendmail index_system2=lA:Qmail index_title=Sendmail պA index_toomany=bztΤWӦhϥΪ̡AҥHLkPܦb@W log_copymail=q $2 $3 ƻs$1ʰT log_delmail=wq $2 R $1l log_movemail=q $2 $3 $1ʰT log_send=woel $1 mail_addresses=޲zpH mail_advanced=ijM mail_all=ܥ mail_bcc=ðƥ mail_body= mail_cc=ƥ۰e mail_compose=g@sl mail_copy=ƻs: mail_crypt=GnuPG[K: mail_date= mail_delall=R mail_delete=Rܪl mail_deltrash=ũU mail_ecannot=zQ\ŪoӨϥΪ̪l mail_eexists=TsbF! mail_err=ƧlCoͤ@ӿ~ : $1 mail_fchange=ܧ mail_folder=Ƨ mail_folders=޲zƧ mail_for=b $1 mail_for2=ΩϥΪ$1 mail_forward=Hwܪ mail_from=HH mail_high= mail_highest=̰ mail_invert=ϦV mail_jump=ܭ: mail_login=nJ mail_logindesc=zblD$1W
JϥΪ̦W٩MKXӶiJHc mail_loginheader=POP3nJA mail_loginmailbox=IMAPHc mail_loginpass=KX mail_loginuser=ϥΪ̦W mail_logout=ܧPOP3nJ mail_logout2=ܧIMAPnJ mail_low=C mail_lowest=̧C mail_mark=NlаOG mail_mark0=\Ū mail_mark1=\Ū mail_mark2=SO mail_match=ŦX mail_move=: mail_nocrypt=<sX> mail_none=HcSl mail_nonefrom=L mail_normal=@ mail_nosign=<ñ> mail_of= mail_ok=jM mail_pos=l $1 $2 @ $3 mail_pri=u mail_replyto=^ mail_reset=M mail_return=ϥΪ̹qll mail_return2=ϥΪ̶l mail_rfc=HH mail_samecrypt=<_qتm> mail_search=Ml, 䤤 mail_search2=jM: mail_sent=boelC mail_sig=sñW mail_sign=GnuPG[K: mail_size=jp mail_subject=DD mail_title=ϥΪ̹qll mail_to=H reply_attach=H󧨱a reply_attach2=󧨱a reply_body=Tr reply_draft=sܯZ reply_ecannot=zQ\HoӨϥΪ̦WٰeXl reply_headers=lY reply_mailforward=wHl reply_send=eX reply_spell=rˬd? reply_title=^Шqll search_all=bҦƧ search_ecannot=zQ\jMoӨϥΪ̪l search_efield=zjM search_ematch=zJjM search_enone=J search_ewhat=JC$1ŦXr search_local=baƧ search_none=䤣ŦXl. search_results2=$1lŦX$2 search_results3=$1l󤣲ŦX$2 search_results4=$1ʶlTŦXzjM search_title=jMG send_draft=H$1xsZƧ send_eattach=jp`XWL $1 kBC send_eattachsize=l[ɶWL\̤jjp$1 줸 send_ecannot=zQ\HoӨϥΪ̦WٰeXl send_ecrypt=TsX:$1 send_efile=\Ūa$1 : $2 send_efrom=򥢱HHl} send_ekey=bl$1䤣_ send_eline=bu$1W: send_epass=zT@ƦñA]z|]wGunPGҲո̪qX send_epath=Sendmail{ $1sbC send_eperms=ϥΪ $1 \Ū $2 send_eperms2=zQ\oe$1 send_err=leX send_esign=ƦñT: $1 send_esmtp=SMTP RO $1 : $2 send_espell=bzTUCr~ .. send_eto=򥢦Hl} send_eword=r$1 send_eword2=r$1 - iॿTO $2 send_ok=l󦨥\e $1 send_title=eXl sform_all=<ҦƧ> sform_and=UCŦXҦT .. sform_body=Te sform_cc=ƥ: Y sform_date=:Y sform_folder=bƧ sform_from=q:Y sform_headers=Y sform_local=<aƧ> sform_neg0=]t sform_neg1=]t sform_ok= sform_or=UCŦX@T .. sform_return=ijM sform_size=Tjp sform_subject=D: Y sform_text=br sform_title=ijM sform_to=H: Y sform_where= view_allheaders=dݩҦlY view_ashtml=˵HTML view_astext=˵r view_attach=󧨱a view_black=H view_body=Tr view_crypt=GnuPGlѱK view_crypt_1=Tw[KAGnuPG䴩|w view_crypt_2=ѱKT: $1 view_crypt_3=l󦨥\ѱK view_crypt_4=[KO@l󦨥\ѱK view_dall=<Ҧɮ> view_delete=R view_desc=l $1 b $2 view_desc2=ϥΪ$2l$1 view_desc3=l$1 view_detach=[ɮ: view_diagnostic-code=ѭ] view_dir=AɮשΥؿ view_dstatus=ǰeA view_ecannot=zQ\ŪoӨϥΪ̪l view_egone=Tsb view_enew=ssl view_final-recipient=̫᦬ view_folder=^Hc view_forward=H view_gnupg=GnuPG{ñ view_gnupg_0=$1ñT{ view_gnupg_1=$1ñġALkإߩU view_gnupg_2=$1ñ|T{ view_gnupg_3=zM椤L_$1AҥHñL view_gnupg_4=T{ñ view_headers=lY view_mark=аO: view_mark0=\Ū view_mark1=\Ū view_mark2=SO view_noheaders=ݰ򥻶lY view_print=CL view_qdesc=Cl $1 view_raw=˵lT view_razor=^Razor view_recv=q_Do_$1. view_remote-mta=ݶlA view_reply=^ view_reply2=^е view_reporting-mta=^lA view_return=ll view_sent=woelCl$1 view_strip= view_sub=al view_title=Ūqll mailboxes/lang/zh_CN.UTF-80100664000567100000120000000606510420075004015172 0ustar jcameronwheelmail_title=用户邮件 mail_from=来自 mail_date=日期 mail_subject=主题 mail_to=发往 mail_cc=转送 mail_bcc=密送 mail_pri=优先级 mail_highest=最高 mail_high=高 mail_normal=一般 mail_low=低 mail_lowest=最低 mail_for=在 $1 mail_for2=用于用户$1 mail_sent=在发送邮件列表中 mail_size=大小 mail_delete=删除选定的邮件 mail_compose=编写新邮件 mail_return=用户邮箱 mail_ecannot=您没有阅读该用户的邮件的权限 mail_all=全部选中 mail_invert=逆向选取 mail_search=寻找邮件,其中 mail_body=正文 mail_match=匹配 mail_ok=搜索 mail_nonefrom=无 mail_mark=将已选中的邮件标记为: mail_mark0=未阅读 mail_mark1=阅读 mail_mark2=特别 mail_forward=转发已选择的 mail_rfc=寄件人行 view_title=阅读邮件 view_desc=$2中的邮件$1 view_desc2=用户$2的邮件$1 view_desc3=邮件$1 view_sent=已发送邮件列表中的邮件$1 view_qdesc=待发的邮件 $1 view_headers=邮件头 view_allheaders=查看所有邮件头 view_noheaders=察看基本邮件头 view_attach=附件 view_reply=回复 view_reply2=回复给所有 view_enew=编辑新邮件 view_forward=转发 view_delete=删除 view_strip=移除附件 view_ecannot=您没有阅读该用户的邮件的权限 view_mark0=未阅读 view_mark1=阅读 view_mark2=特别 view_return=原件 view_sub=带有附件的邮件 compose_title=编写邮件 reply_title=回复邮件 forward_title=转发邮件 reply_headers=邮件头 reply_attach=转发的附件 reply_mailforward=已转发的邮件 reply_attach2=客户端和服务器的附件 reply_send=发送 reply_ecannot=您没有以这个用户的身份发送邮件的权限 send_err=无法发送邮件 send_eto=未输入“发往”地址 send_efrom=丢失“来自”地址 send_title=已发送的邮件 send_ok=邮件已成功发送到 $1 send_ecannot=您没有以这个用户的身份发送邮件的权限 send_esmtp=SMTP 命令 $1 失败:$2 send_eattach=附件大小总量不能超过 $1 kB。 send_eperms=用户 $1 不能阅读 $2 send_eperms2=您没有发送文件$1的权限 send_epath=Sendmail程序 $1不存在。 delete_ecannot=您没有删除这个用户的邮件的权限 delete_enone=没选择要删除的邮件 delete_emnone=没有选择要标记的邮件 search_title=搜索结果 search_ecannot=您没有搜索该用户的邮件的权限 search_ematch=您必须再次输入匹配的文本。 search_none=找不到邮件。 search_results2=$1邮件匹配$2 search_results3=$1邮件不匹配$2 acl_none=无 acl_same=同名的用户 acl_all=所有 acl_read=可阅读其邮件的用户 acl_users=仅限用户 acl_userse=所有用户除了 acl_usersg=组的成员 acl_from=允许“来自”地址 acl_any=任何地址 acl_fdoms=邮箱 @ 域 acl_faddrs=列出的地址 acl_fdom=任何地址 @ 域 acl_fromname=来源地址的真名 acl_apath=限制文件和程序到目录 acl_attach=最大附件总大小 acl_sent=在邮箱中储存已发送的邮件 acl_canattach=可以粘附服务器文件吗? acl_usersm=匹配的用户 acl_asame=与用户相同 log_delmail=已从 $2 删除 $1邮件 log_send=已发送邮件到 $1 mailboxes/lang/ja_JP.UTF-80100664000567100000120000000577010420075004015156 0ustar jcameronwheelmail_title=ユーザ E メール mail_from=送信元 mail_date=日付 mail_subject=件名 mail_to=宛先 mail_pri=優先度 mail_highest=最優先 mail_high=高 mail_normal=標準 mail_low=低 mail_lowest=最後 mail_for=$1 内 mail_sent=送信済みメール リスト内 mail_size=サイズ mail_delete=選択されたメッセージを削除 mail_compose=新規メールを作成 mail_return=ユーザ E メール mail_ecannot=このユーザーのメールは読めません mail_all=すべて選択 mail_invert=選択の反転 mail_search=メッセージの検索 mail_body=本文 mail_match=一致 mail_ok=検索 mail_nonefrom=なし view_title=E メールを読む view_desc=$2のメッセージ $1 view_sent=送信済みメール リストのメッセージ $1 view_qdesc=キューされたメッセージ $1 view_headers=メール ヘッダ view_attach=添付ファイル view_reply=返信 view_reply2=全員に返信 view_enew=新規として編集 view_forward=転送 view_delete=削除 view_ecannot=このユーザーのメールは読めません compose_title=E メールの作成 reply_title=E メールへの返信 forward_title=E メールの転送 reply_headers=メール ヘッダ reply_attach=転送された添付ファイル reply_attach2=添付ファイル reply_send=送信 reply_ecannot=このユーザとしてはメールを送信できません send_err=メールを送信できませんでした send_eto=To (宛先)アドレスがありません send_efrom=From (送信者) アドレスがありません send_title=送信されたメール send_ok=$1 へのメールの送信を完了しました send_ecannot=このユーザとしてはメールを送信できません send_esmtp=SMTP コマンド $1 が失敗しました: $2 send_eattach=添付ファイルのサイズは $1 KB を越えられません。 send_eperms=ユーザ $1 は $2 を読み取れません send_eperms2=ファイル $1 は送信できません delete_ecannot=このユーザからのメールを削除できます delete_enone=削除するメッセージが選択されていません search_title=検索結果 search_ecannot=このユーザのメールは検索できません search_ematch=検索するにはテキストを入力する必要があります。 search_none=メッセージが見つかりませんでした。 acl_none=なし acl_same=同名のユーザ acl_all=すべて acl_read=メールを読み取れるユーザ acl_users=次のユーザのみ acl_userse=次のユーザ以外すべて acl_usersg=グループのメンバー acl_from=アドレスから許可 acl_any=任意のアドレス acl_fdoms=メールボックス @ ドメイン acl_faddrs=リストされたアドレス acl_fdom=任意のアドレス @ ドメイン acl_apath=ディレクトリへのファイルとプログラムを制限 acl_attach=添付ファイルの合計サイズの最大値 acl_sent=送信済みメールをメールボックスに保存 log_delmail=$1 メッセージを $2 から削除しました log_send=$1 にメールを送信しました mailboxes/lang/ko_KR.UTF-80100664000567100000120000000541710420075004015176 0ustar jcameronwheelmail_title=紫遂切 穿切 五析 mail_from=降重切 mail_date=劾促 mail_subject=薦鯉 mail_to=呪重切 mail_cc=凧繕 mail_bcc=需精 凧繕 mail_pri=酔識 授是 mail_highest=亜舌 株製 mail_high=株製 mail_normal=左搭 mail_low=碍製 mail_lowest=亜舌 碍製 mail_for=$1 mail_sent=降重 五析 鯉系 mail_size=滴奄 mail_delete=識澱廃 五獣走 肢薦 mail_compose=歯 五析 拙失 mail_return=紫遂切 穿切 五析 mail_ecannot=戚 紫遂切税 穿切 五析聖 石聖 呪 蒸柔艦陥 mail_all=乞砧 識澱 mail_invert=鋼企稽 識澱 mail_search=五獣走 伊事 是帖 mail_body=沙庚 mail_match=析帖 mail_ok=伊事 mail_nonefrom=蒸製 view_title=穿切 五析 石奄 view_desc=$2拭 赤澗 五獣走 $1 view_sent=降重 五析 鯉系拭 赤澗 五獣走 $1 view_qdesc=企奄伸拭 赤澗 五獣走 $1 view_headers=五析 伯希 view_attach=歎採 督析 view_reply=噺重 view_reply2=穿端 噺重 view_enew=歯 五析稽 畷増 view_forward=穿含 view_delete=肢薦 view_ecannot=戚 紫遂切税 穿切 五析聖 石聖 呪 蒸柔艦陥 compose_title=穿切 五析 拙失 reply_title=穿切 五析拭 噺重 forward_title=穿切 五析 穿含 reply_headers=五析 伯希 reply_attach=穿含吉 歎採 督析 reply_attach2=歎採 督析 reply_send=穿勺 reply_ecannot=戚 紫遂切稽 五析聖 穿勺拝 呪 蒸柔艦陥 send_err=五析聖 穿勺馬走 公梅柔艦陥 send_eto=蒸澗 呪重切 爽社 send_efrom=蒸澗 降重切 爽社 send_title=五析 穿勺 刃戟 send_ok=$1拭 五析聖 穿勺梅柔艦陥. send_ecannot=戚 紫遂切稽 五析聖 穿勺拝 呪 蒸柔艦陥 send_esmtp=SMTP 誤敬 $1 叔鳶: $2 send_eattach=歎採 督析税 恥 滴奄澗 $1KB研 段引拝 呪 蒸柔艦陥. send_eperms=紫遂切 $1精(澗) $2聖(研) 石聖 呪 蒸柔艦陥 send_eperms2=督析 $1聖(研) 左馨 呪 蒸柔艦陥 delete_ecannot=戚 紫遂切稽採斗 閤精 五析聖 肢薦拝 呪 蒸柔艦陥 delete_enone=肢薦拝 五析聖 識澱馬走 省紹柔艦陥 search_title=伊事 衣引 search_ecannot=戚 紫遂切税 穿切 五析聖 伊事拝 呪 蒸柔艦陥 search_ematch=伊事拝 努什闘研 脊径背醤 杯艦陥. search_none=五獣走亜 蒸柔艦陥. acl_none=蒸製 acl_same=戚硯戚 疑析廃 紫遂切 acl_all=乞砧 acl_read=石聖 呪 赤澗 五析聖 左鎧澗 紫遂切 acl_users=紫遂切幻 acl_userse=紫遂切研 薦須廃 乞砧 acl_usersg=益血 姥失据 acl_from=買遂 亜管廃 降重切 爽社 acl_any=績税税 爽社 acl_fdoms=紫辞敗@亀五昔 acl_faddrs=蟹伸吉 爽社 acl_fdom=績税税 爽社@亀五昔 acl_apath=巨刑塘軒拭 企廃 督析 貢 覗稽益轡 薦廃 acl_attach=穿端 歎採 督析税 置企 滴奄 acl_sent=紫辞敗拭 降重 五析 煽舌 log_delmail=$2拭辞 $1鯵 五獣走 肢薦喫 log_send=$1拭惟 五析 穿勺 刃戟 mailboxes/module.info0100664000567100000120000000052110446424443014671 0ustar jcameronwheeldesc=Read User Mail category=servers longdesc=Read email in users' mailboxes. desc_de=Lese Benutzer-E-Mail desc_zh_TW.Big5=ŪϥΪ̶l desc_ca=Lectura del Correu d'Usuaris desc_fr=Lecture du Courrier des Usagers readonly=1 os_support=!windows desc_es=Lectura de Correo de Usuarios desc_zh_TW.UTF-8=讀取使用者郵件 version=1.281 mailboxes/index.cgi0100775000567100000120000000542310415576045014335 0ustar jcameronwheel#!/usr/local/bin/perl # index.cgi # Display all users on the system require './mailboxes-lib.pl'; if ($config{'mail_system'} == 3) { # Need to detect mail server $ms = &detect_mail_system(); if ($ms == 3) { &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1); &ui_print_endpage(&text('index_esystem', "../config.cgi?$module_name")); } else { $config{'mail_system'} = $ms; &save_module_config(); } } elsif (!$config{'send_mode'} || !$config{'auto'}) { # Make sure mail system is valid local ($ms) = grep { $_->[1] == $config{'mail_system'} } @mail_system_modules; if (!&check_mail_system($ms)) { &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1); &ui_print_endpage(&text('index_esystem2', "../config.cgi?$module_name")); } } # Make sure mail system is running $err = &test_mail_system(); if ($err) { &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1); &ui_print_endpage(&text('index_esystem3', "../config.cgi?$module_name", $err)); } # Show main page header &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0, undef, undef, undef, $text{'index_system'.$config{'mail_system'}}); # Check for Perl modules for SMTP authentication if ($config{'smtp_user'}) { local @needed = ( "Authen::SASL" ); local $smode = $config{'smtp_auth'} || "Cram-MD5"; $smode = uc($smode); $smode =~ s/-/_/g; push(@needed, "Authen::SASL::Perl::$smode"); foreach $n (@needed) { eval "use $n"; if ($@) { &ui_print_endpage( "

".&text('index_eperl', "$n", "/cpan/download.cgi?source=3&cpan=$n&mode=2&". "return=/$module_name/&returndesc=". &urlize($text{'index_return'}))."

\n". "$text{'index_eperl2'}\n". "

$@
\n"); } } } # Build a list of all available users @users = &list_mail_users($config{'max_records'}); @users = grep { &can_user(@$_) } @users; $form = 0; if (!@users) { # No users! print "$text{'index_none'}

\n"; } elsif ($config{'max_records'} && @users > $config{'max_records'}) { # Show input for searching for a user print $text{'index_toomany'},"

\n"; print &ui_form_start("find.cgi"); print &ui_submit($text{'index_find'}),"\n"; print &ui_select("match", undef, [ [ "0", $text{'index_equals'} ], [ "1", $text{'index_contains'} ] ]),"\n"; print &ui_user_textbox("user"),"\n"; print &ui_form_end(); $form++; } else { # Show using selected mode and sort &show_users_table(\@users, $config{'show_mail'}); } if (&allowed_directory()) { # Show form to view any mail file print "

\n"; print &ui_form_start("list_mail.cgi"); print &ui_submit($text{'index_file'}),"\n"; print &ui_textbox("user", undef, 40),"\n", &file_chooser_button("user", $form),"
\n"; print &ui_form_end(); } &ui_print_footer("/", $text{'index'}); mailboxes/config0100664000567100000000000000130710437653574013607 0ustar jcameronrootmax_records=200 show_size=1 show_size_below=0 mail_system=3 auto=1 mail_dir=/var/mail mail_style=0 mail_file=Mailbox mail_dir=Maildir wrap_width=80 perpage=20 track_read=0 show_to=0 sort_mode=1 index_min=1000000 fwd_mode=0 delete_warn=y index_dbm=2 top_buttons=2 view_html=0 mail_usermin=mail sync_create=0 sync_modify=1 sync_delete=1 size_mode=1 no_crlf=0 sync_perms=0600 show_mail=0 html_edit=0 check_mod=1 spam_buttons=mail show_delall=0 spam_del=0 spam_report= mailbox_user=.usermin/mailbox vpopmail_dir=/home/vpopmail html_quote=0 log_read=0 from_virtualmin=1 show_count=0 show_sent=0 sig_file=* show_body=0 column_count=4 ignore_users= ignore_users_enabled=0 link_mode=0 date_fmt=dmy arrows=1 open_mode=0 mailboxes/config.info0100664000567100000000000001103710437653562014537 0ustar jcameronrootline0=Configurable options,11 wrap_width=Width to wrap mail messages at,0,6 perpage=Mail messages to display per page,0,6 track_read=Keep track of read/unread emails,1,1-Yes,0-No show_to=Show To: address in mailboxes?,1,1-Yes,0-No max_records=Maximum number of users to display,0,6 top_buttons=Show buttons at top for,1,2-Mailboxes and mails,1-Mailboxes only,0-Never arrows=Show pager arrows at bottom for,1,2-Mailboxes and mails,1-Mailboxes only,0-Never show_delall=Show button to delete entire mailbox?,1,1-Yes,0-No show_size=User display mode,1,0-Username only,1-Username and size,2-Full details show_size_below=       Username and size - Where to display size,1,0-To the right of username,1-Below the username column_count=Number of columns in which to display usernames,1,3-3,4-4,5-5,6-6,7-7,8-8,9-9 ignore_users=Ignore these usernames (do not show),15,userIgnoreList ignore_users_enabled=        Ignore list status,1,1-Enabled,0-Disabled show_count=Show number of messages in inbox?,1,1-Yes,0-No show_sent=Show number of messages in sent mail folder?,1,1-Yes,0-No sort_mode=Sort mailboxes by,1,2-Size,1-Username,0-Order in password file show_mail=Only show users who have mail?,1,1-Yes,0-No size_mode=Include all folders in size?,1,1-Yes,0-No (first folder only) fwd_mode=Forward messages with quoting?,1,0-Yes,1-No delete_warn=Ask for confirmation before deleting?,10,y-Yes,n-No,For mbox files larger than index_dbm=Indexing type,1,2-DBM,0-Text file index_min=Minimum mail file size to index,3,Always index view_html=Show message body as,4,0-Always plain text,1-Text if possible, HTML otherwise,2-HTML if possible, text otherwise,3-Convert HTML to plain text html_edit=Use HTML editor for composing?,1,2-Always,1-When replying to HTML email,0-Never html_quote=HTML quoting mode,1,1-Message below <hr>,0-Message inside <blockquote> check_mod=Check for mailbox modification when deleting mail?,1,1-Yes,0-No log_read=Record the reading of mail in the Webmin Actions Log?,1,1-Yes,0-No bcc_to=Bcc: sent messages to,0 sig_file=Signature file,10,*-None,.signature-~/.signature,Other file show_body=Show message body previews in list?,1,1-Yes,0-No open_mode=Open messages in,1,1-New window,0-List window link_mode=Open links in,1,1-New window,0-Same window download=Attachment MIME types to always download,9,20,4,\t date_fmt=Date format in mail list,1,dmy-DD/MM/YYYY,mdy-MM/DD/YYYY,ymd-YYYY/MM/DD date_tz=Timezone for date displays,3,System default line3=Spam options,11 spam_buttons=Show spam reporting buttons for,2,list-Mailboxes,mail-Messages spam_del=Delete spam when reporting?,1,1-Yes,0-No spam_report=Report spam using,1,sa_learn-sa-learn --spam,spamassassin-spamassasin -r,-Decide automatically line3.5=From address options,11 from_addr=From: address to use when sending email manually,3,From mailbox username webmin_from=From: address to use when Webmin sends email,3,Default (webmin@yourhost) from_virtualmin=Get From: address from Virtualmin?,1,1-Yes,0-No from_dom=Domain to use in From: address,3,System hostname line1=System configuration,11 mail_system=Mail server installed,4,1-Sendmail,0-Postfix,2-Qmail,4-Qmail+LDAP,5-Qmail+VPopMail,3-Detect automatically send_mode=Send mail using,10,-Mail server program,SMTP server no_crlf=Add carriage return ( \r ) to each line?,1,0-Yes,1-No smtp_user=SMTP login name for mail server,3,None smtp_pass=SMTP password for mail server,3,None smtp_auth=SMTP authentication method,4,-Default,Cram-MD5-Cram-MD5,Digest-MD5-Digest-MD5,Plain-Plain,Login-Login auto=Detect location of mail files automatically?,1,1-Yes, based on mail server,0-No, use settings below .. mail_dir=User mail file directory,3,None mail_style=Mail file directory style,4,0-mail/username,1-mail/u/username,2-mail/u/us/username,3-mail/u/s/username mail_file=Mail file in user home directories,3,None mail_sub=Mail directory in user home directories,3,None mail_usermin=Usermin-style folders subdirectory in home directory,3,None mailbox_user=Usermin Read Mail configuration directory in home directory,3,None line2=User synchronization,11 sync_create=Create mailbox when user is created?,1,1-Yes,0-No sync_modify=Rename mailbox when user is renamed?,1,1-Yes,0-No sync_delete=Delete mailbox when user is deleted?,1,1-Yes,0-No sync_perms=Permissions for new mailboxes,0,4 line4=VPOPMail options,11 vpopmail_dir=Base directory for VPOPMail,0 line5=Qmail+LDAP options,11 ldap_host=LDAP server,0 ldap_port=LDAP port,3,Default ldap_login=Login for LDAP server,0 ldap_pass=Password for LDAP server,0 ldap_base=Base for mail users,0 mailboxes/mailboxes-lib.pl0100664000567100000000000006451710437660616015512 0ustar jcameronroot# mailboxes-lib.pl # Common functions for reading user mailboxes do '../web-lib.pl'; do '../ui-lib.pl'; do 'boxes-lib.pl'; do 'folders-lib.pl'; &init_config(); %access = &get_module_acl(); $config{'perpage'} ||= 20; $gconfig{'logfiles'} = 0; # file change logging never needs to be done # Always detect the mail system if not set if ($config{'mail_system'} == 3) { $config{'mail_system'} = &detect_mail_system(); &save_module_config() if ($config{'mail_system'} != 3); } # send_mail_program(from, to) # Returns the command for injecting email, based on the mail system in use sub send_mail_program { if ($config{'mail_system'} == 1 || $config{'mail_system'} == 0) { # Use sendmail executable, or postfix wrapper local %sconfig = &foreign_check("sendmail") && $config{'mail_system'} == 1 ? &foreign_config("sendmail") : ( ); local $cmd = &has_command($sconfig{'sendmail_path'} || "sendmail"); return "$cmd -t -f".quotemeta($_[0]) if ($cmd); } elsif ($config{'mail_system'} == 2) { # Use qmail injector local %qconfig = &foreign_check("qmailadmin") ? &foreign_config("qmailadmin") : ( ); local $cmd = ($qconfig{'qmail_dir'} || "/var/qmail"). "/bin/qmail-inject"; return $cmd if (-x $cmd); } else { # Fallback - use sendmail command local $cmd = &has_command("sendmail"); return "$cmd -t -f".quotemeta($_[0]) if ($cmd); } return undef; } # list_folders() # Returns a list of all mailboxes for all users sub list_folders { local (@rv, $uinfo); foreach $uinfo (&list_mail_users()) { push(@rv, &list_user_folders(@$uinfo)); } return @rv; } # list_user_folders(user, [other info]) # Returns a list of folders for mailboxes belonging to some user sub list_user_folders { if ($_[0] =~ /^\//) { # A path .. return a folder just for it return ( { 'name' => $_[0], 'file' => $_[0], 'type' => &folder_type($_[0]), 'mode' => 1, 'index' => 0 } ); } else { # Getting folders for a user local @uinfo = @_ > 1 ? @_ : &get_mail_user($_[0]); return ( ) if (!@uinfo); local ($dir, $style, $mailbox, $maildir) = &get_mail_style(); local @rv; # Check for user-specified mail store if ($uinfo[10]) { push(@rv, { 'name' => $uinfo[10], 'file' => $uinfo[10], 'type' => &folder_type($uinfo[10]), 'mode' => 0, 'index' => scalar(@rv) } ); } # Check for /var/mail/USERNAME file if ($dir) { local $mf = &mail_file_style($uinfo[0], $dir, $style); push(@rv, { 'type' => 0, 'name' => $mf, 'file' => $mf, 'user' => $uinfo[0], 'index' => scalar(@rv) }); } # Check for file in home dir if ($mailbox) { local $mf = "$uinfo[7]/$mailbox"; if (-r $mf || !@rv) { push(@rv, { 'type' => 0, 'name' => $mf, 'file' => $mf, 'user' => $uinfo[0], 'index' => scalar(@rv) }); } } # Check for directory in home dir if ($maildir) { local $mf = "$uinfo[7]/$maildir"; if (-d $mf || !@rv) { push(@rv, { 'type' => 1, 'name' => $mf."/", 'file' => $mf, 'user' => $uinfo[0], 'index' => scalar(@rv) }); } } # Add any ~/mail files if ($config{'mail_usermin'}) { local $folders_dir = "$uinfo[7]/$config{'mail_usermin'}"; foreach $p (&recursive_files($folders_dir, 1)) { local $f = $p; $f =~ s/^\Q$folders_dir\E\///; push(@rv, { 'name' => $p, 'file' => $p, 'type' => &folder_type($p), 'mode' => 0, 'sent' => $f eq "sentmail", 'index' => scalar(@rv) } ); } } # Add any Usermin external mail files if ($config{'mailbox_user'}) { local %userconfig; &read_file_cached("$uinfo[7]/$config{'mailbox_user'}/config", \%userconfig); local $o; foreach $o (split(/\t+/, $userconfig{'mailboxes'})) { $o =~ /\/([^\/]+)$/ || next; push(@rv, { 'name' => $o, 'file' => $o, 'type' => &folder_type($o), 'mode' => 1, 'index' => scalar(@rv) } ); } } return @rv; } } sub list_user_folders_sorted { return &list_user_folders(@_); } # get_mail_style() # Returns a list containing the mail base directory, directory style, # mail file in home dir, and maildir in home dir sub get_mail_style { if (!defined(@mail_style_cache)) { if ($config{'auto'}) { # Based on mail server if ($config{'mail_system'} == 1) { # Can get paths from Sendmail module config local %sconfig = &foreign_config("sendmail"); if ($sconfig{'mail_dir'}) { return ($sconfig{'mail_dir'}, $sconfig{'mail_style'}, undef, undef); } else { return (undef, $sconfig{'mail_style'}, $sconfig{'mail_file'}, undef); } } elsif ($config{'mail_system'} == 0) { # Need to query Postfix module for paths &foreign_require("postfix", "postfix-lib.pl"); local @s = &postfix::postfix_mail_system(); if ($s[0] == 0) { return ($s[1], 0, undef, undef); } elsif ($s[0] == 1) { return (undef, 0, $s[1], undef); } elsif ($s[0] == 2) { return (undef, 0, undef, $s[1]); } } elsif ($config{'mail_system'} == 2 || $config{'mail_system'} == 4) { # Need to check qmail module config for paths local %qconfig = &foreign_config("qmailadmin"); if ($qconfig{'mail_system'} == 1) { return (undef, 0, undef, $qconfig{'mail_dir_qmail'}); } elsif ($qconfig{'mail_dir'}) { return ($qconfig{'mail_dir'}, $qconfig{'mail_style'}, undef, undef); } else { return (undef, $qconfig{'mail_style'}, $qconfig{'mail_file'}, undef); } } elsif ($config{'mail_system'} == 5) { # vpopmail always uses ~/Maildir return ( undef, 0, undef, "Maildir" ); } else { # No mail server set yet! return (undef, undef, undef, undef); } } else { # Use config settings @mail_style_cache = ($config{'mail_dir'}, $config{'mail_style'}, $config{'mail_file'}, $config{'mail_sub'}); } } return @mail_style_cache; } # can_user(username, [other details]) sub can_user { if (!&is_user($_[0])) { # For external files, check if the file is under an allowed # directory, or owned by an allowed user. local @st = stat($_[0]); local @uinfo = &get_mail_uid($st[4]); return 1 if (@uinfo && &can_user(@uinfo)); local $dir = &allowed_directory(); return defined($dir) && &is_under_directory($dir, $_[0]); } local @u = @_ > 1 ? @_ : &get_mail_user($_[0]); return 1 if ($_[0] && $access{'sent'} eq $_[0]); return 1 if ($access{'mmode'} == 1); return 0 if (!@u); return 0 if ($_[0] =~ /\.\./); return 0 if ($access{'mmode'} == 0); local $u; if ($access{'mmode'} == 2) { # Is user in list of users? foreach $u (split(/\s+/, $access{'musers'})) { return 1 if ($u eq $_[0]); } return 0; } elsif ($access{'mmode'} == 4) { # Is user the current Webmin user? return 1 if ($_[0] eq $remote_user); } elsif ($access{'mmode'} == 5) { # Is the user's gid in the list of groups? local $gid; foreach $gid (split(/\s+/, $access{'musers'})) { return 1 if ($u[3] eq $gid); if ($access{'msec'}) { # Check user's secondary groups too local @ginfo = getgrgid($gid); local @m = split(/\s+/, $ginfo[3]); return 1 if (&indexof($_[0], @m) >= 0); } } } elsif ($access{'mmode'} == 3) { # Is the user not in the list of denied users foreach $u (split(/\s+/, $access{'musers'})) { return 0 if ($u eq $_[0]); } return 1; } elsif ($access{'mmode'} == 6) { # Does the user match a regexp? return ($_[0] =~ /^$access{'musers'}$/); } elsif ($access{'mmode'} == 7) { # Is the user's UID within the allowed range? return (!$access{'musers'} || $u[2] >= $access{'musers'}) && (!$access{'musers2'} || $u[2] <= $access{'musers2'}); } return 0; # can't happen! } # movecopy_user_select(number, folders, folder, form-no) # Returns HTML for entering a username to copy mail to sub movecopy_user_select { local $rv; $rv .= ""; $rv .= ""; $rv .= &ui_user_textbox("mfolder$_[0]", undef, $_[3]); return $rv; } # need_delete_warn(&folder) sub need_delete_warn { return 1 if ($config{'delete_warn'} eq 'y'); return 0 if ($config{'delete_warn'} eq 'n'); local $mf; return $_[0]->{'type'} == 0 && ($mf = &folder_file($_[0])) && &disk_usage_kb($mf)*1024 > $config{'delete_warn'}; } @mail_system_modules = ( [ undef, 4, \&check_qmail_ldap, \&test_qmail_ldap ], [ undef, 5, \&check_vpopmail ], [ "qmailadmin", 2 ], [ "postfix", 0 ], [ "sendmail", 1 ], ); # detect_mail_system() # Works out which mail server is installed sub detect_mail_system { foreach $m (@mail_system_modules) { return $m->[1] if (&check_mail_system($m)); } return 3; } # check_mail_system(&mailsystem) sub check_mail_system { if ($_[0]->[0]) { # Just check module return &foreign_installed($_[0]->[0]); } else { # Call function local $func = $_[0]->[2]; return &$func($_[0]); } } # test_mail_system([&mailsystem]) # Returns an error message if the mail system is invalid sub test_mail_system { local $ms; if (!$ms) { ($ms) = grep { $_->[1] == $config{'mail_system'} } @mail_system_modules; } if ($ms->[3]) { local $func = $ms->[3]; return &$func(); } return undef; } # check_qmail_ldap() # Make sure Qmail with LDAP extensions is installed sub check_qmail_ldap { return 0 if (&foreign_installed("qmailadmin", 1) != 2); local %qconfig = &foreign_config("qmailadmin"); return 0 if (!-r "$qconfig{'qmail_dir'}/control/ldapserver"); return 1; } # check_vpopmail() # Make sure Qmail with VPopMail extensions is installed sub check_vpopmail { return 0 if (&foreign_installed("qmailadmin", 1) != 2); return -x "$config{'vpopmail_dir'}/bin/vadddomain"; } # test_qmail_ldap() # Returns undef the Qmail+LDAP database can be contacted OK, or an error message sub test_qmail_ldap { $config{'ldap_host'} || return $text{'ldap_ehost'}; $config{'ldap_port'} =~ /^\d+$/ || return $text{'ldap_eport'}; $config{'ldap_login'} || return $text{'ldap_euser'}; $config{'ldap_base'} || return $text{'ldap_ebase'}; local $err = &connect_qmail_ldap(1); return ref($err) ? undef : $err; } # show_users_table(&users-list, [only-with-mail]) # Outputs HTML for a table of users, with the appropriate sorting and mode sub show_users_table { local @users = @{$_[0]}; local ($u, %size, %incount, %sentcount); if ($config{'sort_mode'} == 2 || $config{'show_size'} > 0 || $_[1] || $config{'show_count'} || $config{'show_sent'}) { # Need to check folders foreach $u (@users) { next if($config{'ignore_users_enabled'} == 1 && $config{'ignore_users'} =~ /$u->[0]/); local @folders = &list_user_folders(@$u); if ($config{'sort_mode'} == 2 || $config{'show_size'} > 0 || $_[1]) { # Compute size of folders $size{$u->[0]} = $config{'size_mode'} ? &folder_size(@folders) : &folder_size($folders[0]); } if ($config{'show_count'}) { # Get number of mails in inbox $incount{$u->[0]} = &mailbox_folder_size($folders[0]); } if ($config{'show_sent'}) { # Count number of messages in sent mail local ($sent) = grep { $_->{'sent'} } @folders; $sentcount{$u->[0]} = &mailbox_folder_size($sent) if ($sent); } } } # Sort by chosen mode if ($config{'sort_mode'} == 2) { @users = sort { $size{$b->[0]} <=> $size{$a->[0]} } @users; } elsif ($config{'sort_mode'} == 1) { @users = sort { lc($a->[0]) cmp lc($b->[0]) } @users; } local @allusers = @users; if ($_[1]) { # Limit to those with mail @users = grep { $size{$_->[0]} } @users; } # Show table of users if (!@allusers) { print "$text{'index_nousers'}

\n"; } elsif (!@users) { print "$text{'index_nousersmail'}

\n"; } elsif ($config{'show_size'} == 2) { # Show full user details local %uconfig = &foreign_config("useradmin"); local @ccols; push(@ccols, $text{'find_incount'}) if ($config{'show_count'}); push(@ccols, $text{'find_sentcount'}) if ($config{'show_sent'}); print &ui_columns_start( [ $text{'find_user'}, $text{'find_real'}, $text{'find_group'}, $text{'find_home'}, $text{'find_size'}, @ccols ], 100); foreach $u (@users) { local $g = getgrgid($u->[3]); next if($config{'ignore_users_enabled'} == 1 && $config{'ignore_users'} =~ /$u->[0]/); $u->[6] =~ s/,.*$// if ($uconfig{'extra_real'}); local $home = $u->[7]; if (length($home) > 30) { $home = "...".substr($home, -30); } local @ccols; push(@ccols,int($incount{$u->[0]})) if ($config{'show_count'}); push(@ccols,int($sentcount{$u->[0]})) if ($config{'show_sent'}); print &ui_columns_row( [ "$u->[0]", $u->[6], $g, $home, $size{$u->[0]} == 0 ? $text{'index_empty'} : &nice_size($size{$u->[0]}), @ccols ], [ undef, undef, undef, undef, "nowrap" ]); } print &ui_columns_end(); } else { # Just showing username (and maybe size) print &ui_table_start($text{'index_header'}, "width=100%", $config{'column_count'}); local $i = 0; foreach $u (@users) { next if($config{'ignore_users_enabled'} == 1 && $config{'ignore_users'} =~ /$u->[0]/); print "\n" if ($i % $config{'column_count'} == 0); print ""; print $u->[0]; if ($config{'show_size'} == 1) { local @folders = &list_user_folders(@$u); local $total = &folder_size(@folders); if ($size{$u->[0]} > 0) { print $config{'show_size_below'} ? '
' : ' '; print "(",&nice_size($size{$u->[0]}),")"; } } print "
\n"; print "\n" if ($i % $config{'column_count'} == ($config{'column_count'} - 1)); $i++; } if ($i % $config{'column_count'}) { while($i++ % $config{'column_count'}) { print "\n"; } print "\n"; } print &ui_table_end(); } } # switch_to_user(user) # Switch to the Unix user that files are accessed as. sub switch_to_user { if (!defined($old_uid)) { local @uinfo = &get_mail_user($_[0]); $old_uid = $>; $old_gid = $); $) = "$uinfo[3] $uinfo[3]"; $> = $uinfo[2]; } } sub switch_user_back { if (defined($old_uid)) { $> = $old_uid; $) = $old_gid; $old_uid = $old_gid = undef; } } sub folder_link { return "$text{'mail_return2'}"; } # get_from_address() # Returns the address to use when sending email from a script sub get_from_address { local $host = &get_from_domain(); if ($config{'webmin_from'} =~ /\@/) { return $config{'webmin_from'}; } elsif (!$config{'webmin_from'}) { return "webmin\@$host"; } else { return "$config{'webmin_from'}\@$host"; } } # get_from_domain() # Returns the default domain for From: addresses sub get_from_domain { return $config{'from_dom'} || &get_display_hostname(); } # get_user_from_address(&uinfo) # Returns the default From: address for mail sent from some user's mailbox sub get_user_from_address { local $uinfo = $_[0]; if ($config{'from_addr'}) { return $config{'from_addr'}; } elsif ($uinfo->[11]) { return $uinfo->[11]; } elsif ($config{'from_virtualmin'} && &foreign_check("virtual-server")) { # Does Virtualmin manage this user? &foreign_require("virtual-server", "virtual-server-lib.pl"); local $d; foreach $d (&virtual_server::list_domains()) { local @users = &virtual_server::list_domain_users($d, 0, 0, 1); local $u; foreach $u (@users) { if ($u->{'user'} eq $uinfo->[0] && $u->{'email'}) { # Found him! return $u->{'email'}; } } } } if ($uinfo->[0] =~ /\@/) { return $uinfo->[0]; } else { return $uinfo->[0].'@'.&get_from_domain(); } } # check_modification(&folder) # Display an error message if a folder has been modified since the time # in $in{'mod'} sub check_modification { local $newmod = &modification_time($_[0]); if ($in{'mod'} && $in{'mod'} != $newmod && $config{'check_mod'}) { # Changed! &error(&text('emodified', "list_mail.cgi?user=$in{'user'}&folder=$_[0]->{'index'}")); } } # spam_report_cmd(user) # Returns a command for reporting spam, or undef if none sub spam_report_cmd { local ($user) = @_; local %sconfig = &foreign_config("spam"); local $cmd; if ($config{'spam_report'} eq 'sa_learn') { $cmd = &has_command($sconfig{'sa_learn'}) ? "$sconfig{'sa_learn'} --spam --mbox" : undef; } elsif ($config{'spam_report'} eq 'spamassassin') { $cmd = &has_command($sconfig{'spamassassin'}) ? "$sconfig{'spamassassin'} --r" : undef; } else { $cmd = &has_command($sconfig{'sa_learn'}) ? "$sconfig{'sa_learn'} --spam --mbox" : &has_command($sconfig{'spamassassin'}) ? "$sconfig{'spamassassin'} --r" : undef; } return $user eq "root" ? $cmd : $cmd ? &command_as_user($user, 0, $cmd) : undef; } # allowed_directory() # Returns base directory for mail files, or undef if not allowed sub allowed_directory { if ($access{'dir'}) { return $access{'dir'}; } else { return $access{'mmode'} == 1 ? "/" : undef; } } # is_user(user) sub is_user { return $_[0] !~ /^\//; } # list_mail_users([max]) # Returns getpw* style structures for all users who can recieve mail. Those with # duplicate info are skipped. sub list_mail_users { local ($max) = @_; local @rv; if ($config{'mail_system'} < 3) { # Postfix, Sendmail and Qmail all use Unix users local %found; local %hfound; local ($dir, $style, $mailbox, $maildir) = &get_mail_style(); setpwent(); while(my (@uinfo) = getpwent()) { next if ($found{$uinfo[0]}++); # done this username already next if (!$dir && $hfound{$uinfo[7]}++); push(@rv, \@uinfo); last if ($max && @rv > $max); } endpwent(); } elsif ($config{'mail_system'} == 4) { # Qmail+LDAP uses an LDAP db local $ldap = &connect_qmail_ldap(); local $rv = $ldap->search(base => $config{'ldap_base'}, filter => "(objectClass=qmailUser)"); &error($rv->error) if ($rv->code); local $u; foreach $u ($rv->all_entries) { local @uinfo = &qmail_dn_to_user($u); next if (!$uinfo[10]); # alias only push(@rv, \@uinfo); last if ($max && @rv > $max); } $ldap->unbind(); } elsif ($config{'mail_system'} == 5) { # Get vpopmail user list for all domains opendir(DOMS, "$config{'vpopmail_dir'}/domains"); foreach $d (readdir(DOMS)) { next if ($d =~ /^\./); push(@rv, &parse_vpopmail_users("-D $d")); last if ($max && @rv > $max); } } return @rv; } # parse_vpopmail_users(command) sub parse_vpopmail_users { local %attr_map = ( "passwd" => 1, "gecos" => 5, "dir" => 7 ); local (@rv, $user); open(UINFO, "$config{'vpopmail_dir'}/bin/vuserinfo $_[0] |"); while() { s/\r|\n//g; if (/^([^:]+):\s+(.*)$/) { local ($attr, $value) = ($1, $2); if ($attr eq "name") { # Start of a new user $user = [ "$value\@$d" ]; $user->[11] = $user->[0]; push(@rv, $user); } local $amapped = $attr_map{$attr}; $user->[$amapped] = $value if ($amapped); } } close(UINFO); return @rv; } # get_mail_user(name) # Looks up a user by name sub get_mail_user { if ($config{'mail_system'} < 3) { # Just find Unix user return getpwnam($_[0]); } elsif ($config{'mail_system'} == 4) { # Lookup in LDAP DB local $ldap = &connect_qmail_ldap(); local $rv = $ldap->search(base => $config{'ldap_base'}, filter => "(&(objectClass=qmailUser)(uid=$_[0]))"); &error($rv->error) if ($rv->code); local ($u) = $rv->all_entries; if ($u) { # Found in LDAP local @uinfo = &qmail_dn_to_user($u); $ldap->unbind(); return @uinfo; } else { # Fall back to Unix user return getpwnam($_[0]); } } elsif ($config{'mail_system'} == 5) { # Find in vpopmail local @users = &parse_vpopmail_users($_[0]); return @{$users[0]}; } } # get_mail_uid(name) # Looks up a user by UID sub get_mail_uid { if ($config{'mail_system'} < 3) { # Just find Unix user return getpwuid($_[0]); } elsif ($config{'mail_system'} == 4) { # Lookup in LDAP DB local $ldap = &connect_qmail_ldap(); local $rv = $ldap->search(base => $config{'ldap_base'}, filter => "(&(objectClass=qmailUser)(uidNumber=$_[0]))"); &error($rv->error) if ($rv->code); local ($u) = $rv->all_entries; local @uinfo = &qmail_dn_to_user($u); $ldap->unbind(); return @uinfo; } elsif ($config{'mail_system'} == 5) { # Find in vpopmail return ( ); # not possible, since UIDs aren't used! } } # connect_qmail_ldap([return-error]) # Connect to the LDAP server used for Qmail. Returns an LDAP handle on success, # or an error message on failure. sub connect_qmail_ldap { eval "use Net::LDAP"; if ($@) { local $err = &text('ldap_emod', "Net::LDAP"); if ($_[0]) { return $err; } else { &error($err); } } # Connect to server local $port = $config{'ldap_port'} || 389; local $ldap = Net::LDAP->new($config{'ldap_host'}, port => $port); if (!$ldap) { local $err = &text('ldap_econn', "$config{'ldap_host'}","$port"); if ($_[0]) { return $err; } else { &error($err); } } # Start TLS if configured if ($config{'ldap_tls'}) { $ldap->start_tls(); } # Login local $mesg; if ($config{'ldap_login'}) { $mesg = $ldap->bind(dn => $config{'ldap_login'}, password => $config{'ldap_pass'}); } else { $mesg = $ldap->bind(anonymous => 1); } if (!$mesg || $mesg->code) { local $err = &text('ldap_elogin', "$config{'ldap_host'}", $dn, $mesg ? $mesg->error : "Unknown error"); if ($_[0]) { return $err; } else { &error($err); } } return $ldap; } # qmail_dn_to_user(&dn) sub qmail_dn_to_user { local $mms = &add_ldapmessagestore( scalar($_[0]->get_value("mailMessageStore"))); if (-d "$mms/Maildir") { $mms .= "/" if ($mms !~ /\/$/); $mms .= "Maildir"; } return ( scalar($_[0]->get_value("uid")), scalar($_[0]->get_value("userPassword")), scalar($_[0]->get_value("uidNumber")), scalar($_[0]->get_value("gidNumber")), scalar($_[0]->get_value("mailQuotaSize")), scalar($_[0]->get_value("cn")), scalar($_[0]->get_value("cn")), scalar($_[0]->get_value("homeDirectory")), scalar($_[0]->get_value("loginShell")), undef, $mms, scalar($_[0]->get_value("mail")), ); } # add_ldapmessagestore(path) sub add_ldapmessagestore { if (!$_[0]) { return $_[0]; } elsif ($_[0] =~ /^\//) { return $_[0]; } else { &foreign_require("qmailadmin", "qmail-lib.pl"); local $pfx = &qmailadmin::get_control_file("ldapmessagestore"); return $pfx."/".$_[0]; } } # show_buttons(number, &folders, current-folder, &mail, user, search-mode) sub show_buttons { local ($num, $folders, $folder, $mail, $user, $search) = @_; local $uuser = &urlize($user); local $spacer = " \n"; if (@$mail) { # Delete print ""; if ($config{'show_delall'} && !$search) { print ""; } print $spacer; # Mark as print ""; print ""; print $spacer; if (&is_user($user)) { # Forward if ($config{'open_mode'}) { # Forward messages in a separate window print ""; } else { print ""; } print $spacer; } # Move/copy print &movecopy_user_select($_[0], $folders, $folder, 1); print $spacer; # Show spam report buttons local @modules = &get_available_module_infos(1); local ($hasspam) = grep { $_->{'dir'} eq "spam" } @modules; if (&foreign_installed("spam") && $config{'spam_buttons'} =~ /list/ && &spam_report_cmd($user)) { if ($hasspam) { print ""; } if ($config{'spam_del'}) { print "\n"; } else { print ""; } print $spacer; } } if ($config{'open_mode'}) { # Show mass open button print ""; print $spacer; } # Compose if (&is_user($user)) { if ($config{'open_mode'}) { # In a separate window print ""; } else { print ""; } } print "
\n"; } # get_signature(user) # Returns the users signature, if any sub get_signature { local $sf = &get_signature_file($_[0]); $sf || return undef; local $sig; open(SIG, $sf) || return undef; while() { $sig .= $_; } close(SIG); return $sig; } # get_signature_file(user) # Returns the full path to the file that should contain the user's signature, # or undef if none is defined sub get_signature_file { return undef if ($config{'sig_file'} eq '*' || $config{'sig_file'} eq ''); local $sf = $config{'sig_file'}; if ($sf !~ /^\//) { local @uinfo = getpwnam($_[0]); $sf = "$uinfo[7]/$sf"; } return $sf; } # view_mail_link(user, &folder, index, from-to-text) sub view_mail_link { local ($user, $folder, $idx, $txt) = @_; local $uuser = &urlize($user); local $url = "view_mail.cgi?user=$uuser&idx=$idx&folder=$folder->{'index'}"; if ($config{'open_mode'}) { return "". &simplify_from($txt).""; } else { return "".&simplify_from($txt).""; } } # mail_page_header(title, headstuff, bodystuff, rightstuff) sub mail_page_header { if ($config{'open_mode'}) { &popup_header($_[0], $_[1], $_[2]); } else { &ui_print_header(undef, $_[0], "", undef, 0, 0, 0, $_[3], $_[1], $_[2]); } } # mail_page_footer(link, text, ...) sub mail_page_footer { if ($config{'open_mode'}) { &popup_footer(); } else { &ui_print_footer(@_); } } 1; mailboxes/list_mail.cgi0100755000567100000120000001730710446424356015206 0ustar jcameronwheel#!/usr/local/bin/perl # list_mail.cgi # List the mail messages for some user in some folder require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); &is_user($in{'user'}) || -e $in{'user'} || &error($text{'mail_efile'}); $uuser = &urlize($in{'user'}); if ($config{'track_read'}) { dbmopen(%read, "$module_config_directory/$in{'user'}.read", 0600); } # Make sure the mail system is OK $err = &test_mail_system(); if ($err) { &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1); if (!$access{'noconfig'}) { &ui_print_endpage(&text('index_esystem3', "../config.cgi?$module_name", $err)); } else { &ui_print_endpage(&text('mail_esystem', $err)); } } &ui_print_header(undef, $text{'mail_title'}, ""); print &check_clicks_function(); @folders = &list_user_folders_sorted($in{'user'}); ($folder) = grep { $_->{'index'} == $in{'folder'} } @folders; # Get folder-selection HTML $sel = &folder_select(\@folders, $folder, "folder"); # Work out start from jump page $perpage = $folder->{'perpage'} || $config{'perpage'}; if ($in{'jump'} =~ /^\d+$/ && $in{'jump'} > 0) { $in{'start'} = ($in{'jump'}-1)*$perpage; } # View mail from the most recent @mail = reverse(&mailbox_list_mails(-$in{'start'}, -$in{'start'}-$perpage+1, $folder, 1, \@error)); if ($in{'start'} >= @mail && $in{'jump'}) { # Jumped too far! $in{'start'} = @mail - $perpage; @mail = reverse(&mailbox_list_mails(-$in{'start'}, -$in{'start'}-$perpage+1, $folder, 1, \@error)); } # Show page flipping arrows &show_arrows(); print "

\n"; print "\n"; print "\n"; print "\n"; print "\n"; if ($config{'top_buttons'} && @mail) { &show_buttons(1, \@folders, $folder, \@mail, $in{'user'}); print &select_all_link("d", 1, $text{'mail_all'})," \n"; print &select_invert_link("d", 1, $text{'mail_invert'})," \n"; } $showto = $folder->{'sent'} || $folder->{'drafts'}; @tds = ( "width=5", "nowrap", "nowrap", "nowrap", "nowrap" ); if (@mail) { # Show mailbox headers local @hcols; push(@hcols, ""); push(@hcols, $showto ? $text{'mail_to'} : $text{'mail_from'}); push(@hcols, $config{'show_to'} ? $showto ? ( $text{'mail_from'} ) : ( $text{'mail_to'} ) : ()); push(@hcols, $text{'mail_date'}); push(@hcols, $text{'mail_size'}); push(@hcols, $text{'mail_subject'}); print &ui_columns_start(\@hcols, 100, 0, \@tds); } if (@error) { print "
\n"; print &text('mail_err', $error[0] == 0 ? $error[1] : &text('save_elogin', $error[1])),"\n"; print "
\n"; } elsif (@error && $error[0] == 2) { } # Show rows for actual mail messages for($i=$in{'start'}; $i<@mail && $i<$in{'start'}+$perpage; $i++) { local $idx = $mail[$i]->{'idx'}; local $cols = 0; local @cols; local $from = $mail[$i]->{'header'}->{$showto ? 'to' : 'from'}; $from = $text{'mail_unknown'} if ($from !~ /\S/); push(@cols, &view_mail_link($in{'user'}, $folder, $idx, $from)); if ($config{'show_to'}) { push(@cols, &simplify_from( $mail[$i]->{'header'}->{$showto ? 'from' : 'to'})); } push(@cols, &simplify_date($mail[$i]->{'header'}->{'date'})); push(@cols, &nice_size($mail[$i]->{'size'}, 1024)); local $tbl; $tbl .= "". "
".&simplify_subject($mail[$i]->{'header'}->{'subject'}). " "; if ($mail[$i]->{'header'}->{'content-type'} =~ /multipart\/\S+/i) { $tbl .= ""; } local $p = int($mail[$i]->{'header'}->{'x-priority'}); if ($p == 1) { $tbl .= " "; } elsif ($p == 2) { $tbl .= " "; } if (!$showto) { if ($read{$mail[$i]->{'header'}->{'message-id'}} == 2) { $tbl .= " "; } elsif ($read{$mail[$i]->{'header'}->{'message-id'}} == 1) { $tbl .= " "; } } $tbl .= "
\n"; push(@cols, $tbl); if (&editable_mail($mail[$i])) { print &ui_checked_columns_row(\@cols, \@tds, "d", $idx); } else { print &ui_columns_row([ "", @cols ], \@tds); } if ($config{'show_body'}) { # Show part of the body too &parse_mail($mail[$i]); local $data = &mail_preview($mail[$i]); if ($data) { print " ", &html_escape($data)," \n"; } } } if (@mail) { print &ui_columns_end(); print &select_all_link("d", 1, $text{'mail_all'})," \n"; print &select_invert_link("d", 1, $text{'mail_invert'}),"
\n"; } &show_buttons(2, \@folders, $folder, \@mail, $in{'user'}); print "
\n"; if ($config{'arrows'}) { # Show page flipping arrows &show_arrows(); } if (@mail) { print "
\n"; print "\n"; # Show simple search form print "\n"; # Show advanced search button print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; # Show delete all button print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } # Show page jump form $jumpform = (@mail > $perpage); if ($jumpform) { print "\n"; print "\n"; print "\n"; print "\n"; } else { print "\n"; } if (@mail) { print "\n"; print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
\n"; print "\n"; printf " %s %s\n", int($in{'start'} / $perpage)+1, $text{'mail_of'}, int(@mail / $perpage)+1; print "
\n"; } if ($config{'log_read'}) { &webmin_log("read", undef, $in{'user'}, { 'file' => $folder->{'file'} }); } &ui_print_footer("", $text{'index_return'}); sub show_arrows { print "
\n"; print "
\n"; print "\n"; if ($in{'start'}+$perpage < @mail) { printf "". "\n", $in{'start'}+$perpage, $uuser, $in{'folder'}; } local $s = @mail-$in{'start'}; local $e = @mail-$in{'start'}-$perpage+1; if (@mail) { print &text('mail_pos', $s, $e < 1 ? 1 : $e, scalar(@mail), $sel); } else { print &text('mail_none', $sel); } print "\n"; if ($in{'start'}) { printf "". "\n", $in{'start'}-$perpage, $uuser, $in{'folder'}; } print "
\n"; } mailboxes/folders-lib.pl0100664000567100000120000017131710443360626015301 0ustar jcameronwheel# folders-lib.pl # Functions for dealing with mail folders in various formats $pop3_port = 110; $imap_port = 143; $cache_directory = $user_module_config_directory || $module_config_directory; # mailbox_list_mails(start, end, &folder, [headersonly], [&error]) # Returns an array whose size is that of the entire folder, with messages # in the specified range filled in. sub mailbox_list_mails { if ($_[2]->{'type'} == 0) { # List a single mbox formatted file return &list_mails($_[2]->{'file'}, $_[0], $_[1]); } elsif ($_[2]->{'type'} == 1) { # List a qmail maildir local $md = $_[2]->{'file'}; return &list_maildir($md, $_[0], $_[1]); } elsif ($_[2]->{'type'} == 2) { # Get mail headers/body from a remote POP3 server # Login first local @rv = &pop3_login($_[2]); if ($rv[0] != 1) { # Failed to connect or login if ($_[4]) { @{$_[4]} = @rv; return (); } elsif ($rv[0] == 0) { &error($rv[1]); } else { &error(&text('save_elogin', $rv[1])); } } local $h = $rv[1]; local @uidl = &pop3_uidl($h); local %onserver = map { &safe_uidl($_), 1 } @uidl; # Work out what range we want local ($start, $end) = &compute_start_end($_[0], $_[1], scalar(@uidl)); local @rv = map { undef } @uidl; # For each message in the range, get the headers or body local ($i, $f, %cached, %sizeneed); local $cd = "$cache_directory/$_[2]->{'id'}.cache"; if (opendir(CACHE, $cd)) { while($f = readdir(CACHE)) { if ($f =~ /^(\S+)\.body$/) { $cached{$1} = 2; } elsif ($f =~ /^(\S+)\.headers$/) { $cached{$1} = 1; } } closedir(CACHE); } else { mkdir($cd, 0700); } for($i=$start; $i<=$end; $i++) { local $u = &safe_uidl($uidl[$i]); if ($cached{$u} == 2 || $cached{$u} == 1 && $_[3]) { # We already have everything that we need } elsif ($cached{$u} == 1 || !$_[3]) { # We need to get the entire mail &pop3_command($h, "retr ".($i+1)); open(CACHE, ">$cd/$u.body"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); print CACHE $_; } close(CACHE); unlink("$cd/$u.headers"); $cached{$u} = 2; } else { # We just need the headers &pop3_command($h, "top ".($i+1)." 0"); open(CACHE, ">$cd/$u.headers"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); print CACHE $_; } close(CACHE); $cached{$u} = 1; } local $mail = &read_mail_file($cached{$u} == 2 ? "$cd/$u.body" : "$cd/$u.headers"); if ($cached{$u} == 1) { if ($mail->{'body'} ne "") { $mail->{'size'} = int($mail->{'body'}); } else { $sizeneed{$i} = 1; } } $mail->{'uidl'} = $uidl[$i]; $mail->{'idx'} = $i; $rv[$i] = $mail; } # Get sizes for mails if needed if (%sizeneed) { &pop3_command($h, "list"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); if (/^(\d+)\s+(\d+)/ && $sizeneed{$1-1}) { # Add size to the mail cache $rv[$1-1]->{'size'} = $2; local $u = &safe_uidl($uidl[$1-1]); open(CACHE, ">>$cd/$u.headers"); print CACHE $2,"\n"; close(CACHE); } } } # Clean up any cached mails that no longer exist on the server foreach $f (keys %cached) { if (!$onserver{$f}) { unlink($cached{$f} == 1 ? "$cd/$f.headers" : "$cd/$f.body"); } } return @rv; } elsif ($_[2]->{'type'} == 3) { # List an MH directory local $md = $_[2]->{'file'}; return &list_mhdir($md, $_[0], $_[1]); } elsif ($_[2]->{'type'} == 4) { # Get headers and possibly bodies from an IMAP server # Login and select the specified mailbox local @rv = &imap_login($_[2]); if ($rv[0] != 1) { # Something went wrong if ($_[4]) { @{$_[4]} = @rv; return (); } elsif ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 3) { &error(&text('save_emailbox', $rv[1])); } elsif ($rv[0] == 2) { &error(&text('save_elogin2', $rv[1])); } } local $h = $rv[1]; local $count = $rv[2]; return () if (!$count); # Work out what range we want local ($start, $end) = &compute_start_end($_[0], $_[1], $count); local @mail = map { undef } (0 .. $count-1); # Get the headers or body of messages in the specified range local @rv; if ($_[3]) { # Just the headers @rv = &imap_command($h, sprintf "FETCH %d:%d (RFC822.SIZE RFC822.HEADER)", $start+1, $end+1); } else { # Whole messages @rv = &imap_command($h, sprintf "FETCH %d:%d RFC822", $start+1, $end+1); } # Parse the headers or whole messages that came back local $i; for($i=0; $i<@{$rv[1]}; $i++) { # Extract the actual mail part local $mail = &parse_imap_mail($rv[1]->[$i]); if ($mail) { $mail->{'idx'} = $start+$i; $mail[$start+$i] = $mail; } } return @mail; } elsif ($_[2]->{'type'} == 5) { # Just all of the constituent folders local @mail; # Work out exactly how big the total is local ($sf, %len, $count); foreach $sf (@{$_[2]->{'subfolders'}}) { $len{$sf} = &mailbox_folder_size($sf); $count += $len{$sf}; } # Work out what range we need local ($start, $end) = &compute_start_end($_[0], $_[1], $count); # Fetch the needed part of each sub-folder local $pos = 0; foreach $sf (@{$_[2]->{'subfolders'}}) { local ($sfstart, $sfend); $sfstart = $start - $pos; $sfend = $end - $pos; $sfstart = $sfstart < 0 ? 0 : $sfstart >= $len{$sf} ? $len{$sf}-1 : $sfstart; $sfend = $sfend < 0 ? 0 : $sfend >= $len{$sf} ? $len{$sf}-1 : $sfend; local @submail = &mailbox_list_mails($sfstart, $sfend, $sf, $_[3]); local $sm; foreach $sm (@submail) { if ($sm) { &push_index($sm, $sf, $sm->{'idx'}+$pos); } } push(@mail, @submail); $pos += $len{$sf}; } return @mail; } elsif ($_[2]->{'type'} == 6) { # A virtual folder, which just contains indexes into other folders local $mems = $folder->{'members'}; local ($start, $end) = &compute_start_end($_[0], $_[1], scalar(@$mems)); # Work out which folders we need, and how much local (%frange, %namemap); local $i; for($i=$start; $i<=$end; $i++) { local $sf = $mems->[$i]->[0]; local $sfn = &folder_name($sf); local $idx = $mems->[$i]->[1]; if ($frange{$sfn}) { $frange{$sfn}->[0] = $idx if ($idx < $frange{$sfn}->[0]); $frange{$sfn}->[1] = $idx if ($idx > $frange{$sfn}->[1]); } else { $frange{$sfn} = [ $idx, $idx ]; } $namemap{$sfn} = $sf; } # Get all the needed folders local %sfs; local $sfn; foreach $sfn (keys %frange) { local $sf = $namemap{$sfn}; local @submail = &mailbox_list_mails($frange{$sfn}->[0], $frange{$sfn}->[1], $sf, $_[3]); $sfs{$sfn} = \@submail; } # Construct the results local @mail = map { undef } (0 .. @$mems-1); local $need_save = 0; local @newmems = @$mems; for($i=$start; $i<=$end && $i<=@$mems; $i++) { local $sf = $mems->[$i]->[0]; local $sfn = &folder_name($sf); local $idx = $mems->[$i]->[1]; $mail[$i] = $sfs{$sfn}->[$idx]; if ($mems->[$i]->[2] && $mail[$i]->{'header'}->{'message-id'} ne $mems->[$i]->[2]) { # Argh .. index is wrong! Find message by ID local $real = &find_by_message_id($sf,$mems->[$i]->[2]); if ($real) { $mems->[$i]->[1] = $real->{'idx'}; $mail[$i] = $real; $need_save++; } else { # Doesn't exist! Lose from index.. @newmems = grep { $_ ne $mems->[$i] } @newmems; $need_save++; next; } } &push_index($mail[$i], $sf, $i); } if ($need_save) { $_[2]->{'members'} = \@newmems; &save_folder($_[2]); } return @mail; } } # mailbox_select_mails(&folder, &indexes, headersonly) # Returns only messages from a folder with indexes in the given array sub mailbox_select_mails { local ($folder, $indexes, $headersonly) = @_; if ($folder->{'type'} == 0) { # mbox folder return &select_mails($folder->{'file'}, $indexes, $headersonly); } elsif ($folder->{'type'} == 1) { # Maildir folder return &select_maildir($folder->{'file'}, $indexes, $headersonly); } elsif ($folder->{'type'} == 3) { # MH folder return &select_mhdir($folder->{'file'}, $indexes, $headersonly); } elsif ($folder->{'type'} == 2) { # POP folder # Login first local @rv = &pop3_login($folder); if ($rv[0] != 1) { # Failed to connect or login if ($_[4]) { @{$_[4]} = @rv; return (); } elsif ($rv[0] == 0) { &error($rv[1]); } else { &error(&text('save_elogin', $rv[1])); } } local $h = $rv[1]; local @uidl = &pop3_uidl($h); # For each message in the range, get the headers or body local ($i, $f, %cached, %sizeneed); local @rv; local $cd = "$cache_directory/$_[2]->{'id'}.cache"; if (opendir(CACHE, $cd)) { while($f = readdir(CACHE)) { if ($f =~ /^(\S+)\.body$/) { $cached{$1} = 2; } elsif ($f =~ /^(\S+)\.headers$/) { $cached{$1} = 1; } } closedir(CACHE); } else { mkdir($cd, 0700); } foreach my $i (@$indexes) { local $u = &safe_uidl($uidl[$i]); if ($cached{$u} == 2 || $cached{$u} == 1 && $headersonly) { # We already have everything that we need } elsif ($cached{$u} == 1 || !$headersonly) { # We need to get the entire mail &pop3_command($h, "retr ".($i+1)); open(CACHE, ">$cd/$u.body"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); print CACHE $_; } close(CACHE); unlink("$cd/$u.headers"); $cached{$u} = 2; } else { # We just need the headers &pop3_command($h, "top ".($i+1)." 0"); open(CACHE, ">$cd/$u.headers"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); print CACHE $_; } close(CACHE); $cached{$u} = 1; } local $mail = &read_mail_file($cached{$u} == 2 ? "$cd/$u.body" : "$cd/$u.headers"); if ($cached{$u} == 1) { if ($mail->{'body'} ne "") { $mail->{'size'} = int($mail->{'body'}); } else { $sizeneed{$i} = 1; } } $mail->{'uidl'} = $uidl[$i]; $mail->{'idx'} = $i; push(@rv, $mail); } # Get sizes for mails if needed if (%sizeneed) { &pop3_command($h, "list"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); if (/^(\d+)\s+(\d+)/ && $sizeneed{$1-1}) { # Find mail in results, and set its size local ($ns) = grep { $_->{'idx'} == $1-1 } @rv; next if (!$ns); $ns->{'size'} = $2; local $u = &safe_uidl($uidl[$1-1]); open(CACHE, ">>$cd/$u.headers"); print CACHE $2,"\n"; close(CACHE); } } } return @rv; } elsif ($folder->{'type'} == 4) { # IMAP folder # XXX } elsif ($folder->{'type'} == 5) { # Composite folder .. need to convert each index to a position # in a sub-folder # XXX could be faster my $pos = 0; my @ranges; foreach my $sf (@{$folder->{'subfolders'}}) { my $len = &mailbox_folder_size($sf); push(@ranges, [ $pos, $pos+$len, $sf ]); $pos += $len; } local @rv; foreach my $i (@$indexes) { # Find out which sub-folder this index is in foreach my $r (@ranges) { if ($i >= $r->[0] && $i < $r->[1]) { # Found it! local ($mail) = &mailbox_select_mails( $r->[2], [ $i - $r->[0] ], $headersonly); &push_index($mail, $r->[2], $i); push(@rv, $mail); last; } } } return @rv; } elsif ($folder->{'type'} == 6) { # Virtual folder .. translate each index to sub-folder index # XXX could be faster local $mems = $folder->{'members'}; local @rv; local $need_save = 0; local @newmems = @$mems; # Work out how many different sub-folders we have local $sf; foreach my $i (@$indexes) { $sf = $mems->[$i]->[0]; $sfcount{&folder_name($sf)} = 1; } if ((keys %sfcount) == 1) { # Just one, so we can do one big select local (@sfindexes, @sfmems); foreach my $i (@$indexes) { push(@sfindexes, $mems->[$i]->[1]); push(@sfmems, $i); } local $i = 0; foreach my $mail (&mailbox_select_mails($sf, \@sfindexes, $headersonly)) { $mail->{'mem'} = $mems->[$sfmems[$i]]; &push_index($mail, $sf, $sfmems[$i]); push(@rv, $mail); $i++; } } elsif ((keys %sfcount) > 0) { # Several sub-folders, so we need to select from each foreach my $i (@$indexes) { local $sf = $mems->[$i]->[0]; local $idx = $mems->[$i]->[1]; local ($mail) = &mailbox_select_mails($sf, [ $idx ], $headersonly); $mail->{'mem'} = $mems->[$i]; &push_index($mail, $sf, $i); push(@rv, $mail); } } # Fix up any mistmatches between indexes and message IDs foreach $mail (@rv) { local $mem = $mail->{'mem'}; if ($mem->[2] && $mail->{'header'}->{'message-id'} ne $mem->[2]) { # Message ID mismatch! Fix it.. local $real = &find_by_message_id( $mail->{'subfolder'}, $mem->[2]); if ($real) { $mem->[1] = $real->{'idx'}; $mail = $real; $need_save++; } else { # Doesn't exist! Lose from index.. @newmems = grep { $_ ne $mem } @newmems; $need_save++; } } } if ($need_save) { $folder->{'members'} = \@newmems; &save_folder($folder); } return @rv; } } # compute_start_end(start, end, count) # Given start and end indexes (which may be negative or undef), returns the # real mail file indexes. sub compute_start_end { local ($start, $end, $count) = @_; if (!defined($start)) { return (0, $count-1); } elsif ($end < 0) { local $rstart = $count+$_[1]-1; local $rend = $count+$_[0]-1; $rstart = $rstart < 0 ? 0 : $rstart; return ($rstart, $rend); } else { local $rend = $_[1]; $rend = $count - 1 if ($rend >= $count); return ($start, $rend); } } # mailbox_list_mails_sorted(start, end, &folder, [headeronly], [&error], # [sort-field, sort-dir]) # Returns messages in a folder within the given range, but sorted by the # given field and condition. sub mailbox_list_mails_sorted { local ($start, $end, $folder, $headers, $error, $field, $dir) = @_; if (!$field) { # Default to current ordering ($field, $dir) = &get_sort_field($folder); } if (!$field || !$folder->{'sortable'}) { # No sorting .. just return newest first local @rv = reverse(&mailbox_list_mails( -$start, -$end-1, $folder, $headers, $error)); local $i = 0; foreach my $m (@rv) { $m->{'sortidx'} = $i++; } return @rv; } # Build the appropriate sort index, if missing local %index; &build_sort_index($folder, $field, \%index); # Get message indexes, sorted by the field my @sorter; while(my ($k, $v) = each %index) { if ($k =~ /^(\d+)_\Q$field\E$/) { push(@sorter, [ $1, lc($v) ]); } } if ($field eq "size" || $field eq "date" || $field eq "x-spam-status") { # Numeric sort @sorter = sort { my $s = $a->[1] <=> $b->[1]; $dir ? $s : -$s } @sorter; } else { # Alpha sort @sorter = sort { my $s = $a->[1] cmp $b->[1]; $dir ? $s : -$s } @sorter; } # Find those mails within the requested range ($start, $end) = &compute_start_end($start, $end, scalar(@sorter)); local @rv = map { undef } (0 .. scalar(@sorter)-1); local @wantindexes = map { $sorter[$_]->[0] } ($start .. $end); local @mails = &mailbox_select_mails($folder, \@wantindexes, $headers); for(my $i=0; $i<@mails; $i++) { $rv[$start+$i] = $mails[$i]; $mails[$i]->{'sortidx'} = $start+$i; } return @rv; } # set_sort_indexes(&folder, &mails, [sort-field, sort-dir]) # Given a list of messages, sets the sortidx field based on their indexes # that would be used if the folder was sorted sub set_sort_indexes { local ($folder, $mails, $field, $dir) = @_; if (!$field) { # Default to current ordering ($field, $dir) = &get_sort_field($folder); } if (!$field || !$folder->{'sortable'}) { # Sort index is the same as the normal index reversed my $count = &mailbox_folder_size($folder); foreach my $m (@$mails) { $m->{'sortidx'} = $count-$m->{'idx'}-1; } return; } # Build the appropriate sort index, if missing local %index; &build_sort_index($folder, $field, \%index); # Get message indexes, sorted by the field my @sorter; while(my ($k, $v) = each %index) { if ($k =~ /^(\d+)_\Q$field\E$/) { push(@sorter, [ $1, lc($v) ]); } } if ($field eq "size" || $field eq "date") { # Numeric sort @sorter = sort { my $s = $a->[1] <=> $b->[1]; $dir ? $s : -$s } @sorter; } else { # Alpha sort @sorter = sort { my $s = $a->[1] cmp $b->[1]; $dir ? $s : -$s } @sorter; } # Update sort indexes for mails in list my $i = 0; my %idxmap = map { $_->{'idx'}, $_ } @$mails; foreach my $s (@sorter) { my $m = $idxmap{$s->[0]}; if ($m) { $m->{'sortidx'} = $i; } $i++; } } # build_sort_index(&folder, field, &index) # Builds and/or loads the index for sorting a folder on some field. The # index uses the mail number as the key, and the field value as the value. sub build_sort_index { local ($folder, $field, $index) = @_; return 0 if (!$folder->{'sortable'}); local $ifile = &folder_sort_index_file($folder); dbmopen(%$index, $ifile, 0600); if ($index->{'lastchange'} < $folder->{'lastchange'} || !$folder->{'lastchange'}) { # The mail file is newer than the index .. add messages not in the index # to it. local $realcount = $folder->{'type'} == 6 ? scalar(@{$folder->{'members'}}) : &mailbox_folder_size($folder); local $indexcount = int($index->{'mailcount'}); if ($realcount < $indexcount) { # Mail size has decreased! Need total rebuild $indexcount = 0; %$index = ( ); } local @mails = $realcount ? &mailbox_select_mails($folder, [ $indexcount .. $realcount-1 ], 1) : ( ); my @index_fields = ( "subject", "from", "to", "date", "size", "x-spam-status", "message-id" ); foreach my $mail (@mails) { foreach my $f (@index_fields) { if ($f eq "date") { # Convert date to Unix time $index->{$mail->{'idx'}."_date"} = &parse_mail_date($mail->{'header'}->{'date'}); } elsif ($f eq "size") { # Get mail size $index->{$mail->{'idx'}."_size"} = $mail->{'size'}; } elsif ($f eq "from" || $f eq "to") { # From: header .. convert to display version $index->{$mail->{'idx'}."_".$f} = &simplify_from($mail->{'header'}->{$f}); } elsif ($f eq "subject") { # Convert subject to display version $index->{$mail->{'idx'}."_".$f} = &simplify_subject($mail->{'header'}->{$f}); } elsif ($f eq "x-spam-status") { # Extract spam score $index->{$mail->{'idx'}."_".$f} = $mail->{'header'}->{$f} =~ /(hits|score)=([0-9\.]+)/ ? $2 : undef; } else { # Just a header $index->{$mail->{'idx'}."_".$f} = $mail->{'header'}->{$f}; } } } $index->{'lastchange'} = time(); $index->{'mailcount'} = $realcount; } return 1; } # delete_sort_index(&folder) # Trashes the sort index for a folder, to force a rebuild sub delete_sort_index { local ($folder) = @_; local $ifile = &folder_sort_index_file($folder); my %index; dbmopen(%index, $ifile, 0600); %index = ( ); } # folder_sort_index_file(&folder) # Returns the index file to use for some folder sub folder_sort_index_file { local ($folder) = @_; return &user_index_file(($folder->{'file'} || $folder->{'id'}).".sort"); } # find_by_message_id(&folder, id) # Finds a message by ID, and returns the mail object sub find_by_message_id { local ($folder, $mid) = @_; local %index; if (&build_sort_index($folder, undef, \%index)) { while(my ($k, $v) = each %index) { if ($k =~ /^(\d+)_message-id$/ && $v eq $mid) { # Got it! local ($rv) = &mailbox_select_mails($folder, [ $1 ]); &set_sort_indexes($folder, [ $rv ]); return $rv; } } } return undef; } # find_message_by_index(&mails, &folder, index, mid) # Finds a message by index (in a sorted folder) or message ID sub find_message_by_index { local ($mails, $folder, $idx, $mid) = @_; local $mail = $mails->[$idx]; if ($mid && (!$mail || $mail->{'header'}->{'message-id'} ne $mid)) { $mail = &find_by_message_id($folder, $mid); } return $mail; } # mailbox_search_mail(&fields, andmode, &folder, [&limit]) # Search a mailbox for multiple matching fields sub mailbox_search_mail { # For folders other than mbox and IMAP, build a sort index and use that for # the search, if it is simple enough (Subject, From and To only) local @idxfields = grep { $_->[0] eq 'from' || $_->[0] eq 'to' || $_->[0] eq 'subject' } @{$_[0]}; if ($_[2]->{'type'} != 0 && $_[2]->{'type'} != 4 && $_[2]->{'type'} != 5 && scalar(@idxfields) == scalar(@{$_[0]}) && @idxfields) { local %index; &build_sort_index($_[2], undef, \%index); local @rv; # Work out which mail indexes match the requested headers local %idxmatches = map { ("$_->[0]/$_->[1]", [ ]) } @idxfields; while(my ($k, $v) = each %index) { local ($ki, $kf) = split(/_/, $k, 2); next if (!$kf || $ki eq ''); # Check all of the fields to see which ones match foreach my $if (@idxfields) { local $iff = $if->[0]; local ($neg) = ($iff =~ s/^\!//); next if ($kf ne $iff); if (!$neg && $v =~ /\Q$if->[1]\E/i || $neg && $v !~ /\Q$if->[1]\E/i) { push(@{$idxmatches{"$if->[0]/$if->[1]"}}, $ki); } } } local @matches; if ($_[1]) { # Find indexes in all arrays local %icount; foreach my $if (keys %idxmatches) { foreach my $i (@{$idxmatches{$if}}) { $icount{$i}++; } } foreach my $i (keys %icount) { } local $fif = $idxfields[0]; @matches = grep { $icount{$_} == scalar(@idxfields) } @{$idxmatches{"$fif->[0]/$fif->[1]"}}; } else { # Find indexes in any array foreach my $if (keys %idxmatches) { push(@matches, @{$idxmatches{$if}}); } @matches = &unique(@matches); } @matches = sort { $a <=> $b } @matches; # Select the actual mails return &mailbox_select_mails($_[2], \@matches, 0); } if ($_[2]->{'type'} == 0) { # Just search an mbox format file (which will use its own special # field-level index) return &advanced_search_mail($_[2]->{'file'}, $_[0], $_[1], $_[3]); } elsif ($_[2]->{'type'} == 1) { # Search a maildir directory local $md = $_[2]->{'file'}; return &advanced_search_maildir($md, $_[0], $_[1], $_[3]); } elsif ($_[2]->{'type'} == 2) { # Get all of the mail from the POP3 server and search it local ($min, $max); if ($_[3] && $_[3]->{'latest'}) { $min = -1; $max = -$_[3]->{'latest'}; } local @mails = &mailbox_list_mails($min, $max, $_[2], &indexof('body', &search_fields($_[0])) >= 0 ? 0 : 1); local @rv = grep { $_ && &mail_matches($_[0], $_[1], $_) } @mails; } elsif ($_[2]->{'type'} == 3) { # Search an MH directory local $md = $_[2]->{'file'}; return &advanced_search_mhdir($md, $_[0], $_[1], $_[3]); } elsif ($_[2]->{'type'} == 4) { # Use IMAP's remote search feature # XXX broken! local @rv = &imap_login($_[2]); if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 3) { &error(&text('save_emailbox', $rv[1])); } elsif ($rv[0] == 2) { &error(&text('save_elogin2', $rv[1])); } local $h = $rv[1]; # Do the search to get back a list of matching numbers local @search; foreach $f (@{$_[0]}) { local $field = $f->[0]; local $neg = ($field =~ s/^\!//); local $what = $f->[1]; $what = "\"$what\"" if ($field ne "size"); $field = "LARGER" if ($field eq "size"); local $search = uc($field)." ".$what.""; $search = "NOT $search" if ($neg); push(@searches, $search); } local $searches; if (@searches == 1) { $searches = $searches[0]; } elsif ($_[1]) { $searches = join(" ", @searches); } else { $searches = $searches[$#searches]; for($i=$#searches-1; $i>=0; $i--) { $searches = "or $searches[$i] ($searches)"; } } @rv = &imap_command($h, "SEARCH $searches"); &error(&text('save_esearch', $rv[3])) if (!$rv[0]); # Get and parse those specific messages local ($srch) = grep { $_ =~ /^\*\s+SEARCH/i } @{$rv[1]}; local @ids = split(/\s+/, $srch); shift(@ids); shift(@ids); # lose * SEARCH local (@mail, $idx); foreach $idx (@ids) { local $realidx = $idx-1; if ($_[3] && $_[3]->{'latest'}) { # Don't get message if outside search range next if ($realidx < $rv[3]-$_[3]->{'latest'}); } local @rv = &imap_command($h, "FETCH $idx (RFC822.SIZE RFC822.HEADER)"); &error(&text('save_esearch', $rv[3])) if (!$rv[0]); local $mail = &parse_imap_mail($rv[1]->[0]); if ($mail) { $mail->{'idx'} = $realidx; push(@mail, $mail); } } return reverse(@mail); } elsif ($_[2]->{'type'} == 5) { # Search each sub-folder and combine the results - taking any count # limits into effect local $sf; local $pos = 0; local @mail; local (%start, %len); foreach $sf (@{$_[2]->{'subfolders'}}) { $len{$sf} = &mailbox_folder_size($sf); $start{$sf} = $pos; $pos += $len{$sf}; } local $limit = $_[3] ? { %{$_[3]} } : undef; foreach $sf (reverse(@{$_[2]->{'subfolders'}})) { local @submail = &mailbox_search_mail($_[0], $_[1], $sf, $limit); foreach $sm (@submail) { &push_index($sm, $sf, $sm->{'idx'}+$start{$sf}); } push(@mail, reverse(@submail)); if ($limit && $limit->{'latest'}) { # Adjust latest down by size of this folder $limit->{'latest'} -= $len{$sf}; last if ($limit->{'latest'} <= 0); } } return reverse(@mail); } elsif ($_[2]->{'type'} == 6) { # Just run a search on the sub-mails local @rv; local ($min, $max); if ($_[3] && $_[3]->{'latest'}) { $min = -1; $max = -$_[3]->{'latest'}; } local $mail; foreach $mail (&mailbox_list_mails($min, $max, $_[2])) { push(@rv, $mail) if ($mail && &mail_matches($_[0],$_[1],$mail)); } return @rv; } } # mailbox_delete_mail(&folder, mail, ...) # Delete multiple messages from some folder sub mailbox_delete_mail { return undef if (&is_readonly_mode()); local $f = shift(@_); if ($userconfig{'delete_mode'} == 1 && !$f->{'trash'} && !$f->{'spam'}) { # Copy to trash folder first local ($trash) = grep { $_->{'trash'} } &list_folders(); local $m; foreach $m (@_) { &write_mail_folder($m, $trash); } } if ($f->{'type'} == 0) { &delete_mail($f->{'file'}, @_); } elsif ($f->{'type'} == 1) { &delete_maildir(@_); } elsif ($f->{'type'} == 2) { # Login and delete from the POP3 server local @rv = &pop3_login($f); if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 2) { &error(&text('save_elogin', $rv[1])); } local $h = $rv[1]; local @uidl = &pop3_uidl($h); local $m; local $cd = "$cache_directory/$f->{'id'}.cache"; foreach $m (@_) { local $idx = &indexof($m->{'uidl'}, @uidl); if ($idx >= 0) { &pop3_command($h, "dele ".($idx+1)); local $u = &safe_uidl($m->{'uidl'}); unlink("$cd/$u.headers", "$cd/$u.body"); } } } elsif ($f->{'type'} == 3) { &delete_mhdir(@_); } elsif ($f->{'type'} == 4) { # Delete from the IMAP server local @rv = &imap_login($f); if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 3) { &error(&text('save_emailbox', $rv[1])); } elsif ($rv[0] == 2) { &error(&text('save_elogin2', $rv[1])); } local $h = $rv[1]; local $m; foreach $m (@_) { @rv = &imap_command($h, "STORE ".($m->{'idx'}+1). " +FLAGS (\\Deleted)"); &error(&text('save_edelete', $rv[3])) if (!$rv[0]); } @rv = &imap_command($h, "EXPUNGE"); &error(&text('save_edelete', $rv[3])) if (!$rv[0]); } elsif ($f->{'type'} == 5) { # Delete from underlying folder(s) local $sm; foreach $sm (@_) { local ($subfolder, $idx) = &pop_index($sm); &mailbox_delete_mail($subfolder, $sm); &push_index($sm, $subfolder, $idx); } } elsif ($f->{'type'} == 6) { local $sm; if ($f->{'delete'}) { # Delete the underlying messages, and remove from index local %folderdel; foreach $sm (sort { $b->{'subs'}->[0]->[1] <=> $a->{'subs'}->[0]->[1] } @_) { local ($subfolder, $idx) = &pop_index($sm); &mailbox_delete_mail($subfolder, $sm); &push_index($sm, $subfolder, $idx); # Adjust indexes in virtual list that refer to same # sub-folder, and have higher numbers for(my $i=0; $i<@{$f->{'members'}}; $i++) { my $m = $f->{'members'}->[$i]; my $subidx = $sm->{'subs'}->[0]->[1]; if ($m->[0] eq $sm->{'subfolder'}) { if ($m->[1] == $subidx) { splice(@{$f->{'members'}}, $i--, 1); } elsif ($m->[1] > $subidx) { $m->[1]--; } } } } } else { # Just take out of the virtual index foreach $sm (sort { $b->{'idx'} <=> $a->{'idx'} } @_) { splice(@{$f->{'members'}}, $sm->{'idx'}, 1); } } &save_folder($f, $f); } # Update folder index to remove indexes for deleted messages if ($f->{'sortable'}) { local %index; &build_sort_index($f, undef, \%index); foreach my $m (sort { $b->{'idx'} <=> $a->{'idx'} } @_) { foreach my $k (sort { $a <=> $b } (keys %index)) { local ($ki, $kf) = split(/_/, $k, 2); if ($m->{'idx'} == $ki) { # Delete this actual mail from the index delete($index{$k}); } elsif ($m->{'idx'} < $ki) { # Mail is after one being deleted .. shift down $index{($ki-1)."_".$kf} = $index{$k}; delete($index{$k}); } } } $index{'mailcount'} -= scalar(@_); $index{'lastchange'} = time(); dbmclose(%index); } } # mailbox_empty_folder(&folder) # Remove the entire contents of a mail folder sub mailbox_empty_folder { return undef if (&is_readonly_mode()); local $f = $_[0]; if ($f->{'type'} == 0) { # mbox format mail file &empty_mail($f->{'file'}); } elsif ($f->{'type'} == 1) { # qmail format maildir &empty_maildir($f->{'file'}); } elsif ($f->{'type'} == 2) { # POP3 server .. delete all messages local @rv = &pop3_login($f); if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 2) { &error(&text('save_elogin', $rv[1])); } local $h = $rv[1]; @rv = &pop3_command($h, "stat"); $rv[1] =~ /^(\d+)/ || return; local $count = $1; local $i; for($i=1; $i<=$count; $i++) { &pop3_command($h, "dele ".$i); } } elsif ($f->{'type'} == 3) { # mh format maildir &empty_mhdir($f->{'file'}); } elsif ($f->{'type'} == 4) { # IMAP server .. delete all messages local @rv = &imap_login($f); if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 3) { &error(&text('save_emailbox', $rv[1])); } elsif ($rv[0] == 2) { &error(&text('save_elogin2', $rv[1])); } local $h = $rv[1]; local $count = $rv[2]; local $i; for($i=1; $i<=$count; $i++) { @rv = &imap_command($h, "STORE ".$i. " +FLAGS (\\Deleted)"); &error(&text('save_edelete', $rv[3])) if (!$rv[0]); } @rv = &imap_command($h, "EXPUNGE"); &error(&text('save_edelete', $rv[3])) if (!$rv[0]); } elsif ($f->{'type'} == 5) { # Empty each sub-folder local $sf; foreach $sf (@{$f->{'subfolders'}}) { &mailbox_empty_folder($sf); } } elsif ($f->{'type'} == 6) { # Just clear the virtual index $f->{'members'} = [ ]; &save_folder($f); } # Trash the folder index if ($folder->{'sortable'}) { &delete_sort_index($folder); } } # mailbox_copy_folder(&source, &dest) # Copy all messages from one folder to another. This is done in an optimized # way if possible. sub mailbox_copy_folder { local ($src, $dest) = @_; if ($src->{'type'} == 0 && $dest->{'type'} == 0) { # mbox to mbox .. just read and write the files &open_readfile(SOURCE, $src->{'file'}); &open_tempfile(DEST, ">>$dest->{'file'}"); while(read(SOURCE, $buf, 1024) > 0) { &print_tempfile(DEST, $buf); } &close_tempfile(DEST); close(SOURCE); } elsif ($src->{'type'} == 1 && $dest->{'type'} == 1) { # maildir to maildir .. just copy the files local @files = &get_maildir_files($src->{'file'}); foreach my $f (@files) { local $fn = $f; $fn =~ s/^.*\///; ©_source_dest($f, "$dest->{'file'}/$fn"); } } elsif ($src->{'type'} == 1 && $dest->{'type'} == 0) { # maildir to mbox .. append all the files local @files = &get_maildir_files($src->{'file'}); &open_tempfile(DEST, ">>$dest->{'file'}"); foreach my $f (@files) { &open_readfile(SOURCE, $f); while(read(SOURCE, $buf, 1024) > 0) { &print_tempfile(DEST, $buf); } close(SOURCE); } &close_tempfile(DEST); } else { # read in all mail and write out, in 100 message blocks local $max = &mailbox_folder_size($src); for(my $s=0; $s<$max; $s+=100) { local $e = $s+99; $e = $max-1 if ($e >= $max); local @mail = &mailbox_list_mails($s, $e, $src); local @want = @mail[$s..$e]; &mailbox_copy_mail($src, $dest, @want); } } } # mailbox_move_mail(&source, &dest, mail, ...) # Move mail from one folder to another sub mailbox_move_mail { return undef if (&is_readonly_mode()); local $src = shift(@_); local $dst = shift(@_); local $now = time(); local $hn = &get_system_hostname(); &create_folder_maildir($dst); if (($src->{'type'} == 1 || $src->{'type'} == 3) && $dst->{'type'} == 1) { # Can just move mail files local $dd = $dst->{'file'}; &create_folder_maildir($dst); foreach $m (@_) { rename($m->{'file'}, "$dd/cur/$now.$$.$hn"); $now++; } } elsif (($src->{'type'} == 1 || $src->{'type'} == 3) && $dst->{'type'} == 3) { # Can move and rename to MH numbering local $dd = $dst->{'file'}; local $num = &max_mhdir($dst->{'file'}) + 1; foreach $m (@_) { rename($m->{'file'}, "$dd/$num"); $num++; } } else { # Append to new folder file, or create in folder directory local $m; foreach $m (@_) { &write_mail_folder($m, $dst); } &mailbox_delete_mail($src, @_); } # Force re-generation of source folder index if ($src->{'sortable'}) { &delete_sort_index($src); # XXX could be faster } } # mailbox_move_folder(&source, &dest) # Moves all mail from one folder to another, possibly converting the type sub mailbox_move_folder { return undef if (&is_readonly_mode()); local ($src, $dst) = @_; if ($src->{'type'} == $dst->{'type'}) { # Can just move the file or dir system("rm -rf ".quotemeta($dst->{'file'})); system("mv ".quotemeta($src->{'file'})." ".quotemeta($dst->{'file'})); } else { # Need to copy one by one :( local @mails = &mailbox_list_mails(undef, undef, $src); &mailbox_move_mail($src, $dst, @mails); } # Delete source folder index if ($src->{'sortable'}) { &delete_sort_index($src); } } # mailbox_copy_mail(&source, &dest, mail, ...) # Copy mail from one folder to another sub mailbox_copy_mail { return undef if (&is_readonly_mode()); local $src = shift(@_); local $dst = shift(@_); local $now = time(); &create_folder_maildir($dst); local $m; if ($src->{'type'} == 6 && $dst->{'type'} == 6) { # Copying from one virtual folder to another, so just copy the # reference foreach $m (@_) { push(@{$dst->{'members'}}, [ $m->{'subfolder'}, $m->{'subid'}, $m->{'header'}->{'message-id'} ]); } } elsif ($dst->{'type'} == 6) { # Add this mail to the index of the virtual folder foreach $m (@_) { push(@{$dst->{'members'}}, [ $src, $m->{'idx'}, $m->{'header'}->{'message-id'} ]); } &save_folder($dst); } else { # Just write to destination folder foreach $m (@_) { &write_mail_folder($m, $dst); } } } # folder_type(file_or_dir) sub folder_type { return -d "$_[0]/cur" ? 1 : -d $_[0] ? 3 : 0; } # create_folder_maildir(&folder) # Ensure that a maildir folder has the needed new, cur and tmp directories sub create_folder_maildir { mkdir($folders_dir, 0700); if ($_[0]->{'type'} == 1) { local $id = $_[0]->{'file'}; mkdir("$id/cur", 0700); mkdir("$id/new", 0700); mkdir("$id/tmp", 0700); } } # write_mail_folder(&mail, &folder, textonly) # Writes some mail message to a folder sub write_mail_folder { return undef if (&is_readonly_mode()); &create_folder_maildir($_[1]); if ($_[1]->{'type'} == 1) { # Add to a maildir directory local $md = $_[1]->{'file'}; &write_maildir($_[0], $md, $_[2]); } elsif ($_[1]->{'type'} == 3) { # Create a new MH file local $num = &max_mhdir($_[1]->{'file'}) + 1; local $md = $_[1]->{'file'}; &send_mail($_[0], "$md/$num", $_[2], 1); } elsif ($_[1]->{'type'} == 0) { # Just append to the folder file &send_mail($_[0], $_[1]->{'file'}, $_[2], 1); } elsif ($_[1]->{'type'} == 4) { # Upload to the IMAP server local @rv = &imap_login($_[1]); if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 3) { &error(&text('save_emailbox', $rv[1])); } elsif ($rv[0] == 2) { &error(&text('save_elogin2', $rv[1])); } local $h = $rv[1]; # Create a temp file and use it to create the IMAP command local $temp = &transname(); &send_mail($_[0], $temp, $_[2], 1); open(TEMP, $temp); local $text; while() { $text .= $_; } close(TEMP); unlink($temp); @rv = &imap_command($h, sprintf "APPEND %s {%d}\r\n%s", $_[1]->{'mailbox'} || "INBOX", length($text), $text); &error(&text('save_eappend', $rv[3])) if (!$rv[0]); } elsif ($_[1]->{'type'} == 5) { # Just append to the last subfolder local @sf = @{$_[1]->{'subfolders'}}; &write_mail_folder($_[0], $sf[$#sf], $_[2]); } elsif ($_[1]->{'type'} == 6) { # Add mail to first sub-folder, and to virtual index &error("Cannot add mail to virtual folders"); } } # mailbox_modify_mail(&oldmail, &newmail, &folder, textonly) # Replaces some mail message with a new one sub mailbox_modify_mail { return undef if (&is_readonly_mode()); if ($_[2]->{'type'} == 1) { # Just replace the existing file &modify_maildir($_[0], $_[1], $_[3]); } elsif ($_[2]->{'type'} == 3) { # Just replace the existing file &modify_mhdir($_[0], $_[1], $_[3]); } elsif ($_[2]->{'type'} == 0) { # Modify the mail file &modify_mail($_[2]->{'file'}, $_[0], $_[1], $_[3]); } elsif ($_[2]->{'type'} == 5 || $_[2]->{'type'} == 6) { # Modify in the appropriate folder local ($oldsubfolder, $oldidx) = &pop_index($_[0]); local ($newsubfolder, $newidx) = &pop_index($_[1]); &mailbox_modify_mail($_[0], $_[1], $oldsubfolder, $_[3]); &push_index($_[0], $oldsubfolder, $oldidx); &push_index($_[1], $newsubfolder, $newidx); } else { &error("Cannot modify mail in this type of folder!"); } # Force re-generation of folder index if ($_[2]->{'sortable'}) { &delete_sort_index($_[2]); # XXX could be faster } } # mailbox_folder_size(&folder, [estimate]) # Returns the number of messages in some folder sub mailbox_folder_size { if ($_[0]->{'type'} == 0) { # A mbox formatted file return &count_mail($_[0]->{'file'}); } elsif ($_[0]->{'type'} == 1) { # A qmail maildir return &count_maildir($_[0]->{'file'}); } elsif ($_[0]->{'type'} == 2) { # A POP3 server local @rv = &pop3_login($_[0]); if ($rv[0] != 1) { if ($rv[0] == 0) { &error($rv[1]); } else { &error(&text('save_elogin', $rv[1])); } } local @st = &pop3_command($rv[1], "stat"); if ($st[0] == 1) { local ($count, $size) = split(/\s+/, $st[1]); return $count; } else { &error($st[1]); } } elsif ($_[0]->{'type'} == 3) { # An MH directory return &count_mhdir($_[0]->{'file'}); } elsif ($_[0]->{'type'} == 4) { # An IMAP server local @rv = &imap_login($_[0]); if ($rv[0] != 1) { if ($rv[0] == 0) { &error($rv[1]); } elsif ($rv[0] == 3) { &error(&text('save_emailbox', $rv[1])); } elsif ($rv[0] == 2) { &error(&text('save_elogin2', $rv[1])); } } return $rv[2]; } elsif ($_[0]->{'type'} == 5) { # A composite folder - the size is just that of the sub-folders my $rv = 0; foreach my $sf (@{$_[0]->{'subfolders'}}) { $rv += &mailbox_folder_size($sf); } return $rv; } elsif ($_[0]->{'type'} == 6 && !$_[1]) { # A virtual folder .. we need to exclude messages that no longer # exist in the parent folders my $rv = 0; foreach my $msg (@{$_[0]->{'members'}}) { if (!$msg->[2] || &find_by_message_id($msg->[0], $msg->[2])) { $rv++; } } return $rv; } elsif ($_[0]->{'type'} == 6 && $_[1]) { # A virtual folder .. but we can just use the last member count return scalar(@{$_[0]->{'members'}}); } } # pop3_login(&folder) # Logs into a POP3 server and returns a status (1=ok, 0=connect failed, # 2=login failed) and handle or error message sub pop3_login { local $h = $pop3_login_handle{$_[0]->{'id'}}; return (1, $h) if ($h); $h = time().++$pop3_login_count; local $error; &open_socket($_[0]->{'server'}, $_[0]->{'port'} || 110, $h, \$error); return (0, $error) if ($error); local $os = select($h); $| = 1; select($os); local @rv = &pop3_command($h); return (0, $rv[1]) if (!$rv[0]); @rv = &pop3_command($h, "user $_[0]->{'user'}"); return (2, $rv[1]) if (!$rv[0]); @rv = &pop3_command($h, "pass $_[0]->{'pass'}"); return (2, $rv[1]) if (!$rv[0]); return (1, $pop3_login_handle{$_[0]->{'id'}} = $h); } # pop3_command(handle, command) # Executes a command and returns the status (1 or 0 for OK or ERR) and message sub pop3_command { local ($h, $c) = @_; print $h "$c\r\n" if ($c); local $rv = <$h>; $rv =~ s/\r|\n//g; return !$rv ? ( 0, "Connection closed" ) : $rv =~ /^\+OK\s*(.*)/ ? ( 1, $1 ) : $rv =~ /^\-ERR\s*(.*)/ ? ( 0, $1 ) : ( 0, $rv ); } # pop3_logout(handle, doquit) sub pop3_logout { local @rv = $_[1] ? &pop3_command($_[0], "quit") : (1, undef); local $f; foreach $f (keys %pop3_login_handle) { delete($pop3_login_handle{$f}) if ($pop3_login_handle{$f} eq $_[0]); } close($_[0]); return @rv; } # pop3_uidl(handle) # Returns the uidl list sub pop3_uidl { local @rv; local $h = $_[0]; local @urv = &pop3_command($h, "uidl"); if (!$urv[0] && $urv[1] =~ /not\s+implemented/i) { # UIDL is not available?! Use numeric list instead &pop3_command($h, "list"); while(<$h>) { s/\r//g; last if ($_ eq ".\n"); if (/^(\d+)\s+(\d+)/) { push(@rv, "size$2"); } } } elsif (!$urv[0]) { &error("uidl failed! $urv[1]") if (!$urv[0]); } else { # Can get normal UIDL list while(<$h>) { s/\r//g; last if ($_ eq ".\n"); if (/^(\d+)\s+(\S+)/) { push(@rv, $2); } } } return @rv; } # pop3_logout_all() # Properly closes all open POP3 and IMAP sessions sub pop3_logout_all { local $f; foreach $f (keys %pop3_login_handle) { &pop3_logout($pop3_login_handle{$f}, 1); } foreach $f (keys %imap_login_handle) { &imap_logout($imap_login_handle{$f}, 1); } } # imap_login(&folder) # Logs into a POP3 server, selects a mailbox and returns a status # (1=ok, 0=connect failed, 2=login failed, 3=mailbox error), a handle or error # message, and the number of messages in the mailbox. sub imap_login { local $h = $imap_login_handle{$_[0]->{'id'}}; return (1, $h) if ($h); $h = time().++$imap_login_count; local $error; &open_socket($_[0]->{'server'}, $_[0]->{'port'} || $imap_port, $h, \$error); return (0, $error) if ($error); local $os = select($h); $| = 1; select($os); # Login normally local @rv = &imap_command($h); return (0, $rv[3]) if (!$rv[0]); @rv = &imap_command($h, "login \"$_[0]->{'user'}\" \"$_[0]->{'pass'}\""); return (2, $rv[3]) if (!$rv[0]); # Select the right folder @rv = &imap_command($h, "select ".($_[0]->{'mailbox'} || "INBOX")); return (3, $rv[3]) if (!$rv[0]); return (1, $imap_login_handle{$_[0]->{'id'}} = $h, $rv[2] =~ /\*\s+(\d+)\s+EXISTS/i ? $1 : undef); } # imap_command(handle, command) # Executes an IMAP command and returns 1 for success or 0 for failure, and # a reference to an array of results (some of which may be multiline), and # all of the results joined together, and the stuff after OK/BAD sub imap_command { local ($h, $c) = @_; local @rv; # Send the command, and read lines until a non-* one is found local $id = $$."-".$imap_command_count++; if ($c) { print $h "$id $c\r\n"; } while(1) { local $l = <$h>; last if (!$l); if ($l =~ /^(\*|\+)/) { # Another response, and possibly the only one if no command # was sent. push(@rv, $l); last if (!$c); if ($l =~ /\{(\d+)\}\s*$/) { # Start of multi-line text .. read the specified size local $size = $1; local $got; local $err = "Error reading email"; while($got < $size) { local $buf; local $r = read($h, $buf, $size-$got); return (0, [ $err ], $err, $err) if ($r < 0); $rv[$#rv] .= $buf; $got += $r; } } } elsif ($l =~ /^(\S+)\s+/ && $1 eq $id) { # End of responses push(@rv, $l); last; } else { # Part of last response if (!@rv) { local $err = "Got unknown line $l"; return (0, [ $err ], $err, $err); } $rv[$#rv] .= $l; } } local $j = join("", @rv); local $lline = $rv[$#rv]; if ($lline =~ /^(\S+)\s+OK\s*(.*)/) { # Looks like the command worked return (1, \@rv, $j, $2); } else { # Command failed! return (0, \@rv, $j, $lline =~ /^(\S+)\s+(\S+)\s*(.*)/ ? $3 : undef); } } # imap_logout(handle, doquit) sub imap_logout { local @rv = $_[1] ? &imap_command($_[0], "close") : (1, undef); local $f; foreach $f (keys %imap_login_handle) { delete($imap_login_handle{$f}) if ($imap_login_handle{$f} eq $_[0]); } close($_[0]); return @rv; } # lock_folder(&folder) sub lock_folder { return if ($_[0]->{'remote'} || $_[0]->{'type'} == 5 || $_[0]->{'type'} == 6); local $f = $_[0]->{'file'} ? $_[0]->{'file'} : $_[0]->{'type'} == 0 ? &user_mail_file($remote_user) : $qmail_maildir; if (&lock_file($f)) { $_[0]->{'lock'} = $f; } else { # Cannot lock if in /var/mail local $ff = $f; $ff =~ s/\//_/g; $ff = "/tmp/$ff"; $_[0]->{'lock'} = $ff; &lock_file($ff); } # Also, check for a .filename.pop3 file if ($config{'pop_locks'} && $f =~ /^(\S+)\/([^\/]+)$/) { local $poplf = "$1/.$2.pop"; local $count = 0; while(-r $poplf) { sleep(1); if ($count++ > 5*60) { # Give up after 5 minutes &error(&text('epop3lock_tries', "$f", 5)); } } } } # unlock_folder(&folder) sub unlock_folder { return if ($_[0]->{'remote'}); &unlock_file($_[0]->{'lock'}); } # folder_file(&folder) # Returns the full path to the file or directory containing the folder's mail, # or undef if not appropriate (such as for POP3) sub folder_file { return $_[0]->{'remote'} ? undef : $_[0]->{'file'}; } # parse_imap_mail(response) # Parses a response from the IMAP server into a standard mail structure sub parse_imap_mail { # Extract the actual mail part local $mail = { }; local $realsize; local $imap = $_[0]; if ($imap =~ /RFC822.SIZE\s+(\d+)/) { $realsize = $1; } $imap =~ s/^\*\s+\d+\s+FETCH.*\{(\d+)\}\r?\n// || return undef; local $size = $1; local @lines = split(/\n/, substr($imap, 0, $size)); # Parse the headers local $lnum = 0; local @headers; while(1) { local $line = $lines[$lnum++]; $mail->{'size'} += length($line); $line =~ s/\r//g; last if ($line eq ''); if ($line =~ /^(\S+):\s*(.*)/) { push(@headers, [ $1, $2 ]); } elsif ($line =~ /^(\s+.*)/) { $headers[$#headers]->[1] .= $1 unless($#headers < 0); } } $mail->{'headers'} = \@headers; foreach $h (@headers) { $mail->{'header'}->{lc($h->[0])} = $h->[1]; } # Parse the body while($lnum < @lines) { $mail->{'size'} += length($lines[$lnum]+1); $mail->{'body'} .= $lines[$lnum]."\n"; $lnum++; } $mail->{'size'} = $realsize if ($realsize); return $mail; } # find_body(&mail, mode) # Returns the plain text body, html body and the one to use sub find_body { local ($a, $body, $textbody, $htmlbody); foreach $a (@{$_[0]->{'attach'}}) { if ($a->{'type'} =~ /^text\/plain/i || $a->{'type'} eq 'text') { $textbody = $a if (!$textbody && $a->{'data'} =~ /\S/); } elsif ($a->{'type'} =~ /^text\/html/i) { $htmlbody = $a if (!$htmlbody && $a->{'data'} =~ /\S/); } } if ($_[1] == 0) { $body = $textbody; } elsif ($_[1] == 1) { $body = $textbody || $htmlbody; } elsif ($_[1] == 2) { $body = $htmlbody || $textbody; } elsif ($_[1] == 3) { # Convert HTML to text if needed if ($textbody) { $body = $textbody; } else { local $text = &html_to_text($htmlbody->{'data'}); $body = $textbody = { 'data' => $text }; } } return ($textbody, $htmlbody, $body); } # safe_html(html) # Converts HTML to a form safe for inclusion in a page sub safe_html { local $html = $_[0]; local $bodystuff; if ($html =~ s/^[\000-\377]*]*)>//i) { $bodystuff = $1; } $html =~ s/<\/BODY>[\000-\377]*$//i; $html =~ s/]*>//i; $html = &filter_javascript($html); $html = &safe_urls($html); $bodystuff = &safe_html($bodystuff) if ($bodystuff); return wantarray ? ($html, $bodystuff) : $html; } # head_html(html) # Returns HTML in the section of a document sub head_html { local $html = $_[0]; return undef if ($html !~ /]*>/i || $html !~ /<\/HEAD[^>]*>/i); $html =~ s/^[\000-\377]*]*>//gi || &error("Failed to filter
".&html_escape($html)."
"); $html =~ s/<\/HEAD[^>]*>[\000-\377]*//gi || &error("Failed to filter
".&html_escape($html)."
"); $html =~ s/]*>//i; return &filter_javascript($html); } # safe_urls(html) # Replaces dangerous-looking URLs in HTML sub safe_urls { local $html = $_[0]; $html =~ s/((src|href|background)\s*=\s*)([^ '">]+)()/&safe_url($1, $3, $4)/gei; $html =~ s/((src|href|background)\s*=\s*')([^']+)(')/&safe_url($1, $3, $4)/gei; $html =~ s/((src|href|background)\s*=\s*")([^"]+)(")/&safe_url($1, $3, $4)/gei; return $html; } # safe_url(before, url, after) sub safe_url { local ($before, $url, $after) = @_; if ($url =~ /^#/) { # Relative link - harmless return $before.$url.$after; } elsif ($url =~ /^cid:/i) { # Definately safe (CIDs are harmless) return $before.$url.$after; } elsif ($url =~ /^(http:|https:)/) { # Possibly safe, unless refers to local local ($host, $port, $page, $ssl) = &parse_http_url($url); local ($hhost, $hport) = split(/:/, $ENV{'HTTP_HOST'}); $hport ||= $ENV{'SERVER_PORT'}; if ($host ne $hhost || $port != $hport || $ssl != (uc($ENV{'HTTPS'}) eq 'ON' ? 1 : 0)) { return $before.$url.$after; } else { return $before."_unsafe_link_".$after; } } else { # Relative URL like foo.cgi or /foo.cgi or ../foo.cgi - unsafe! return $before."_unsafe_link_".$after; } } # safe_uidl(string) sub safe_uidl { local $rv = $_[0]; $rv =~ s/\/|\./_/g; return $rv; } # html_to_text(html) # Attempts to convert some HTML to text form sub html_to_text { local ($h2, $lynx); if (($h2 = &has_command("html2text")) || ($lynx = &has_command("lynx"))) { # Can use a commonly available external program local $temp = &transname().".html"; open(TEMP, ">$temp"); print TEMP $_[0]; close(TEMP); open(OUT, ($lynx ? "$lynx -dump $temp" : "$h2 $temp")." 2>/dev/null |"); while() { if ($lynx && $_ =~ /^\s*References\s*$/) { # Start of Lynx references output $gotrefs++; } elsif ($lynx && $gotrefs && $_ =~ /^\s*(\d+)\.\s+(http|https|ftp|mailto)/) { # Skip this URL reference line } else { $text .= $_; } } close(OUT); unlink($temp); return $text; } else { # Do conversion manually :( local $html = $_[0]; $html =~ s/\s+/ /g; $html =~ s/

/\n\n/gi; $html =~ s/
/\n/gi; $html =~ s/<[^>]+>//g; $html = &entities_to_ascii($html); return $html; } } # folder_select(&folders, selected-folder, name, [extra-options]) # Returns HTML for selecting a folder sub folder_select { local $sel = "\n"; return $sel; } # folder_size(&folder, ...) # Sets the 'size' field of one or more folders, and returns the total sub folder_size { local ($f, $total); foreach $f (@_) { if ($f->{'type'} == 0) { # Single mail file - size is easy local @st = stat($f->{'file'}); $f->{'size'} = $st[7]; } elsif ($f->{'type'} == 1) { # Maildir folder size is that of all files in it $f->{'size'} = &recursive_disk_usage($f->{'file'}); } elsif ($f->{'type'} == 3) { # MH folder size is that of all mail files local $mf; $f->{'size'} = 0; opendir(MHDIR, $f->{'file'}); while($mf = readdir(MHDIR)) { next if ($mf eq "." || $mf eq ".."); local @st = stat("$f->{'file'}/$mf"); $f->{'size'} += $st[7]; } closedir(MHDIR); } elsif ($f->{'type'} == 5) { # Size of a combined folder is the size of all sub-folders return &folder_size(@{$f->{'subfolders'}}); } else { # Cannot get size of a remote folder $f->{'size'} = undef; } $total += $f->{'size'}; } return $total; } # parse_boolean(string) # Separates a string into a series of and/or separated values. Returns a # mode number (0=or, 1=and, 2=both) and a list of words sub parse_boolean { local @rv; local $str = $_[0]; local $mode = -1; local $lastandor = 0; while($str =~ /^\s*"([^"]*)"(.*)$/ || $str =~ /^\s*"([^"]*)"(.*)$/ || $str =~ /^\s*(\S+)(.*)$/) { local $word = $1; $str = $2; if (lc($word) eq "and") { if ($mode < 0) { $mode = 1; } elsif ($mode != 1) { $mode = 2; } $lastandor = 1; } elsif (lc($word) eq "or") { if ($mode < 0) { $mode = 0; } elsif ($mode != 0) { $mode = 2; } $lastandor = 1; } else { if (!$lastandor && @rv) { $rv[$#rv] .= " ".$word; } else { push(@rv, $word); } $lastandor = 0; } } $mode = 0 if ($mode < 0); return ($mode, \@rv); } # recursive_files(dir, treat-dirs-as-folders) sub recursive_files { local ($f, @rv); opendir(DIR, $_[0]); local @files = readdir(DIR); closedir(DIR); foreach $f (@files) { next if ($f eq "." || $f eq ".." || $f =~ /\.lock$/i || $f eq "cur" || $f eq "tmp" || $f eq "new" || $f =~ /^\.imap/i || $f eq ".customflags" || $f eq "dovecot-uidlist" || $f =~ /^courierimap/ || $f eq "maildirfolder" || $f eq "maildirsize"); local $p = "$_[0]/$f"; local $added = 0; if ($_[1] || !-d $p || -d "$p/cur") { push(@rv, $p); $added = 1; } # If this directory wasn't a folder (or it it in Maildir format), # search it too. if (-d "$p/cur" || !$added) { push(@rv, &recursive_files($p)); } } return @rv; } # editable_mail(&mail) # Returns 0 if some mail message should not be editable (ie. internal folder) sub editable_mail { return $_[0]->{'header'}->{'subject'} !~ /DON'T DELETE THIS MESSAGE.*FOLDER INTERNAL DATA/; } # fix_cids(html, &attachments, url-prefix, &cid-list) # Replaces HTML like img src=cid:XXX with img src=detach.cgi?whatever sub fix_cids { local $rv = $_[0]; $rv =~ s/(src="|href=")cid:([^"]+)(")/$1.&fix_cid($2,$_[1],$_[2],$_[3]).$3/gei; $rv =~ s/(src='|href=')cid:([^']+)(')/$1.&fix_cid($2,$_[1],$_[2],$_[3]).$3/gei; $rv =~ s/(src=|href=)cid:([^\s>]+)()/$1.&fix_cid($2,$_[1],$_[2],$_[3]).$3/gei; return $rv; } # fix_cid(cid, &attachments, url-prefix, &cid-list) sub fix_cid { local ($cont) = grep { $_->{'header'}->{'content-id'} eq $_[0] || $_->{'header'}->{'content-id'} eq "<$_[0]>" } @{$_[1]}; return "cid:$_[0]" if (!$cont); push(@{$_[3]}, $cont) if ($_[3]); return "$_[2]&attach=$cont->{'idx'}"; } # quoted_message(&mail, quote-mode, sig, 0=any,1=text,2=html) # Returns the quoted text, html-flag and body attachment sub quoted_message { local ($mail, $qu, $sig, $bodymode) = @_; local $mode = $bodymode == 1 ? 1 : $bodymode == 2 ? 2 : defined(%userconfig) ? $userconfig{'view_html'} : $config{'view_html'}; local ($plainbody, $htmlbody) = &find_body($mail, $mode); local ($quote, $html_edit, $body); local $cfg = defined(%userconfig) ? \%userconfig : \%config; local @writers = &split_addresses($mail->{'header'}->{'from'}); local $writer = ($writers[0]->[1] || $writers[0]->[0])." wrote .."; local $tm; if ($cfg->{'reply_date'} && ($tm = &parse_mail_date($_[0]->{'header'}->{'date'}))) { local $tmstr = &make_date($tm); $writer = "On $tmstr $writer"; } local $qm = defined(%userconfig) ? $userconfig{'html_quote'} : $config{'html_quote'}; if (($cfg->{'html_edit'} == 2 || $cfg->{'html_edit'} == 1 && $htmlbody) && $bodymode != 1) { # Create quoted body HTML if ($htmlbody) { $body = $htmlbody; $sig =~ s/\n/
\n/g; if ($qu && $qm == 0) { # Quoted HTML as cite $quote = "$writer\n". "

\n". &safe_html($htmlbody->{'data'}). "
".$sig."
\n"; } elsif ($qu && $qm == 1) { # Quoted HTML below line $quote = "
$sig
". "$writer
\n". &safe_html($htmlbody->{'data'}); } else { # Un-quoted HTML $quote = &safe_html($htmlbody->{'data'}). $sig."
\n"; } } elsif ($plainbody) { $body = $plainbody; local $pd = $plainbody->{'data'}; $pd =~ s/^\s+//g; $pd =~ s/\s+$//g; if ($qu && $qm == 0) { # Quoted plain text as HTML as cite $quote = "$writer\n". "
\n". "
$pd
". "
".$sig."
\n"; } elsif ($qu && $qm == 1) { # Quoted plain text as HTML below line $quote = "
$sig
". "$writer
\n". "
$pd

\n"; } else { # Un-quoted plain text as HTML $quote = "
$pd
". $sig."
\n"; } } $html_edit = 1; } else { # Create quoted body text if ($plainbody) { $body = $plainbody; $quote = $plainbody->{'data'}; } elsif ($htmlbody) { $body = $htmlbody; $quote = &html_to_text($htmlbody->{'data'}); } if ($quote && $qu) { $quote = join("", map { "> $_\n" } &wrap_lines($quote, 70)); } $quote = $writer."\n".$quote if ($quote && $qu); $quote .= "$sig\n" if ($sig); } return ($quote, $html_edit, $body); } # modification_time(&folder) # Returns the unix time on which this folder was last modified, or 0 if unknown sub modification_time { if ($_[0]->{'type'} == 0) { # Modification time of file local @st = stat($_[0]->{'file'}); return $st[9]; } elsif ($_[0]->{'type'} == 1) { # Greatest modification time of cur/new directory local @stcur = stat("$_[0]->{'file'}/cur"); local @stnew = stat("$_[0]->{'file'}/new"); return $stcur[9] > $stnew[9] ? $stcur[9] : $stnew[9]; } elsif ($_[0]->{'type'} == 2 || $_[0]->{'type'} == 4) { # Cannot know for POP3 or IMAP folders return 0; } elsif ($_[0]->{'type'} == 3) { # Modification time of MH folder local @st = stat($_[0]->{'file'}); return $st[9]; } else { # Huh? return 0; } } # requires_delivery_notification(&mail) sub requires_delivery_notification { return $_[0]->{'header'}->{'disposition-notification-to'} || $_[0]->{'header'}->{'read-reciept-to'}; } # send_delivery_notification(&mail, [from-addr], manual) # Send an email containing delivery status information sub send_delivery_notification { local ($mail, $from) = @_; $from ||= $mail->{'header'}->{'to'}; local $host = &get_display_hostname(); local $to = &requires_delivery_notification($mail); local $product = &get_product_name(); $product = ucfirst($product); local $version = &get_webmin_version(); local ($taddr) = &split_addresses($mail->{'header'}->{'to'}); local $disp = $manual ? "manual-action/MDN-sent-manually" : "automatic-action/MDN-sent-automatically"; local $dsn = <[0] Final-Recipient: rfc822;$taddr->[0] Original-Message-ID: $mail->{'header'}->{'message-id'} Disposition: $disp; displayed EOF local $dmail = { 'headers' => [ [ 'From' => $from ], [ 'To' => $to ], [ 'Subject' => 'Delivery notification' ], [ 'Content-type' => 'multipart/report; report-type=disposition-notification' ], [ 'Content-Transfer-Encoding' => '7bit' ] ], 'attach' => [ { 'headers' => [ [ 'Content-type' => 'text/plain' ] ], 'data' => "This is a delivery status notification for the email sent to:\n$mail->{'header'}->{'to'}\non the date:\n$mail->{'header'}->{'date'}\nwith the subject:\n$mail->{'header'}->{'subject'}\n" }, { 'headers' => [ [ 'Content-type' => 'message/disposition-notification' ], [ 'Content-Transfer-Encoding' => '7bit' ] ], 'data' => $dsn } ] }; eval { local $main::errors_must_die = 1; &send_mail($dmail); }; return $to; } # find_named_folder(name, &folders, [&cache]) # Finds a folder by ID, filename, server name or displayed name sub find_named_folder { local $rv; if ($_[2] && exists($_[2]->{$_[0]})) { # In cache $rv = $_[2]->{$_[0]}; } else { # Need to lookup ($rv) = grep { $_->{'id'} eq $_[0] } @{$_[1]} if (!$rv); ($rv) = grep { my $escfile = $_->{'file'}; $escfile =~ s/\s/_/g; $escfile eq $_[0] || $_->{'file'} eq $_[0] || $_->{'server'} eq $_[0] } @{$_[1]} if (!$rv); ($rv) = grep { my $escname = $_->{'name'}; $escname =~ s/\s/_/g; $escname eq $_[0] || $_->{'name'} eq $_[0] } @{$_[1]} if (!$rv); $_[2]->{$_[0]} = $rv if ($_[2]); } return $rv; } # folder_name(&folder) # Returns a unique identifier for a folder, based on it's filename or ID sub folder_name { my $rv = $_[0]->{'id'} || $_[0]->{'file'} || $_[0]->{'server'} || $_[0]->{'name'}; $rv =~ s/\s/_/g; return $rv; } # set_folder_lastmodified(&folders) # Sets the last-modified time and sortable flag on all given folders sub set_folder_lastmodified { local ($folders) = @_; foreach my $folder (@$folders) { if ($folder->{'type'} == 0 || $folder->{'type'} == 3) { # For an mbox or MH folder, the last modified date is just that # of the file or directory itself local @st = stat($folder->{'file'}); $folder->{'lastchange'} = $st[9]; $folder->{'sortable'} = 1; } elsif ($folder->{'type'} == 1) { # For a Maildir folder, the date is that of the newest # sub-directory (cur, tmp or new) $folder->{'lastchange'} = 0; foreach my $sf ("cur", "tmp", "new") { local @st = stat("$folder->{'file'}/$sf"); $folder->{'lastchange'} = $st[9] if ($st[9] > $folder->{'lastchange'}); } $folder->{'sortable'} = 1; } elsif ($folder->{'type'} == 6) { # For a virtual folder, the date is that of the newest # sub-folder, OR the folder file itself local @st = stat($folder->{'folderfile'}); $folder->{'lastchange'} = $st[9]; my %done; foreach my $m (@{$folder->{'members'}}) { if (!$done{$m->[0]}++) { &set_folder_lastmodified([ $m->[0] ]); $folder->{'lastchange'} = $m->[0]->{'lastchange'} if ($m->[0]->{'lastchange'} > $folder->{'lastchange'}); } } $folder->{'sortable'} = 1; } else { # For POP3 and IMAP folders, we don't know the last change $folder->{'lastchange'} = undef; $folder->{'sortable'} = 1; } } } # push_index(&mail, &folder, new-index) # Adjusts the index of some email to the new one, and stores the old # index and folder sub push_index { local ($mail, $folder, $newidx) = @_; unshift(@{$mail->{'subs'}}, [ $mail->{'subfolder'}, $mail->{'idx'} ]); $mail->{'subidx'} = $mail->{'subs'}->[0]->[1]; $mail->{'subfolder'} = $folder; $mail->{'idx'} = $newidx; } # pop_index(&mail) # Removes the stored sub-folder and index, and restores the original index. # Returns the original sub-folder and index. sub pop_index { local ($mail) = @_; local $old = shift(@{$mail->{'subs'}}); $mail->{'subidx'} = $mail->{'subs'}->[0]->[1]; local @rv = ( $mail->{'subfolder'}, $mail->{'idx'} ); $mail->{'subfolder'} = $old->[0]; $mail->{'idx'} = $old->[1]; return @rv; } # mail_preview(&mail) # Returns a short text preview of a message body sub mail_preview { local ($textbody, $htmlbody, $body) = &find_body($_[0], 0); local $data = $body->{'data'}; $data =~ s/\r?\n/ /g; $data = substr($data, 0, 100); if ($data =~ /\S/) { return $data; } return undef; } 1; mailboxes/defaultacl0100664000567100000120000000006210030276176014553 0ustar jcameronwheelmmode=1 fmode=0 attach=-1 canattach=1 candetach=1 mailboxes/view_mail.cgi0100755000567100000120000002706410437656042015205 0ustar jcameronwheel#!/usr/local/bin/perl # view_mail.cgi # View a single email message require './mailboxes-lib.pl'; $force_charset = ''; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); if (&is_user($in{'user'})) { @uinfo = &get_mail_user($in{'user'}); @uinfo || &error($text{'view_eugone'}); } $uuser = &urlize($in{'user'}); @folders = &list_user_folders($in{'user'}); $folder = $folders[$in{'folder'}]; @mail = &mailbox_list_mails($in{'idx'}, $in{'idx'}, $folder); $mail = $mail[$in{'idx'}]; &parse_mail($mail, undef, $in{'raw'}); @sub = split(/\0/, $in{'sub'}); $subs = join("", map { "&sub=$_" } @sub); foreach $s (@sub) { # We are looking at a mail within a mail .. local $amail = &extract_mail($mail->{'attach'}->[$s]->{'data'}); &parse_mail($amail, undef, $in{'raw'}); $mail = $amail; } dbmopen(%read, "$module_config_directory/$in{'user'}.read", 0600); eval { $read{$mail->{'header'}->{'message-id'}} = 1 } if (!$read{$mail->{'header'}->{'message-id'}}); if ($in{'raw'}) { # Special mode - viewing whole raw message print "Content-type: text/plain\n\n"; if ($mail->{'fromline'}) { print $mail->{'fromline'},"\n"; } if (defined($mail->{'rawheaders'})) { #$mail->{'rawheaders'} =~ s/(\S)\t/$1\n\t/g; print $mail->{'rawheaders'}; } else { foreach $h (@{$mail->{'headers'}}) { #$h->[1] =~ s/(\S)\t/$1\n\t/g; print "$h->[0]: $h->[1]\n"; } } print "\n"; print $mail->{'body'}; exit; } # Find body attachment and type ($textbody, $htmlbody, $body) = &find_body($mail, $config{'view_html'}); $body = $htmlbody if ($in{'body'} == 2); $body = $textbody if ($in{'body'} == 1); @attach = @{$mail->{'attach'}}; # Show pre-body HTML if ($body && $body eq $htmlbody) { $headstuff = &head_html($body->{'data'}); } &mail_page_header($text{'view_title'}, $headstuff, undef, &folder_link($in{'user'}, $folder)); print &check_clicks_function(); &show_arrows(); print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; foreach $s (@sub) { print "\n"; } # Find any delivery status attachment ($dstatus) = grep { $_->{'type'} eq 'message/delivery-status' } @attach; # Strip out attachments not to display as icons @attach = grep { $_ ne $body && $_ ne $dstatus } @attach; @attach = grep { !$_->{'attach'} } @attach; if ($config{'top_buttons'} == 2 && &editable_mail($mail)) { &show_mail_buttons(1, scalar(@sub)); print "

\n"; } print "\n"; print "\n"; print "
", "\n"; print "
$text{'view_headers'} \n"; if ($in{'headers'}) { print "$text{'view_noheaders'}\n"; } else { print "$text{'view_allheaders'}\n"; } print "  $text{'view_raw'}
\n"; if ($in{'headers'}) { # Show all the headers if ($mail->{'fromline'}) { print "", "\n"; } foreach $h (@{$mail->{'headers'}}) { print " ", "\n"; } } else { # Just show the most useful headers print " ", "\n"; print " ", "\n"; print " ", "\n" if ($mail->{'header'}->{'cc'}); print " ", "\n"; print " ", "\n"; } print "
$text{'mail_rfc'}",&eucconv_and_escape($mail->{'fromline'}), "
$h->[0]:",&eucconv_and_escape(&decode_mimewords($h->[1])), "
$text{'mail_from'}",&address_link($mail->{'header'}->{'from'}),"
$text{'mail_to'}",&address_link($mail->{'header'}->{'to'}),"
$text{'mail_cc'}",&address_link($mail->{'header'}->{'cc'}),"
$text{'mail_date'}",&eucconv_and_escape($mail->{'header'}->{'date'}), "
$text{'mail_subject'}",&eucconv_and_escape(&decode_mimewords( $mail->{'header'}->{'subject'})),"

\n"; # Show body attachment, with properly linked URLs if ($body && $body->{'data'} =~ /\S/) { if ($body eq $textbody) { # Show plain text $bodycontents = "

";
		foreach $l (&wrap_lines(&eucconv($body->{'data'}),
					$config{'wrap_width'})) {
			$bodycontents .= &link_urls_and_escape($l,
						$config{'link_mode'})."\n";
			}
		$bodycontents .= "
"; if ($htmlbody) { $bodyright = "$text{'view_ashtml'}"; } } elsif ($body eq $htmlbody) { # Attempt to show HTML $bodycontents = &safe_html($body->{'data'}); $bodycontents = &fix_cids($bodycontents, \@attach, "detach.cgi?user=$uuser&idx=$in{'idx'}&folder=$in{'folder'}$subs"); if ($textbody) { $bodyright = "$text{'view_astext'}"; } } } if ($bodycontents) { print "\n"; print "\n"; print "
", " ", "
$text{'view_body'}$bodyright
\n"; print $bodycontents; print "

\n"; } # Show delivery status if ($dstatus) { print "\n"; print "\n"; print "
$text{'view_dstatus'}
\n"; local $ds = &parse_delivery_status($dstatus->{'data'}); foreach $dsh ('final-recipient', 'diagnostic-code', 'remote-mta', 'reporting-mta') { if ($ds->{$dsh}) { $ds->{$dsh} =~ s/^\S+;//; print "\n"; print "\n"; } } print "
", $text{'view_'.$dsh},"",&html_escape($ds->{$dsh}),"

\n"; } # Display other attachments if (@attach) { print "\n"; print "\n"; print "
$text{'view_attach'}
\n"; foreach $a (@attach) { local $fn; $size = (int(length($a->{'data'})/1000)+1)." Kb"; local $cb; if ($a->{'type'} eq 'message/rfc822') { push(@titles, "$text{'view_sub'}
$size"); } elsif ($a->{'filename'}) { push(@titles, &decode_mimewords($a->{'filename'}). "
$size"); $fn = &decode_mimewords($a->{'filename'}); push(@detach, [ $a->{'idx'}, $fn ]); } else { push(@titles, "$a->{'type'}
$size"); $a->{'type'} =~ /\/(\S+)$/; $fn = "file.$1"; push(@detach, [ $a->{'idx'}, $fn ]); } if ($a->{'error'}) { $titles[$#titles] .= "
($a->{'error'})"; } $fn =~ s/ /_/g; $fn =~ s/\#/_/g; $fn = &html_escape($fn); if ($a->{'type'} eq 'message/rfc822') { push(@links, "view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$uuser$subs&sub=$a->{'idx'}"); } else { push(@links, "detach.cgi/$fn?idx=$in{'idx'}&folder=$in{'folder'}&user=$uuser&attach=$a->{'idx'}$subs"); } if ($config{'thumbnails'} && ($a->{'type'} =~ /image\/gif/i && &has_command("giftopnm")&& &has_command("pnmscale") && &has_command("cjpeg") || $a->{'type'} =~ /image\/jpeg/i && &has_command("djpeg") && &has_command("pnmscale") && &has_command("cjpeg"))) { # Can show an image icon push(@icons, "detach.cgi?scale=1&idx=$in{'idx'}&folder=$in{'folder'}&attach=$a->{'idx'}$subs"); $imgicons++; } else { push(@icons, "images/boxes.gif"); } } &icons_table(\@links, \@titles, \@icons, 6, undef, $imgicons ? ( 0, 0 ) : ( )); if ($access{'candetach'} && @detach && defined($uinfo[2])) { print "\n"; print "\n" if ($body); print "\n"; print "$text{'view_dir'}\n"; print " ", &file_chooser_button("dir", 1),"\n"; } print "

\n"; } &show_mail_buttons(2, scalar(@sub)) if (&editable_mail($mail)); if ($config{'arrows'} == 2 && !@sub) { &show_arrows(); } print "

\n"; dbmclose(%read); local @sr = !@sub ? ( ) : ( "view_mail.cgi?idx=$in{'idx'}", $text{'view_return'} ), $s = int((@mail - $in{'idx'} - 1) / $config{'perpage'}) * $config{'perpage'}; &mail_page_footer(@sub ? ( "view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$uuser", $text{'view_return'} ) : ( ), "list_mail.cgi?folder=$in{'folder'}&user=$uuser", $text{'mail_return'}, "", $text{'index_return'}); # show_mail_buttons(pos, submode) sub show_mail_buttons { local $spacer = " \n"; if (!$_[1]) { print ""; print $spacer; if (!$folder->{'sent'} && !$folder->{'drafts'}) { $m = $read{$mail->{'header'}->{'message-id'}}; print ""; print ""; print $spacer; } } if (&is_user($in{'user'})) { print ""; print $spacer; } print ""; print $spacer; if (&is_user($in{'user'})) { print ""; print ""; print $spacer; } print ""; print $spacer; # Show spam report buttons @modules = &get_available_module_infos(1); ($hasspam) = grep { $_->{'dir'} eq "spam" } @modules; if (&foreign_installed("spam") && $config{'spam_buttons'} =~ /mail/ && &spam_report_cmd($in{'user'})) { if ($hasspam) { print ""; } if ($config{'spam_del'}) { print "\n"; } else { print "\n"; } } print "
\n"; } sub show_arrows { print "
\n"; if (!@sub) { if ($in{'idx'}) { print "", "\n"; } print "",&text('view_desc', $in{'idx'}+1, $folder->{'name'}),"\n"; if ($in{'idx'} < @mail-1) { print "", "\n"; } } else { print "$text{'view_sub'}\n"; } print "

\n"; } # address_link(address) sub address_link { local @addrs = &split_addresses(&decode_mimewords($_[0])); local @rv; foreach $a (@addrs) { push(@rv, &eucconv_and_escape($a->[2])); } return join(" , ", @rv); } mailboxes/detach.cgi0100755000567100000120000000536710367554333014465 0ustar jcameronwheel#!/usr/local/bin/perl # detach.cgi # View one attachment from a message use Socket; require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); @folders = &list_user_folders($in{'user'}); $folder = $folders[$in{'folder'}]; @mail = &mailbox_list_mails($in{'idx'}, $in{'idx'}, $folder); $mail = $mail[$in{'idx'}]; &parse_mail($mail); @sub = split(/\0/, $in{'sub'}); foreach $s (@sub) { # We are looking at a mail within a mail .. local $amail = &extract_mail($mail->{'attach'}->[$s]->{'data'}); &parse_mail($amail); $mail = $amail; } $attach = $mail->{'attach'}->[$in{'attach'}]; if ($in{'scale'}) { # Scale the gif or jpeg image to 48 pixels high local $temp = &transname(); open(TEMP, ">$temp"); print TEMP $attach->{'data'}; close(TEMP); $SIG{'CHLD'} = sub { wait; }; if ($attach->{'type'} eq 'image/gif') { ($pnmin, $pnmout) = &pipeopen("giftopnm $temp"); } elsif ($attach->{'type'} eq 'image/jpeg') { ($pnmin, $pnmout) = &pipeopen("djpeg -fast $temp"); } else { &dump_erroricon(); } close($pnmin); $type = <$pnmout>; $size = <$pnmout>; unlink($temp); $type =~ /^P[0-9]/ || &dump_erroricon(); $size =~ /(\d+)\s+(\d+)/ || &dump_erroricon(); ($w, $h) = ($1, $2); if ($w > 48) { $scale = 48.0 / $w; } else { $scale = 48.0 / $h; } ($jpegin, $jpegout) = &pipeopen("pnmscale $scale 2>/dev/null | cjpeg"); print $jpegin $type; print $jpegin $size; while(read($pnmout, $buf, 1024)) { print $jpegin $buf; } close($jpegin); close($pnmout); print "Content-type: image/jpeg\n\n"; while(read($jpegout, $buf, 1024)) { print $buf; } close($jpegout); } else { # Just output the attachment print "X-no-links: 1\n"; @download = split(/\t+/, $config{'download'}); if (&indexof($attach->{'type'}, @download) >= 0) { # Force download in IE print "Content-Disposition: Attachment\n"; } if ($attach->{'type'} eq 'message/delivery-status') { print "Content-type: text/plain\n\n"; } else { print "Content-type: $attach->{'type'}\n\n"; } if ($attach->{'type'} =~ /^text\/html/i) { print &safe_urls(&filter_javascript($attach->{'data'})); } else { print $attach->{'data'}; } } &pop3_logout_all(); sub dump_erroricon { print "Content-type: image/gif\n\n"; open(ICON, "images/error.gif"); while() { print; } close(ICON); exit; } # pipeopen(command) sub pipeopen { $pipe++; local $inr = "INr$pipe"; local $inw = "INw$pipe"; local $outr = "OUTr$pipe"; local $outw = "OUTw$pipe"; pipe($inr, $inw); pipe($outr, $outw); if (!fork()) { untie(*STDIN); untie(*STDOUT); open(STDIN, "<&$inr"); open(STDOUT, ">&$outw"); close($inw); close($outr); exec($_[0]); print STDERR "exec failed : $!\n"; exit 1; } close($inr); close($outw); return ($inw, $outr); } mailboxes/mail_search.cgi0100775000567100000120000001414610435240011015456 0ustar jcameronwheel#!/usr/local/bin/perl # mail_search.cgi # Find mail messages matching some pattern require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); @folders = &list_user_folders($in{'user'}); if ($in{'simple'}) { # Make sure a search was entered $in{'search'} || &error($text{'search_ematch'}); $ofolder = $folders[$in{'folder'}]; } else { # Validate search fields for($i=0; defined($in{"field_$i"}); $i++) { if ($in{"field_$i"}) { $in{"what_$i"} || &error(&text('search_ewhat', $i+1)); $neg = $in{"neg_$i"} ? "!" : ""; push(@fields, [ $neg.$in{"field_$i"}, $in{"what_$i"} ]); } } @fields || &error($text{'search_enone'}); $ofolder = $folders[$in{'ofolder'}]; } if ($in{'folder'} == -2) { $desc = $text{'search_local'}; } elsif ($in{'folder'} == -1) { $desc = $text{'search_all'}; } else { $folder = $folders[$in{'folder'}]; $desc = &text('mail_for', $folder->{'name'}); } &ui_print_header($desc, $text{'search_title'}, "", undef, 0, 0, undef, &folder_link($in{'user'}, $ofolder)); if ($in{'simple'}) { if ($in{'search'} =~ /^(\S+):\s*(.*)$/) { # A specific field was entered local ($field, $what) = ($1, $2); @searchlist = ( [ $field, $what ] ); @rv = &mailbox_search_mail(\@searchlist, 0, $folder); print "

",&text('search_results5', scalar(@rv), "$field", "$what")," ..

\n"; } else { # Just search by Subject and From in one folder ($mode, $words) = &parse_boolean($in{'search'}); if ($mode == 0) { # Can just do a single 'or' search @searchlist = map { ( [ 'subject', $_ ], [ 'from', $_ ] ) } @$words; @rv = &mailbox_search_mail(\@searchlist, 0, $folder); } elsif ($mode == 1) { # Need to do two 'and' searches and combine @searchlist1 = map { ( [ 'subject', $_ ] ) } @$words; @rv1 = &mailbox_search_mail(\@searchlist1, 1, $folder); @searchlist2 = map { ( [ 'from', $_ ] ) } @$words; @rv2 = &mailbox_search_mail(\@searchlist2, 1, $folder); @rv = @rv1; %gotidx = map { $_->{'idx'}, 1 } @rv; foreach $mail (@rv2) { push(@rv, $mail) if (!$gotidx{$mail->{'idx'}}); } } else { &error($text{'search_eboolean'}); } print "

",&text('search_results2', scalar(@rv), "$in{'search'}")," ..

\n"; } foreach $mail (@rv) { $mail->{'folder'} = $folder; } } else { # Complex search, perhaps over multiple folders! if ($in{'folder'} == -2) { @sfolders = grep { !$_->{'remote'} } @folders; $multi_folder = 1; } elsif ($in{'folder'} == -1) { @sfolders = @folders; $multi_folder = 1; } else { @sfolders = ( $folder ); } foreach $sf (@sfolders) { local @frv = &mailbox_search_mail(\@fields, $in{'and'}, $sf); foreach $mail (@frv) { $mail->{'folder'} = $sf; } push(@rv, @frv); } print "

",&text('search_results4', scalar(@rv))," ..

\n"; } @rv = reverse(@rv); $showto = $folder->{'sent'} || $folder->{'drafts'}; if (@rv) { print "

\n"; print "\n"; print "\n"; if ($config{'top_buttons'}) { if (!$multi_folder) { &show_buttons(1, \@folders, $folder, \@rv, $in{'user'}, 1); print &select_all_link("d", 0, $text{'mail_all'}), " \n"; print &select_invert_link("d", 0, $text{'mail_invert'}), " 
\n"; } } # Show mailbox headers local @hcols; push(@hcols, ""); push(@hcols, $showto ? $text{'mail_to'} : $text{'mail_from'}); push(@hcols, $config{'show_to'} ? $showto ? ( $text{'mail_from'} ) : ( $text{'mail_to'} ) : ()); push(@hcols, $text{'mail_date'}); push(@hcols, $text{'mail_size'}); push(@hcols, $text{'mail_subject'}); print &ui_columns_start(\@hcols, 100, 0, \@tds); } foreach $m (@rv) { local $idx = $m->{'idx'}; local $mf = $m->{'folder'}; local @cols; local $from = &simplify_from($m->{'header'}->{ $showto ? 'to' : 'from'}); $from = $text{'mail_unknown'} if ($from !~ /\S/); push(@cols, "$from"); if ($config{'show_to'}) { push(@cols, &simplify_from( $m->{'header'}->{$showto ? 'from' : 'to'})); } push(@cols, &simplify_date($m->{'header'}->{'date'})); push(@cols, &nice_size($m->{'size'}, 1024)); local $tbl; $tbl .= "". "
".&simplify_subject($m->{'header'}->{'subject'}). " "; if ($m->{'header'}->{'content-type'} =~ /multipart\/\S+/i) { $tbl .= ""; } local $p = int($m->{'header'}->{'x-priority'}); if ($p == 1) { $tbl .= " "; } elsif ($p == 2) { $tbl .= " "; } if (!$showto) { if ($read{$m->{'header'}->{'message-id'}} == 2) { $tbl .= " "; } elsif ($read{$m->{'header'}->{'message-id'}} == 1) { $tbl .= " "; } } $tbl .= "
\n"; push(@cols, $tbl); if (&editable_mail($m)) { print &ui_checked_columns_row(\@cols, \@tds, "d", $idx); } elsif ($multi_folder) { print &ui_columns_row([ $mf->{'name'}, @cols ], \@tds); } else { print &ui_columns_row([ "", @cols ], \@tds); } if ($config{'show_body'}) { # Show part of the body too &parse_mail($m); local $data = &mail_preview($m); if ($data) { print " ", &html_escape($data)," \n"; } } } if (@rv) { print &ui_columns_end(); if (!$multi_folder) { print &select_all_link("d", 0, $text{'mail_all'})," \n"; print &select_invert_link("d", 0, $text{'mail_invert'})," 

\n"; &show_buttons(2, \@folders, $folder, \@rv, $in{'user'}, 1); } print "

\n"; } else { print "$text{'search_none'}

\n"; } &ui_print_footer($in{'simple'} ? ( ) : ( "search_form.cgi?folder=$in{'folder'}", $text{'sform_return'} ), "list_mail.cgi?user=$in{'user'}&folder=$in{'folder'}", $text{'mail_return'}, "", $text{'index_return'}); mailboxes/search_form.cgi0100775000567100000120000000346710153207232015510 0ustar jcameronwheel#!/usr/local/bin/perl # search_form.cgi # Display a form for searching a mailbox require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); @folders = &list_user_folders_sorted($in{'user'}); ($folder) = grep { $_->{'index'} == $in{'folder'} } @folders; &ui_print_header(undef, $text{'sform_title'}, "", undef, 0, 0, undef, &folder_link($in{'user'}, $folder)); print "

\n"; print "\n"; print "\n"; print " $text{'sform_and'}\n"; print " $text{'sform_or'}

\n"; print "\n"; #print " ", # " ", # "\n"; for($i=0; $i<=9; $i++) { print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } print "
$text{'sform_field'}$text{'sform_mode'}$text{'sform_for'}
$text{'sform_where'}$text{'sform_text'}

\n"; $extra = "

\n"; &ui_print_footer("index.cgi?folder=$in{'folder'}", $text{'mail_return'}, "", $text{'index_return'}); mailboxes/delete_mail.cgi0100755000567100000120000001556510332313121015456 0ustar jcameronwheel#!/usr/local/bin/perl # delete_mail.cgi # Delete, mark, move or copy multiple messages require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); @delete = sort { $a <=> $b } split(/\0/, $in{'d'}); @folders = &list_user_folders($in{'user'}); $folder = $folders[$in{'folder'}]; if ($in{'mark1'} || $in{'mark2'}) { # Marking emails with some status @delete || &error($text{'delete_emnone'}); @mail = &mailbox_list_mails($delete[0], $delete[@delete-1], $folder); dbmopen(%read, "$module_config_directory/$in{'user'}.read", 0600); local $m = $in{'mark1'} ? $in{'mode1'} : $in{'mode2'}; foreach $d (@delete) { local $hid = $mail[$d]->{'header'}->{'message-id'}; if ($m) { $read{$hid} = $m; } else { delete($read{$hid}); } } dbmclose(%read); $perpage = $folder->{'perpage'} || $config{'perpage'}; &redirect("list_mail.cgi?start=$in{'start'}&folder=$in{'folder'}&user=$in{'user'}"); } elsif ($in{'move1'} || $in{'move2'}) { # Moving mails to some other user's inbox &check_modification($folder); @delete || &error($text{'delete_emovenone'}); $muser = $in{'move1'} ? $in{'mfolder1'} : $in{'mfolder2'}; &can_user($muser) || &error($text{'delete_emovecannot'}); @mfolders = &list_user_folders($muser); @mfolders || &error($text{'delete_emoveuser'}); @mail = &mailbox_list_mails($delete[0], $delete[@delete-1], $folder); foreach $d (@delete) { $mail[$d] || &error($text{'mail_eexists'}); push(@movemail, $mail[$d]); } &lock_folder($folder); &lock_folder($mfolder); &mailbox_move_mail($folder, $mfolders[0], @movemail); &unlock_folder($mfolder); &unlock_folder($folder); &webmin_log("movemail", undef, undef, { 'from' => $folder->{'file'}, 'to' => $mfolders[0]->{'file'}, 'count' => scalar(@delete) } ); &redirect("list_mail.cgi?start=$in{'start'}&folder=$in{'folder'}&user=$in{'user'}"); } elsif ($in{'copy1'} || $in{'copy2'}) { # Copying mails to some other folder @delete || &error($text{'delete_ecopynone'}); $cuser = $in{'copy1'} ? $in{'mfolder1'} : $in{'mfolder2'}; &can_user($cuser) || &error($text{'delete_ecopycannot'}); @cfolders = &list_user_folders($cuser); @cfolders || &error($text{'delete_ecopyuser'}); @mail = &mailbox_list_mails($delete[0], $delete[@delete-1], $folder); foreach $d (@delete) { $mail[$d] || &error($text{'mail_eexists'}); push(@copymail, $mail[$d]); } &lock_folder($cfolder); &mailbox_copy_mail($folder, $cfolders[0], @copymail); &unlock_folder($cfolder); &webmin_log("copymail", undef, undef, { 'from' => $folder->{'file'}, 'to' => $cfolders[0]->{'file'}, 'count' => scalar(@delete) } ); &redirect("list_mail.cgi?start=$in{'start'}&folder=$in{'folder'}&user=$in{'user'}"); } elsif ($in{'forward'}) { # Forwarding selected mails .. redirect @delete || &error($text{'delete_efnone'}); &redirect("reply_mail.cgi?folder=$in{'folder'}&user=$in{'user'}&". join("&", map { "mailforward=$_" } @delete)); } elsif ($in{'new'}) { # Need to redirect to compose form &redirect("reply_mail.cgi?new=1&folder=$in{'folder'}&user=$in{'user'}"); } elsif ($in{'black'}) { # Deny all senders @delete || &error($text{'delete_ebnone'}); @mail = &mailbox_list_mails($delete[0], $delete[@delete-1], $folder); foreach $d (@delete) { push(@addrs, map { $_->[0] } &split_addresses($mail[$d]->{'header'}->{'from'})); } &foreign_require("spam", "spam-lib.pl"); local $conf = &spam::get_config(); local @from = map { @{$_->{'words'}} } &spam::find("blacklist_from", $conf); local %already = map { $_, 1 } @from; @newaddrs = grep { !$already{$_} } &unique(@addrs); push(@from, @newaddrs); &spam::save_directives($conf, 'blacklist_from', \@from, 1); &flush_file_lines(); &redirect("list_mail.cgi?start=$in{'start'}&folder=$in{'folder'}&user=$in{'user'}"); } elsif ($in{'razor'}) { # Report all messages, and show output to the user @delete || &error($text{'delete_ebnone'}); &ui_print_header(undef, $text{'razor_title'}, ""); print "$text{'razor_report2'}\n"; print "
";

	# Write all messages to a temp file
	@mail = &mailbox_list_mails($delete[0], $delete[@delete-1], $folder);
	$temp = &transname();
	$cmd = &spam_report_cmd($in{'user'});
	foreach $d (@delete) {
		$mail[$d] || &error($text{'mail_eexists'});
		&send_mail($mail[$d], $temp);
		push(@delmail, $mail[$d]);
		}

	# Call reporting command on them
	&open_execute_command(OUT, "$cmd <$temp 2>&1", 1);
	local $error;
	while() {
		print &html_escape($_);
		$error++ if (/failed/i);
		}
	close(OUT);
	unlink($temp);
	print "
\n"; if ($? || $error) { print "$text{'razor_err'}

\n"; } else { if ($config{'spam_del'}) { # Delete spam too &lock_folder($folder); &mailbox_delete_mail($folder, @delmail); &unlock_folder($folder); print "$text{'razor_deleted'}

\n"; } else { print "$text{'razor_done'}

\n"; } } &ui_print_footer("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); } elsif ($in{'delete'} || $in{'deleteall'}) { # Just deleting emails &check_modification($folder); @delete || $in{'deleteall'} || &error($text{'delete_enone'}); if (!$in{'confirm'} && &need_delete_warn($folder)) { # Need to ask for confirmation before deleting &ui_print_header(undef, $text{'confirm_title'}, ""); print &check_clicks_function(); print "

\n"; foreach $i (keys %in) { foreach $v (split(/\0/, $in{$i})) { print "\n"; } } print "
\n"; if ($in{'deleteall'}) { print &text('confirm_warnall'),"
\n"; } else { print &text('confirm_warn', scalar(@delete)),"
\n"; } if ($config{'delete_warn'} ne 'y') { print "$text{'confirm_warn2'}

\n" } else { print "$text{'confirm_warn4'}

\n" } print "

\n"; &ui_print_footer("list_mail.cgi?start=$in{'start'}&folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}); } else { # Go ahead and delete &lock_folder($folder); if ($in{'deleteall'}) { # Clear the whole folder $delcount = &mailbox_folder_size($folder); &mailbox_empty_folder($folder); } else { # Just delete selected messages @mail = &mailbox_list_mails($delete[0], $delete[@delete-1], $folder); foreach $d (@delete) { $mail[$d] || &error($text{'mail_eexists'}); push(@delmail, $mail[$d]); } &mailbox_delete_mail($folder, @delmail); $delcount = scalar(@delmail); } &unlock_folder($folder); &webmin_log("delmail", undef, undef, { 'from' => $folder->{'file'}, 'all' => $in{'deleteall'}, 'count' => $delcount } ); &redirect("list_mail.cgi?start=$in{'start'}&folder=$in{'folder'}&user=$in{'user'}"); } } &pop3_logout_all(); mailboxes/reply_mail.cgi0100755000567100000120000004241010437660407015356 0ustar jcameronwheel#!/usr/local/bin/perl # Display a form for replying to or composing an email require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); @uinfo = &get_mail_user($in{'user'}); @uinfo || &error($text{'view_eugone'}); @folders = &list_user_folders($in{'user'}); $folder = $folders[$in{'folder'}]; if ($in{'new'}) { # Composing a new email $html_edit = 1 if ($config{'html_edit'} == 2); $sig = &get_signature($in{'user'}); if ($html_edit) { $sig =~ s/\n/
\n/g; $quote = ""; } else { $quote = "\n\n$sig" if ($sig); } &mail_page_header($text{'compose_title'}, undef, $html_edit ? "onload='initEditor()'" : "", &folder_link($in{'user'}, $folder)); } else { # Replying or forwarding if ($in{'mailforward'} ne '') { # Replying to multiple @mailforward = sort { $a <=> $b } split(/\0/, $in{'mailforward'}); @mails = &mailbox_list_mails( $mailforward[0], $mailforward[@mailforward-1], $folder); $mail = $mails[$mailforward[0]]; } else { # Replying to one @mails = &mailbox_list_mails($in{'idx'}, $in{'idx'}, $folder); $mail = $mails[$in{'idx'}]; &decode_and_sub(); } &check_modification($folder) if ($in{'delete'}); $mail || &error($text{'mail_eexists'}); if ($in{'delete'}) { # Just delete the email if (!$in{'confirm'} && &need_delete_warn($folder)) { # Need to ask for confirmation before deleting &mail_page_header($text{'confirm_title'}, undef, undef, &folder_link($in{'user'}, $folder)); print &check_clicks_function(); print "
\n"; foreach $i (keys %in) { foreach $v (split(/\0/, $in{$i})) { print "\n"; } } print "
$text{'confirm_warn3'}
\n"; if ($config{'delete_warn'} ne 'y') { print "$text{'confirm_warn2'}

\n" } else { print "$text{'confirm_warn4'}

\n" } print "

\n"; &mail_page_footer("view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$in{'user'}", $text{'view_return'}, "list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); exit; } &lock_folder($folder); &mailbox_delete_mail($folder, $mail); &unlock_folder($folder); &webmin_log("delmail", undef, undef, { 'from' => $folder->{'file'}, 'count' => 1 } ); &redirect("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}"); exit; } elsif ($in{'print'}) { # Extract the mail body &decode_and_sub(); ($textbody, $htmlbody, $body) = &find_body($mail, $config{'view_html'}); # Output HTML header &PrintHeader(); print "\n"; print "",&html_escape(&decode_mimewords( $mail->{'header'}->{'subject'})),"\n"; print "\n"; # Display the headers print "\n"; print "\n"; print "
$text{'view_headers'}
\n"; print " ", "\n"; print " ", "\n"; print " ", "\n" if ($mail->{'header'}->{'cc'}); print " ", "\n"; print " ", "\n"; print "
$text{'mail_from'}",&eucconv_and_escape($mail->{'header'}->{'from'}),"
$text{'mail_to'}",&eucconv_and_escape($mail->{'header'}->{'to'}),"
$text{'mail_cc'}",&eucconv_and_escape($mail->{'header'}->{'cc'}),"
$text{'mail_date'}",&eucconv_and_escape(&html_escape($mail->{'header'}->{'date'})), "
$text{'mail_subject'}",&eucconv_and_escape(&decode_mimewords( $mail->{'header'}->{'subject'})),"

\n"; # Just display the mail body for printing if ($body eq $textbody) { print "
";
			foreach $l (&wrap_lines($body->{'data'},
						$config{'wrap_width'})) {
				print &eucconv_and_escape($l),"\n";
				}
			print "
\n"; } elsif ($body eq $htmlbody) { print "
\n"; print &safe_html($body->{'data'}); print "
\n"; } print "\n"; exit; } elsif ($in{'mark1'} || $in{'mark2'}) { # Just mark the message dbmopen(%read, "$module_config_directory/$in{'user'}.read", 0600); $mode = $in{'mark1'} ? $in{'mode1'} : $in{'mode2'}; if ($mode) { $read{$mail->{'header'}->{'message-id'}} = $mode; } else { delete($read{$mail->{'header'}->{'message-id'}}); } $perpage = $folder->{'perpage'} || $config{'perpage'}; $s = int((@mails - $in{'idx'} - 1) / $perpage) * $perpage; &redirect("list_mail.cgi?start=$s&folder=$in{'folder'}&user=$in{'user'}"); exit; } elsif ($in{'detach'}) { # Detach some attachment to a directory on the server &error_setup($text{'detach_err'}); $in{'dir'} || &error($text{'detach_edir'}); $in{'dir'} = "$uinfo[7]/$in{'dir'}" if ($in{'dir'} !~ /^\//); &decode_and_sub(); if ($in{'attach'} eq '*') { # Detaching all attachments, under their filenames @dattach = grep { $_->{'idx'} ne $in{'bindex'} } @{$mail->{'attach'}}; } else { # Just one attachment @dattach = ( $mail->{'attach'}->[$in{'attach'}] ); } local @paths; foreach $attach (@dattach) { local $path; if (-d $in{'dir'}) { # Just write to the filename in the directory local $fn; if ($attach->{'filename'}) { $fn = &decode_mimewords( $attach->{'filename'}); } else { $attach->{'type'} =~ /\/(\S+)$/; $fn = "file.$1"; } $path = "$in{'dir'}/$fn"; } else { # Assume a full path was given $path = $in{'dir'}; } push(@paths, $path); } &switch_to_user($in{'user'}); for($i=0; $i<@dattach; $i++) { # Try to write the files &open_tempfile(FILE, ">$paths[$i]", 1, 1) || &error(&text('detach_eopen', "$paths[$i]", $!)); (print FILE $dattach[$i]->{'data'}) || &error(&text('detach_ewrite', "$paths[$i]", $!)); close(FILE) || &error(&text('detach_ewrite', "$paths[$i]", $!)); } &switch_user_back(); # Show a message about the new files &mail_page_header($text{'detach_title'}, undef, undef, &folder_link($in{'user'}, $folder)); for($i=0; $i<@dattach; $i++) { local $sz = (int(length($dattach[$i]->{'data'}) / 1000)+1)." Kb"; print "

",&text('detach_ok', "$paths[$i]", $sz),"

\n"; } &mail_page_footer("view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$in{'user'}", $text{'view_return'}, "list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); exit; } elsif ($in{'black'}) { # Add sender to global SpamAssassin blacklist, and tell user &mail_page_header($text{'black_title'}); &foreign_require("spam", "spam-lib.pl"); local $conf = &spam::get_config(); local @from = map { @{$_->{'words'}} } &spam::find("blacklist_from", $conf); local %already = map { $_, 1 } @from; local ($spamfrom) = &address_parts($mail->{'header'}->{'from'}); if ($already{$spamfrom}) { print "",&text('black_already', "$spamfrom"),"

\n"; } else { push(@from, $spamfrom); &spam::save_directives($conf, 'blacklist_from', \@from, 1); &flush_file_lines(); print "",&text('black_done', "$spamfrom"),"

\n"; } &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); exit; } elsif ($in{'razor'}) { # Report message to Razor and tell user &mail_page_header($text{'razor_title'}); print "$text{'razor_report'}\n"; print "

";
		local $cmd = &spam_report_cmd($in{'user'});
		local $temp = &transname();
		&send_mail($mail, $temp, 0, 1);
		&open_execute_command(OUT, "$cmd <$temp 2>&1", 1);
		local $error;
		while() {
			print &html_escape($_);
			$error++ if (/failed/i);
			}
		close(OUT);
		unlink($temp);
		print "
\n"; if ($? || $error) { print "$text{'razor_err'}

\n"; } else { if ($config{'spam_del'}) { # Delete message too &lock_folder($folder); &mailbox_delete_mail($folder, $mail); &unlock_folder($folder); print "$text{'razor_deleted'}

\n"; } else { print "$text{'razor_done'}

\n"; } } &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); exit; } if (!@mailforward) { &parse_mail($mail); @attach = @{$mail->{'attach'}}; } if ($in{'strip'}) { # Remove all non-body attachments local $newmail = { 'headers' => $mail->{'headers'}, 'header' => $mail->{'header'}, 'fromline' => $mail->{'fromline'} }; foreach $a (@attach) { if ($a->{'type'} eq 'text/plain' || $a->{'type'} eq 'text') { $newmail->{'attach'} = [ $a ]; last; } } &lock_folder($folder); &mailbox_modify_mail($mail, $newmail, $folder); &unlock_folder($folder); &redirect("list_mail.cgi?user=$in{'user'}&folder=$in{'folder'}"); exit; } if ($in{'enew'}) { # Editing an existing message, so keep same fields $to = $mail->{'header'}->{'to'}; $rto = $mail->{'header'}->{'reply-to'}; $from = $mail->{'header'}->{'from'}; $cc = $mail->{'header'}->{'cc'}; $ouser = $1 if ($from =~ /^(\S+)\@/); } else { if (!$in{'forward'} && !@mailforward) { # Replying to a message, so set To: field $to = $mail->{'header'}->{'reply-to'}; $to = $mail->{'header'}->{'from'} if (!$to); } if ($in{'rall'}) { # If replying to all, add any addresses in the original # To: or Cc: to our new Cc: address. # XXX should strip own addresses $cc = $mail->{'header'}->{'to'}; $cc .= ", ".$mail->{'header'}->{'cc'} if ($mail->{'header'}->{'cc'}); } } # Work out new subject, depending on whether we are replying # our forwarding a message (or neither) local $qu = !$in{'enew'} && (!$in{'forward'} || !$config{'fwd_mode'}); $subject = &html_escape(&decode_mimewords( $mail->{'header'}->{'subject'})); $subject = "Re: ".$subject if ($subject !~ /^Re/i && !$in{'forward'} && !@mailforward && !$in{'enew'}); $subject = "Fwd: ".$subject if ($subject !~ /^Fwd/i && ($in{'forward'} || @mailforward)); # Construct the initial mail text $sig = &get_signature($in{'user'}); ($quote, $html_edit, $body) = "ed_message($mail, $qu, $sig); if ($in{'forward'} || $in{'enew'}) { @attach = grep { $_ ne $body } @attach; } else { undef(@attach); } # Show header &mail_page_header( $in{'forward'} || @mailforward ? $text{'forward_title'} : $in{'enew'} ? $text{'enew_title'} : $text{'reply_title'}, undef, $html_edit ? "onload='initEditor()'" : "", &folder_link($in{'user'}, $folder)); } print "

\n"; # Output various hidden fields print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; foreach $s (@sub) { print "\n"; } print "\n"; print "\n"; print "
$text{'reply_headers'}
\n"; # Work out and show the From: address print "\n"; $from ||= &get_user_from_address(\@uinfo); if ($access{'fmode'} == 0) { # Any email addresss print "\n"; } elsif ($access{'fmode'} == 1) { # Any username in selected domains local $u = $ouser ? $ouser : $in{'user'}; $u =~ s/\@.*$//; print "\n"; } elsif ($access{'fmode'} == 2) { # Listed from addresses print "\n"; } elsif ($access{'fmode'} == 3) { # Fixed address in fixed domain print "\n"; } $to = &html_escape($to); print " ", "\n"; $cc = &html_escape($cc); print " ", "\n"; print " ", "\n"; print " ", "\n"; print " ", "\n"; print "
$text{'mail_from'}$ouser\@$access{'from'}$text{'mail_to'}
$text{'mail_cc'}$text{'mail_bcc'}
$text{'mail_subject'}$text{'mail_pri'}\n", "\n", "
\n", "

\n"; # Output message body input print "\n", "", "
$text{'reply_body'}
"; if ($html_edit) { # Output HTML editor textarea print < _editor_url = "/$module_name/htmlarea/"; _editor_lang = "en"; EOF print "\n"; } else { # Show text editing area print "\n"; if (&has_command("ispell")) { print "
\n"; print " $text{'reply_spell'}\n"; } } print "

\n"; print "\n"; # Display forwarded attachments if (@attach) { print "\n"; print "\n"; print "
$text{'reply_attach'}
\n"; foreach $a (@attach) { push(@titles, "{'idx'} checked> ".($a->{'filename'} ? $a->{'filename'} : $a->{'type'})); push(@links, "detach.cgi?idx=$in{'idx'}&folder=$in{'folder'}&attach=$a->{'idx'}$subs"); push(@icons, "images/boxes.gif"); } &icons_table(\@links, \@titles, \@icons, 8); print "

\n"; } # Display forwarded mails if (@mailforward) { print "\n"; print "\n"; print "
$text{'reply_mailforward'}
\n"; foreach $f (@mailforward) { push(@titles, &simplify_subject($mails[$f]->{'header'}->{'subject'})); push(@links, "view_mail.cgi?idx=$f&folder=$in{'folder'}&user=$in{'user'}"); push(@icons, "images/boxes.gif"); print "\n"; } &icons_table(\@links, \@titles, \@icons, 8); print "

\n"; } # Add form for more attachments print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; if ($access{'canattach'}) { print "\n"; print "\n"; print "\n"; } print "
$text{'reply_attach2'}
", &file_chooser_button("file0")," ", &file_chooser_button("file1")," ", &file_chooser_button("file2"),"

\n"; print "\n"; print "

\n"; &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); sub decode_and_sub { return if (!$mail); &parse_mail($mail); @sub = split(/\0/, $in{'sub'}); $subs = join("", map { "&sub=$_" } @sub); foreach $s (@sub) { # We are looking at a mail within a mail .. local $amail = &extract_mail( $mail->{'attach'}->[$s]->{'data'}); &parse_mail($amail); $mail = $amail; } } mailboxes/send_mail.cgi0100755000567100000120000002025110437656611015155 0ustar jcameronwheel#!/usr/local/bin/perl # send_mail.cgi # Send off an email message require './mailboxes-lib.pl'; &ReadParseMime(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); # Check inputs @folders = &list_user_folders($in{'user'}); $folder = $folders[$in{'folder'}]; &error_setup($text{'send_err'}); $in{'to'} || &error($text{'send_eto'}); if ($access{'fmode'} == 0) { $in{'from'} || &error($text{'send_efrom'}); } elsif ($access{'fmode'} == 1) { foreach $f (split(/\s+/, $access{'from'})) { $found++ if ("$in{'user'}\@$f" eq $in{'from'} || "$in{'ouser'}\@$f" eq $in{'from'}); } &error($text{'send_efrom'}) if (!$found); } elsif ($access{'fmode'} == 2) { foreach $f (split(/\s+/, $access{'from'})) { $found++ if ($f eq $in{'from'}); } &error($text{'send_efrom'}) if (!$found); } elsif ($access{'fmode'} == 3) { $in{'from'} .= "\@$access{'from'}"; } if ($in{'from'} =~ /^(\S+)\@(\S+)$/ && $access{'fromname'}) { $in{'from'} = "$access{'fromname'} <$in{'from'}>"; } @sub = split(/\0/, $in{'sub'}); $subs = join("", map { "&sub=$_" } @sub); # Construct the email $in{'from'} || &error($text{'send_efrom'}); $mail->{'headers'} = [ [ 'From', $in{'from'} ], [ 'Subject', $in{'subject'} ], [ 'To', $in{'to'} ], [ 'Cc', $in{'cc'} ], [ 'Bcc', $in{'bcc'} ], [ 'X-Originating-IP', $ENV{'REMOTE_ADDR'} ], [ 'X-Mailer', "Webmin ".&get_webmin_version() ] ]; push(@{$mail->{'headers'}}, [ 'X-Priority', $in{'pri'} ]) if ($in{'pri'}); $in{'body'} =~ s/\r//g; if ($in{'body'} =~ /\S/) { if ($in{'spell'}) { pipe(INr, INw); pipe(OUTr, OUTw); select(INw); $| = 1; select(OUTr); $| = 1; select(STDOUT); if (!fork()) { close(INw); close(OUTr); untie(*STDIN); untie(*STDOUT); untie(*STDERR); open(STDOUT, ">&OUTw"); open(STDERR, ">/dev/null"); open(STDIN, "<&INr"); exec("ispell -a"); exit; } close(INr); close(OUTw); local $indent = " " x 4; local @errs; foreach $line (split(/\n+/, $in{'body'})) { next if ($line !~ /\S/); print INw $line,"\n"; local @lerrs; while(1) { ($spell = ) =~ s/\r|\n//g; last if (!$spell); if ($spell =~ /^#\s+(\S+)/) { # Totally unknown word push(@lerrs, $indent.&text('send_eword', "".&html_escape($1)."")); } elsif ($spell =~ /^&\s+(\S+)\s+(\d+)\s+(\d+):\s+(.*)/) { # Maybe possible word, with options push(@lerrs, $indent.&text('send_eword2', "".&html_escape($1)."", "".&html_escape($4)."")); } elsif ($spell =~ /^\?\s+(\S+)/) { # Maybe possible word push(@lerrs, $indent.&text('send_eword', "".&html_escape($1)."")); } } if (@lerrs) { push(@errs, &text('send_eline', "".&html_escape($line)."")."
".join("
", @lerrs)."

\n"); } } close(INw); close(OUTr); if (@errs) { # Spelling errors found! &mail_page_header($text{'compose_title'}, undef, undef, &folder_link($in{'user'}, $folder)); print "$text{'send_espell'}

\n"; print @errs; &mail_page_footer("index.cgi?user=$in{'user'}&folder=$in{'folder'}", $text{'mail_return'}); exit; } } local $mt = $in{'html_edit'} ? "text/html" : "text/plain"; if ($in{'body'} =~ /[\177-\377]/) { # Contains 8-bit characters .. need to make quoted-printable $quoted_printable++; @attach = ( { 'headers' => [ [ 'Content-Type', $mt ], [ 'Content-Transfer-Encoding', 'quoted-printable' ] ], 'data' => quoted_encode($in{'body'}) } ); } else { # Plain 7-bit ascii text @attach = ( { 'headers' => [ [ 'Content-Type', $mt ], [ 'Content-Transfer-Encoding', '7bit' ] ], 'data' => $in{'body'} } ); } $bodyattach = $attach[0]; } $attachsize = 0; foreach $i (0 .. 5) { # Add uploaded attachment next if (!$in{"attach$i"}); &test_max_attach($attachsize); local $filename = $in{"attach${i}_filename"}; $filename =~ s/^.*(\\|\/)//; local $type = $in{"attach${i}_content_type"}."; name=\"". $filename."\""; local $disp = "inline; filename=\"".$filename."\""; push(@attach, { 'data' => $in{"attach${i}"}, 'headers' => [ [ 'Content-type', $type ], [ 'Content-Disposition', $disp ], [ 'Content-Transfer-Encoding', 'base64' ] ] }); $atotal += length($in{"attach${i}"}); } foreach $i (0 .. 2) { # Add server-side attachment next if (!$in{"file$i"} || !$access{'canattach'}); @uinfo = &get_mail_user($in{'user'}); @uinfo || &error($text{'view_eugone'}); if ($in{"file$i"} !~ /^\//) { $in{"file$i"} = $uinfo[7]."/".$in{"file$i"}; } local @st = stat($in{"file$i"}); &test_max_attach($st[7]); local $data; &switch_to_user($in{'user'}); open(DATA, $in{"file$i"}) || &error(&text('send_efile', $in{"file$i"}, $!)); while() { $data .= $_; } close(DATA); &switch_user_back(); $in{"file$i"} =~ s/^.*\///; local $type = &guess_mime_type($in{"file$i"}). "; name=\"".$in{"file$i"}."\""; local $disp = "inline; filename=\"".$in{"file$i"}."\""; push(@attach, { 'data' => $data, 'headers' => [ [ 'Content-type', $type ], [ 'Content-Disposition', $disp ], [ 'Content-Transfer-Encoding', 'base64' ] ] }); $atotal += length($data); } @fwd = split(/\0/, $in{'forward'}); if (@fwd) { # Add forwarded attachments @mail = &mailbox_list_mails($in{'idx'}, $in{'idx'}, $folder); $fwdmail = $mail[$in{'idx'}]; &parse_mail($fwdmail); foreach $s (@sub) { # We are looking at a mail within a mail .. local $amail = &extract_mail($fwdmail->{'attach'}->[$s]->{'data'}); &parse_mail($amail); $fwdmail = $amail; } foreach $f (@fwd) { &test_max_attach(length($fwdmail->{'attach'}->[$f]->{'data'})); push(@attach, $fwdmail->{'attach'}->[$f]); $atotal += length($fwdmail->{'attach'}->[$f]->{'data'}); } } @mailfwd = split(/\0/, $in{'mailforward'}); if (@mailfwd) { # Add forwarded emails @mail = &mailbox_list_mails($mailfwd[0], $mailfwd[@mailfwd-1], $folder); foreach $f (@mailfwd) { $fwdmail = $mail[$f]; local $headertext; foreach $h (@{$fwdmail->{'headers'}}) { $headertext .= $h->[0].": ".$h->[1]."\n"; } push(@attach, { 'data' => $headertext."\n".$fwdmail->{'body'}, 'headers' => [ [ 'Content-type', 'message/rfc822' ], [ 'Content-Description', $fwdmail->{'header'}->{'subject'} ] ] }); } } $mail->{'attach'} = \@attach; if ($access{'attach'} >= 0 && $atotal > $access{'attach'}*1024) { &error(&text('send_eattach', $access{'attach'})); } # Check for text-only email $textonly = $config{'no_mime'} && !$quoted_printable && @{$mail->{'attach'}} == 1 && $mail->{'attach'}->[0] eq $bodyattach && !$in{'html_edit'}; # Send it off &send_mail($mail, undef, $textonly, $config{'no_crlf'}); &webmin_log("send", undef, undef, { 'from' => $in{'from'}, 'to' => $in{'to'} }); # Tell the user that email as sent &mail_page_header($text{'send_title'}, undef, undef, &folder_link($in{'user'}, $folder)); @tos = ( split(/,/, $in{'to'}), split(/,/, $in{'cc'}), split(/,/, $in{'bcc'}) ); $tos = join(" , ", map { "".&html_escape($_)."" } @tos); print "

",&text($in{'draft'} ? 'send_draft' : 'send_ok', $tos),"

\n"; if ($in{'idx'} ne '') { &mail_page_footer("view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$in{'user'}$subs", $text{'view_return'}, "list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); } else { &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}", $text{'mail_return'}, "", $text{'index_return'}); } # write_attachment(&attach) sub write_attachment { local ($a) = @_; local ($enc, $rv); foreach $h (@{$a->{'headers'}}) { $rv .= $h->[0].": ".$h->[1]."\r\n"; $enc = $h->[1] if (lc($h->[0]) eq 'content-transfer-encoding'); } $rv .= "\r\n"; if (lc($enc) eq 'base64') { local $encoded = &encode_base64($a->{'data'}); $encoded =~ s/\r//g; $encoded =~ s/\n/\r\n/g; $rv .= $encoded; } else { $a->{'data'} =~ s/\r//g; $a->{'data'} =~ s/\n/\r\n/g; $rv .= $a->{'data'}; if ($a->{'data'} !~ /\n$/) { $rv .= "\r\n"; } } return $rv; } sub test_max_attach { $attachsize += $_[0]; if ($access{'attach'} >= 0 && $attachsize > $access{'attach'}) { &error(&text('send_eattachsize', $access{'attach'})); } } mailboxes/find.cgi0100775000567100000120000000134110212514047014126 0ustar jcameronwheel#!/usr/local/bin/perl # find.cgi # Display users matching some criteria require './mailboxes-lib.pl'; &ReadParse(); # Build a list of all matching users foreach $uinfo (&list_mail_users()) { if (&can_user(@$uinfo)) { if ($in{'match'} == 0 && lc($in{'user'}) eq $uinfo->[0] || $in{'match'} == 1 && $uinfo->[0] =~ /\Q$in{'user'}\E/i) { push(@users, $uinfo); } } } if (@users == 1) { # Can go direct to user &redirect("list_mail.cgi?user=$users[0]->[0]"); } elsif (@users == 0) { # No matches &error($text{'find_enone'}); } else { # Show table of matches &ui_print_header(undef, $text{'find_title'}, ""); print &text('find_results', $in{'user'}),"

\n"; &show_users_table(\@users); &ui_print_footer(); } mailboxes/acl_security.pl0100644000567100000120000001226710213250075015550 0ustar jcameronwheel require 'mailboxes-lib.pl'; # acl_security_form(&options) # Output HTML for editing security options for the sendmail module sub acl_security_form { # Users whose mail can be read print " $text{'acl_read'} \n"; printf " $text{'acl_none'}\n", $_[0]->{'mmode'} == 0 ? "checked" : ""; printf " $text{'acl_same'}\n", $_[0]->{'mmode'} == 4 ? "checked" : ""; printf " $text{'acl_all'}
\n", $_[0]->{'mmode'} == 1 ? "checked" : ""; printf " $text{'acl_users'}\n", $_[0]->{'mmode'} == 2 ? "checked" : ""; printf " %s
\n", $_[0]->{'mmode'} == 2 ? $_[0]->{'musers'} : "", &user_chooser_button("musers", 1); printf " $text{'acl_userse'}\n", $_[0]->{'mmode'} == 3 ? "checked" : ""; printf " %s
\n", $_[0]->{'mmode'} == 3 ? $_[0]->{'musers'} : "", &user_chooser_button("muserse", 1); printf " $text{'acl_usersg'}\n", $_[0]->{'mmode'} == 5 ? "checked" : ""; printf " %s\n", $_[0]->{'mmode'} == 5 ? join(" ", map { scalar(getgrgid($_)) } split(/\s+/, $_[0]->{'musers'})) : "", &group_chooser_button("musersg", 1); printf " %s
\n", $_[0]->{'msec'} ? "checked" : "", $text{'acl_sec'}; printf " $text{'acl_usersu'}\n", $_[0]->{'mmode'} == 7 ? "checked" : ""; printf " -\n", $_[0]->{'mmode'} == 7 ? $_[0]->{'musers'} : ""; printf "
\n", $_[0]->{'mmode'} == 7 ? $_[0]->{'musers2'} : ""; printf " $text{'acl_usersm'}\n", $_[0]->{'mmode'} == 6 ? "checked" : ""; printf " \n", $_[0]->{'mmode'} == 6 ? $_[0]->{'musers'} : ""; # Directory for arbitrary files print " $text{'acl_dir'} \n"; print &ui_opt_textbox("dir", $_[0]->{'dir'}, 40, $text{'acl_dirauto'}."
"); print " \n"; # Allowed From: addresses print " $text{'acl_from'} \n"; printf " $text{'acl_any'}
\n", $_[0]->{'fmode'} == 0 ? "checked" : ""; printf " $text{'acl_fdoms'}\n", $_[0]->{'fmode'} == 1 ? "checked" : ""; printf "
\n", $_[0]->{'fmode'} == 1 ? $_[0]->{'from'} : ''; printf " $text{'acl_faddrs'}\n", $_[0]->{'fmode'} == 2 ? "checked" : ""; printf "
\n", $_[0]->{'fmode'} == 2 ? $_[0]->{'from'} : ''; printf " $text{'acl_fdom'}\n", $_[0]->{'fmode'} == 3 ? "checked" : ""; printf "
\n", $_[0]->{'fmode'} == 3 ? $_[0]->{'from'} : ''; print " \n"; print " $text{'acl_fromname'}\n"; print " \n"; print " $text{'acl_attach'} \n"; printf " %s\n", $_[0]->{'attach'}<0 ? 'checked' : '', $text{'acl_unlimited'}; printf "\n", $_[0]->{'attach'}<0 ? '' : 'checked'; printf " kB\n", $_[0]->{'attach'}<0 ? '' : $_[0]->{'attach'}; print " \n"; print " $text{'acl_canattach'}\n"; printf " %s\n", $_[0]->{'canattach'} ? 'checked' : '', $text{'yes'}; printf " %s\n", $_[0]->{'canattach'} ? '' : 'checked', $text{'no'}; print "$text{'acl_candetach'}\n"; printf " %s\n", $_[0]->{'candetach'} ? 'checked' : '', $text{'yes'}; printf " %s \n", $_[0]->{'candetach'} ? '' : 'checked', $text{'no'}; } # acl_security_save(&options) # Parse the form for security options for the sendmail module sub acl_security_save { $_[0]->{'mmode'} = $in{'mmode'}; $_[0]->{'musers'} = $in{'mmode'} == 2 ? $in{'musers'} : $in{'mmode'} == 3 ? $in{'muserse'} : $in{'mmode'} == 5 ? join(" ", map { scalar(getgrnam($_)) } split(/\s+/, $in{'musersg'})) : $in{'mmode'} == 6 ? $in{'musersm'} : $in{'mmode'} == 7 ? $in{'musersu1'} : ""; $_[0]->{'musers2'} = $in{'mmode'} == 7 ? $in{'musersu2'} : ""; $_[0]->{'msec'} = $in{'msec'}; $_[0]->{'fmode'} = $in{'fmode'}; $_[0]->{'from'} = $in{'fmode'} == 0 ? undef : $in{'fmode'} == 1 ? $in{'fdoms'} : $in{'fmode'} == 2 ? $in{'faddrs'} : $in{'fdom'}; $_[0]->{'fromname'} = $in{'fromname'}; $_[0]->{'attach'} = $in{'attach_def'} ? -1 : $in{'attach'}; $_[0]->{'canattach'} = $in{'canattach'}; $_[0]->{'candetach'} = $in{'candetach'}; $_[0]->{'dir'} = $in{'dir_def'} ? undef : $in{'dir'}; } mailboxes/CHANGELOG0100664000567100000120000000477410437660707013764 0ustar jcameronwheel---- Changes since 1.130 ---- The first version of this module, which extracts the mail reading functionality from the Sendmail, Postfix and Qmail modules and puts it into a more powerful server-independent user email module instead. ---- Changes since 1.150 ---- Added a basic HTML editor for sending and replying to email in HTML format. Requires Java 1.4+ in the browser. Must be enabled on the Module Config page, as it is still rather unstable. Included support for SMTP authentication when sending email, configurable on the Module Config page. ---- Changes since 1.160 ---- Added buttons for reporting a message as spam and adding the sender to the global SpamAssassin blacklist. ---- Changes since 1.170 ---- Added button for deleting all mail in a folder (disabled by default in the Module Config). ---- Changes since 1.180 ---- Added support for two new mail systems - VPopMail and Qmail+LDAP. Both of these access mail for users in external databases, rather than Unix users. ---- Changes since 1.200 ---- Added a Module Config option (on by default) to get the From: address for users from Virtualmin, if installed. ---- Changes since 1.210 ---- Added Module Config options to show the number of messages in each users' inbox and sent-mail folder, and to attached a signature to sent mail. ---- Changes since 1.220 ---- All Webmin users can now report spam, rather than just those that have access to the SpamAssassin module. ---- Changes since 1.240 ---- Output from sa-learn or spamassassin is now show when reporting multiple messages as spam. ---- Changes since 1.250 ---- Added a Module Config option for selecting users to not display, thanks to Brad Kester. The displayed size of mailboxes in Maildir format includes all files in the directory, rather than just those in the cur, tmp and new subdirectories in older Webmin releases. ---- Changes since 1.260 ---- When the module is configured to display only users with mail and no users have mail, then nothing will be displayed. ---- Changes since 1.270 ---- Added a Module Config option for setting the date format. Added a Module Config option to enable pager arrows at the bottom of mail list and individual message pages. Placed a Delete All button at the bottom of each user's mail list, for deleting all mail in a folder. Added a Module Config option for setting the timezone for dates. The simple search box accepts inputs like from: jcameron or size: 10000 to search on a single specific field. Added a Module Config option for opening user email messages in separate windows. mailboxes/log_parser.pl0100664000567100000120000000202610233633313015213 0ustar jcameronwheel# log_parser.pl # Functions for parsing this module's logs do 'mailboxes-lib.pl'; # parse_webmin_log(user, script, action, type, object, ¶ms) # Converts logged information from this module into human-readable form sub parse_webmin_log { local ($user, $script, $action, $type, $object, $p, $long) = @_; if ($action eq 'delmail') { return &text("log_delmail", $p->{'count'}, "$p->{'from'}"); } elsif ($action eq 'movemail') { return &text("log_movemail", $p->{'count'}, "$p->{'from'}", "$p->{'to'}"); } elsif ($action eq 'copymail') { return &text("log_copymail", $p->{'count'}, "$p->{'from'}", "$p->{'to'}"); } elsif ($action eq 'send') { return &text('log_send', &html_escape(&extract_email($p->{'to'}))); } elsif ($action eq 'read') { return &text('log_read', &html_escape($object)); } else { return undef; } } sub extract_email { if ($_[0] =~ /([^<>"' \(\)]+\@[^<>"' \(\)]+)/) { return $1; } elsif ($_[0] =~ /<(\S+)>/) { return $1; } else { return $_[0]; } } mailboxes/useradmin_update.pl0100644000567100000120000000433210303575177016422 0ustar jcameronwheel do 'mailboxes-lib.pl'; # useradmin_create_user(&details) # Create a new empty mail file sub useradmin_create_user { if ($config{'sync_create'}) { local ($dir, $style, $mailbox, $maildir) = &get_mail_style(); if ($dir && -d $dir) { # Create mail file like /var/mail/USERNAME local $mf = &mail_file_style($_[0]->{'user'}, $dir, $style); if (!-e $mf) { &create_mail_file($_[0], $mf); } } if ($mailbox && !-e "$_[0]->{'home'}/$mailbox") { # Create mail file ~USERNAME/Mailbox &create_mail_file($_[0], "$_[0]->{'home'}/$mailbox"); } if ($maildir && !-e "$_[0]->{'home'}/$maildir") { # Create mail directory like ~USERNAME/Maildir &create_mail_dir($_[0], "$_[0]->{'home'}/$maildir"); } } } # create_mail_file(&user, file) sub create_mail_file { open(TOUCH, ">$_[1]"); close(TOUCH); if ($config{'sync_perms'}) { system("chmod ". quotemeta($config{'sync_perms'})." ". quotemeta($_[1])); } chown($_[0]->{'uid'}, $_[0]->{'gid'}, $_[1]); } # create_mail_dir(&user, dir) sub create_mail_dir { local $d; foreach $d ($_[1], "$_[0]/cur", "$_[1]/tmp", "$_[1]/new") { mkdir($d, 0700); if ($config{'sync_perms'}) { system("chmod ". quotemeta($config{'sync_perms'})." ". quotemeta($d)); } chown($_[0]->{'uid'}, $_[0]->{'gid'}, $d); } } # useradmin_delete_user(&details) # Delete the user's mail file sub useradmin_delete_user { if ($config{'sync_delete'}) { local ($dir, $style, $mailbox, $maildir) = &get_mail_style(); if ($dir && -d $dir) { local $mf = &mail_file_style($_[0]->{'user'}, $dir, $style); unlink($mf); unlink($mf.".pop"); } } } # useradmin_modify_user(&details, &old) # Rename the user's mail file if necessary, and change it's UID sub useradmin_modify_user { if ($config{'sync_modify'} && ($_[0]->{'user'} ne $_[1]->{'user'} || $_[0]->{'uid'} != $_[1]->{'uid'})) { local ($dir, $style, $mailbox, $maildir) = &get_mail_style(); if ($dir && -d $dir) { local $omf = &mail_file_style($_[0]->{'olduser'}, $dir, $style); local $nmf = &mail_file_style($_[0]->{'user'}, $dir, $style); local @st = stat($omf); if ($st[4] != $_[0]->{'uid'}) { chown($_[0]->{'uid'}, $st[5], $omf); } if ($omf ne $nmf && -e $omf) { &rename_logged($omf, $nmf); } } } } 1; mailboxes/config.info.de0100644000567100000120000001112110214144454015226 0ustar jcameronwheelline0=Konfigurierbare Optionen,11 wrap_width=Zeilenumbruch bei Zeichen (70 empfohlen),0,6 perpage=Anzahl von anzuzeigenden E-Mails pro Seite,0,6 track_read=E-Mails als gelesen/ungelesen markieren?,1,1-Ja,0-Nein show_to=Zeige To:-E-Mail-Adressen in E-Mailboxen?,1,1-Ja,0-Nein max_records=Maximale Anzahl anzuzeigender Benutzer,0,6 top_buttons=Zeige Buttons oben an für,1,2-E-Mailboxen und E-Mails,1-Nur für E-Mailboxen,0-Niemals show_delall=Zeige Button an, um die gesammte E-Mailbox löschen zu können?,1,1-Ja (empfohlen),0-Nein show_size=Benutzeranzeige-Modus,1,0-Nur Benutzername,1-Benutzername und Größe,2-Alle Einzelheiten sort_mode=Sortiere E-Mailboxen nach,1,2-Größe,1-Benutzername,0-Reihenfolge in Passwortdatei show_mail=Zeige nur die Benutzer an, die E-Mails haben?,1,1-Ja (empfohlen),0-Nein size_mode=Alle Ordner in Größenanzeigen einrechnen?,1,1-Ja,0-Nein (nur der oberste Ordner) fwd_mode=Zitierte Weiterleitung von E-Mails?,1,0-Ja (empfohlen),1-Nein delete_warn=Bestätigungsabfrage vor dem Löschen von E-Mails?,10,y-Ja (empfohlen),n-Nein,Für mbox-Dateien größer als index_dbm=Indexierungsart,1,2-DBM,0-Textdatei index_min=Minimale E-Maildateigröße zum Indexieren,3,Immer indexieren view_html=Zeige E-Mails an als,4,0-Immer text/plain (empfohlen),1-Text wenn möglich (ansonsten HTML),2-HTML wenn möglich (ansonsten text/plain),3-Konvertiere HTML nach text/plain (geht nicht immer) html_edit=Benutze den HTML-Editor für das Schreiben von E-Mails?,1,2-Immer (nicht empfohlen),1-Wenn auf HTML-E-Mails geantwortet wird (nicht empfohlen),0-Niemals (sehr empfohlen) html_quote=HTML-Zitierverhalten,1,1-Nachricht unterhalb <hr>,0-Nachricht innerhalb <blockquote> check_mod=Auf E-Mailboxänderungen prüfen, wenn E-Mails gelöscht werden?,1,1-Ja,0-Nein line3=Spam-Optionen,11 spam_buttons=Zeige Spam-Report-Buttons an für,2,list-E-Mailboxen,mail-E-Mails spam_del=Lösche Spam nach dem Report?,1,1-Ja,0-Nein spam_report=Spam-Report-Methode,1,sa_learn-sa-learn --spam,spamassassin-spamassassin -r,-Entscheide Automatisch line1=Systemkonfiguration,11 mail_system=Installierter E-Mail-Server,1,1-Sendmail,0-Postfix,2-Qmail send_mode=Versende E-Mails unter Benutzung von,10,-Mailserver-Binary,SMTP-Server no_crlf=Einen Wagenrücklauf ( \r ) jeder Zeile hinzufügen,1,0-Ja,1-Nein smtp_user=SMTP-Login für E-Mailserver,3,kein smtp_pass=SMTP-Passwort für E-Mailserver,3,Kein smtp_auth=SMTP-Authentisierungsmethode,4,-Standard,Cram-MD5-Cram-MD5,Digest-MD5-Digest-MD5,Plain-Plain,Login-Login auto=Erkenne den Speicherort der E-Maildateien automatisch?,1,1-Ja, basierend auf dem Mailserver,0-Nein,benutze folgende Einstellungen .. mail_dir=Benutzer-E-Mail-Dateiverzeichnis,3,Kein mail_style=E-Mail-Dateiverzeichnisart,4,0-mail/benutzername,1-mail/u/benutzername,2-mail/u/us/benutzername,3-mail/u/s/benutzername mail_file=E-Mail-Datei in Benutzer-Heimatverzeichnis,3,Kein mail_sub=E-Mail-Verzeichnis in Benutzer-Heimatverzeichnis,3,Kein mail_usermin=Unterverzeichnis in Heimat-Verzeichnis für Usermin-ähnliche Ordner,3,Kein mailbox_user=Usermin "Lese Benutzer-E-Mail-Konfiguration" im Heimatverzeichnis,3,Keines from_addr=From:-E-Mail-Adresse, die für das Versenden manuell verschickter E--Mails benutzt werden soll,3,Aus dem E-Mailbox-Benutzernamen generieren webmin_from=Wenn Webmin E-Mails versendet benutze diese "From"-E-Mail-Adresse,3,Standard (webmin@yourhost) from_dom=Domaine, die für die From:-E-Mail-Adresse genutzt werden soll,3,System-Hostname line2=Benutzersynchronisation,11 sync_create=E-Mailbox beim Anlegen eines Benutzers ebenfalls einrichten?,1,1-Ja,0-Nein sync_modify=E-Mailbox beim Umbenennen eines Benutzers ebenfalls umbenennen?,1,1-Ja,0-Nein sync_delete=E-Mailbox beim Löschen eines Benutzers ebenfalls löschen?,1,1-Ja,0-Nein sync_perms=Dateirechte für neue E-Mailboxen,0,4 line4=VPOPMail-Optionen,11 vpopmail_dir=Base-Verzeichnis für VPOPMail,0 line5=Qmail+LDAP-Optionen,11 ldap_host=LDAP-Server,0 ldap_port=LDAP-Port,3,Standard ldap_login=Login für LDAP-Server,0 ldap_pass=Passwort für LDAP-Server,0 ldap_base=LDAP-Base für E-Mail-Benutzer,0 mailboxes/makelang.pl0100775000567100000120000000254510032203170014635 0ustar jcameronwheel#!/usr/local/bin/perl @ARGV == 1 || die "usage: makelang.pl "; $usermin = "/usr/local/useradmin/mailbox/ulang"; $mailboxes = "/usr/local/webadmin/mailboxes/lang"; $sendmail = "/usr/local/webadmin/sendmail/lang"; &read_file("$mailboxes/en", \%emailboxes, \@eorder); &read_file("$sendmail/en", \%esendmail); &read_file("$usermin/en", \%eusermin); &read_file("$mailboxes/$ARGV[0]", \%fmailboxes); &read_file("$sendmail/$ARGV[0]", \%fsendmail); &read_file("$usermin/$ARGV[0]", \%fusermin); foreach $k (@eorder) { if ($emailboxes{$k} eq $esendmail{$k} && $fsendmail{$k} && $fsendmail{$k} ne $esendmail{$k}) { print "$k=$fsendmail{$k}\n"; } elsif ($emailboxes{$k} eq $eusermin{$k} && $fusermin{$k} && $fusermin{$k} ne $eusermin{$k}) { print "$k=$fusermin{$k}\n"; } } # read_file(file, &assoc, [&order], [lowercase]) # Fill an associative array with name=value pairs from a file sub read_file { local $_; open(ARFILE, $_[0]) || return 0; while() { chomp; local $hash = index($_, "#"); local $eq = index($_, "="); if ($hash != 0 && $eq >= 0) { local $n = substr($_, 0, $eq); local $v = substr($_, $eq+1); $_[1]->{$_[3] ? lc($n) : $n} = $v; push(@{$_[2]}, $n) if ($_[2]); } } close(ARFILE); if (defined($main::read_file_cache{$_[0]})) { %{$main::read_file_cache{$_[0]}} = %{$_[1]}; } return 1; } mailboxes/Makefile0100644000567100000120000000017510067723005014165 0ustar jcameronwheelHTMLEditor.class: HTMLEditor.java CLASSPATH=/usr/local/netscape7/plugins/java2/lib/javaplugin.jar:. javac HTMLEditor.java mailboxes/config_info.pl0100644000567100000120000000056110350202445015334 0ustar jcameronwheeldo '../web-lib-funcs.pl'; sub show_userIgnoreList { my($ig_usr) = shift(@_) || ''; my($preta) = ''; return $preta . $ig_usr . $postta . ' ' . &user_chooser_button("ignore_users", 1); } sub parse_userIgnoreList { return $in{'ignore_users'}; } mailboxes/delete_all.cgi0100775000567100000120000000236310417540027015311 0ustar jcameronwheel#!/usr/local/bin/perl # Delete all mail in some mailbox, after asking for confirmation require './mailboxes-lib.pl'; &ReadParse(); &can_user($in{'user'}) || &error($text{'mail_ecannot'}); &is_user($in{'user'}) || -e $in{'user'} || &error($text{'mail_efile'}); @folders = &list_user_folders_sorted($in{'user'}); ($folder) = grep { $_->{'index'} == $in{'folder'} } @folders; if ($in{'confirm'}) { # Do it! $sz = &mailbox_folder_size($folder); &mailbox_empty_folder($folder); &webmin_log("delmail", undef, undef, { 'from' => $folder->{'file'}, 'count' => $sz }); &redirect("list_mail.cgi?user=$in{'user'}&folder=$in{'folder'}"); } else { # Ask first &ui_print_header(undef, $text{'delall_title'}, ""); print &ui_form_start("delete_all.cgi"); print &ui_hidden("user", $in{'user'}),"\n"; print &ui_hidden("folder", $in{'folder'}),"\n"; print "

\n"; print &text('delall_rusure', "$folder->{'file'}", &mailbox_folder_size($folder), &nice_size(&folder_size($folder))),"

\n"; print &ui_submit($text{'delall_ok'}, "confirm"),"\n"; print &ui_form_end(); print "

\n"; &ui_print_footer("list_mail.cgi?user=$in{'user'}&folder=$in{'folder'}", $text{'mail_return'}, "", $text{'index_return'}); } mailboxes/config.info.ca0100644000567100000120000001151510424446674015244 0ustar jcameronwheelline0=Opcions configurables,11 wrap_width=Amplada dels missatges de correu,0,6 perpage=Nombre de missatges a mostrar per pgina,0,6 track_read=Porta el compte dels correus llegits/no llegits,1,1-S,0-No show_to=Mostra les adreces To: a les bsties,1,1-S,0-No max_records=Nombre mxim d'usuaris a mostrar,0,6 top_buttons=Mostra els botons a dalt per a,1,2-Bsties i correus,1-Noms les bsties,0-Mai show_delall=Mostra el bot per suprimir tota la bstia,1,1-S,0-No show_size=Mode de mostrar els usuaris,1,0-Noms el nom d'usuari,1-Nom d'usuari i mida,2-Tots els detalls show_size_below=       Usuari i mida - On es mostra la mida,1,0-A la dreta de l'usuari,1-A sota de l'usuari column_count=Nombre de columnes per mostrar-hi els noms d'usuari,1,3-3,4-4,5-5,6-6,7-7,8-8,9-9 ignore_users=Ignora aquests noms d'usuari (no els mostris),15,userIgnoreList ignore_users_enabled=        Ignora l'estat de la llista,1,1-Activat,0-Desactivat show_count=Mostra el nombre de missatges d'entrada,1,1-S,0-No show_sent=Mostra el nombre de missatges de la carpeta de coreru enviat,1,1-S,0-No sort_mode=Ordena les bsties per,1,2-Mida,1-Nom d'usuari,0-Ordre del fitxer de contrasenyes show_mail=Mostra noms els usuaris que tenen correu,1,1-S,0-No size_mode=Inclou totes les carpetes a la mida,1,1-S,0-No (Noms la primera carpeta) fwd_mode=Reenvia els missatges citats,1,0-S,1-No delete_warn=Demana confirmaci abans d'esborrar,10,y-S,n-No,Per a bsties ms grans de index_dbm=Tipus d'indexaci,1,2-DBM,0-Fitxer de text index_min=Mida mnima de fitxer de correu a indexar,3,Indexa sempre view_html=Mostra el cos del missatge,4,0-Sempre en text planer,1-En text si s possible, altrament en HTML,2-HTML si s possible, altrament en text,3-Converteix HTML a text planer html_edit=Utilitza l'editor HTML per a redactar,1,2-Sempre,1-En respondre correus HTML,0-Mai html_quote=Mode de citat HTML,1,1-Missatge sota <hr>,0-Missatge dins de <blockquote> check_mod=Comprova la modificaci de la bstia en esborrar correu,1,1-S,0-No log_read=Registra la lectura del correu al Fitxer d'Accions de Webmin,1,1-S,0-No bcc_to=Fs cpia cega dels missatges enviats a,0 sig_file=Fitxer de signatura,10,*-Cap,.signature-~/.signature,Un altre fitxer show_body=Mostra previsualitzacions del cos del missatge a la llista,1,1-S,0-No link_mode=Obre els enllaos a,1,1-Finestra nova,0-La mateixa finestra download=Tipus MIME d'adjuncions que sempres s'han de descarrregar,9,20,4,\t line3=Opcions de spam,11 spam_buttons=Mostra els botons d'informe de spam de,2,list-Les bsties,mail-Els missatges spam_del=Suprimeix el spam en fer l'informe,1,1-S,0-No spam_report=Informa del spam utilitzant,1,sa_learn-sa-learn --spam,spamassassin-spamassasin -r,-Decideix-ho automticament line3.5=De les opcions de l'adrea,11 from_addr=Adrea From: a utilitzar quan s'envia correu manualmen,3,Del nom d'usuari de la bstia webmin_from=Adrea From: a utilitzar quan el Webmin envia correu,3,per defecte (webmin@elteuhost) from_virtualmin=Obtingues l'adrea From: de Virtualmin,1,1-S,0-No from_dom=Domini a utilitzar a les adreces From:,3,Nom de host del sistema line1=Configuraci del sistema,11 mail_system=Servidor de correu installat,1,1-Sendmail,0-Postfix,2-Qmail,3-Detecta'l automticament,4-Qmail+LDAP,5-Qmail+VPopMail send_mode=Envia el correu emprant,10,-El programa servidor de correu,El servidor SMTP no_crlf=Afegeix un retorn de carro ( \r ) a cada lnia,1,0-S,1-No smtp_user=Nom d'usuari SMTP al servidor de correu,3,Cap smtp_pass=Contrasenya SMTP al servidor de correu,3,Cap smtp_auth=Mtode d'autenticacio SMTP,4,-Defecte,Cram-MD5-Cram-MD5,Digest-MD5-Digest-MD5,Planer-Planer,Login-Login auto=Detecta la ubicaci dels fitxers de correu automticament,1,1-S, basant-se en el servidor de correu,0-No, utilitza la configuraci de sota... mail_dir=Directori del fitxer de correu de l'usuari,3,Cap mail_style=Estil del directori del fitxer de correu,4,0-mail/usuari,1-mail/u/usuari,2-mail/u/us/usuari,3-mail/u/s/usuari mail_file=Fitxer de correu en els directoris arrel dels usuaris,3,Cap mail_sub=Directori de correu en els directoris arrel dels usuaris,3,Cap mail_usermin=SUbdirectori de carpetes estil Usermin al directori arrel,3,Cap mailbox_user=Directori de configuraci de Correu Llegit Usermin al directori arrel,3,Cap line2=Sincronitzaci d'usuaris,11 sync_create=Crea la bstia quan es cre l'usuari,1,1-S,0-No sync_modify=Renomena la bstia quan es renomeni l'usuari,1,1-S,0-No sync_delete=Suprimeix la bstia quan se suprimeixi l'usuari,1,1-S,0-No sync_perms=Permisos de les bsties noves,0,4 line4=Opcions VPOPMail,11 vpopmail_dir=Directori base de VPOPMail,0 line5=Opcions Qmail+LDAP,11 ldap_host=Servidor LDAP,0 ldap_port=Port LDAP,3,Defecte ldap_login=Usuari del servidor LDAP,0 ldap_pass=Contrasenya del servidor LDAP,0 ldap_base=Base d'usuaris de correu,0 mailboxes/htmlarea/0040755000567100000120000000000010374217006014322 5ustar jcameronwheelmailboxes/htmlarea/dialog.js0100644000567100000120000000433410020710422016104 0ustar jcameronwheel// htmlArea v3.0 - Copyright (c) 2003-2004 interactivetools.com, inc. // This copyright notice MUST stay intact for use (see license.txt). // // Portions (c) dynarch.com, 2003-2004 // // A free WYSIWYG editor replacement for mailboxes/htmlarea/popups/insert_image.html0100644000567100000120000001235010020710424021170 0ustar jcameronwheel Insert Image
Insert Image
Image URL:
Alternate text:

Layout
Alignment:

Border thickness:
Spacing
Horizontal:

Vertical:

Image Preview:

mailboxes/htmlarea/popups/insert_table.html0100644000567100000120000001104110020710424021171 0ustar jcameronwheel Insert Table
Insert Table
Rows:
Cols: Width:

Layout
Alignment:

Border thickness:
Spacing
Cell spacing:

Cell padding:
mailboxes/htmlarea/popups/link.html0100644000567100000120000000730110020710424017457 0ustar jcameronwheel Insert/Modify Link
Insert/Modify Link
URL:
Title (tooltip):
Target:
mailboxes/htmlarea/popups/old-fullscreen.html0100644000567100000120000001064710020710424021447 0ustar jcameronwheel Fullscreen Editor

mailboxes/htmlarea/popups/old_insert_image.html0100644000567100000120000002010210020710424022020 0ustar jcameronwheel Insert Image
Image URL:
Alternate Text:
Layout
Spacing
Alignment:
Horizontal:
Border Thickness:
Vertical:
mailboxes/htmlarea/popups/select_color.html0100644000567100000120000007014210020710424021202 0ustar jcameronwheel Select Color
mailboxes/htmlarea/images/0040755000567100000120000000000010020710424015555 5ustar jcameronwheelmailboxes/htmlarea/images/ed_about.gif0100644000567100000120000000012710020710424020023 0ustar jcameronwheelGIF89a!,.LTtNb[{hX-ffx |zeѾ RD@@$'3f;|hYPgݒ" Od%8<;mailboxes/htmlarea/images/ed_color_bg.gif0100644000567100000120000000026510020710424020502 0ustar jcameronwheelGIF89a {{{{! ,bpIJݭMZXːպ(P8-I @`z$`P@,wmzP4a+O= 0)*?|@+9BP')RT6#;mailboxes/htmlarea/images/ed_color_fg.gif0100644000567100000120000000025310020710424020503 0ustar jcameronwheelGIF89a {{{{! ,XPI+M8k+x9p`Cb]Wy 0$2PA rÀ ZGR [5ﭼ^;mailboxes/htmlarea/images/ed_copy.gif0100644000567100000120000000015610020710424017665 0ustar jcameronwheelGIF89a!,? '4l` b>"f>*\ЛyZPal!I(;mailboxes/htmlarea/images/ed_custom.gif0100644000567100000120000000010310020710424020215 0ustar jcameronwheelGIF89a!,@J%qqxIj;mailboxes/htmlarea/images/ed_cut.gif0100644000567100000120000000013310020710424017501 0ustar jcameronwheelGIF89a!,,Dqex\m`!@F UˮM*,;R ;mailboxes/htmlarea/images/ed_delete.gif0100644000567100000120000000013210020710424020147 0ustar jcameronwheelGIF89a!,+`qXS؊t`#>IIW cT  ;mailboxes/htmlarea/images/ed_format_bold.gif0100644000567100000120000000011210020710424021173 0ustar jcameronwheelGIF89a!,!20]ƗQ]JZ"L3;mailboxes/htmlarea/images/ed_format_italic.gif0100644000567100000120000000011510020710424021523 0ustar jcameronwheelGIF89a{{{!,3,vE(XAe G;mailboxes/htmlarea/images/ed_format_strike.gif0100644000567100000120000000011610020710424021560 0ustar jcameronwheelGIF89a!,% "sm5IPY#f=[J"vTL;mailboxes/htmlarea/images/ed_format_sub.gif0100644000567100000120000000011610020710424021050 0ustar jcameronwheelGIF89a!,B0 YU!dyj: M;mailboxes/htmlarea/images/ed_format_sup.gif0100644000567100000120000000011510020710424021065 0ustar jcameronwheelGIF89a!,m,a^xƶ ;mailboxes/htmlarea/images/ed_format_underline.gif0100644000567100000120000000012510020710424022244 0ustar jcameronwheelGIF89a{{{!,& b&Ov^uL'.7PD#]:];mailboxes/htmlarea/images/ed_help.gif0100644000567100000120000000010610020710424017636 0ustar jcameronwheelGIF89a!, Ns_QAu1jɶR;mailboxes/htmlarea/images/ed_hr.gif0100644000567100000120000000010610020710424017317 0ustar jcameronwheelGIF89a333!,>VH;mailboxes/htmlarea/images/ed_html.gif0100644000567100000120000000011310020710424017650 0ustar jcameronwheelGIF89a!,"0sWSm}Iy%xR):LG;mailboxes/htmlarea/images/ed_image.gif0100644000567100000120000000022410020710424017771 0ustar jcameronwheelGIF89a!,YxPA ` ah *[V/!VA(ֿ6B7YH"<)LVz!AL|z-ޝ/j>;mailboxes/htmlarea/images/ed_indent_less.gif0100644000567100000120000000012710020710424021220 0ustar jcameronwheelGIF89a!,(믂lJ@dfVFbxP;mailboxes/htmlarea/images/ed_indent_more.gif0100644000567100000120000000012710020710424021214 0ustar jcameronwheelGIF89a!,(믂lJ@"dfvGfxغP;mailboxes/htmlarea/images/ed_left_to_right.gif0100644000567100000120000000013110020710424021535 0ustar jcameronwheelGIF89a!,*S D^UGmJ7jWyZ)tύ);mailboxes/htmlarea/images/ed_link.gif0100644000567100000120000000014110020710424017642 0ustar jcameronwheelGIF89a!,2Vc+84Sy6_ gPL:d~+e~L2 ;mailboxes/htmlarea/images/ed_list_bullet.gif0100644000567100000120000000012010020710424021224 0ustar jcameronwheelGIF89a!,!&{ь}!FjЇdvLs;mailboxes/htmlarea/images/ed_list_num.gif0100644000567100000120000000012210020710424020536 0ustar jcameronwheelGIF89a!,#3Z&tr{}u]hHVX;mailboxes/htmlarea/images/ed_paste.gif0100644000567100000120000000021310020710424020021 0ustar jcameronwheelGIF89a!,PhЕYs \YPlcbR^ Gb.@Oǟ'0" FA*TQA Jn+;mailboxes/htmlarea/images/ed_redo.gif0100644000567100000120000000012010020710424017633 0ustar jcameronwheelGIF89a!,!@J4OM-acr'@ L;mailboxes/htmlarea/images/ed_right_to_left.gif0100644000567100000120000000013010020710424021534 0ustar jcameronwheelGIF89a!,) p pF5~͙ ,d~R;mailboxes/htmlarea/images/ed_save.gif0100644000567100000120000000021710020710424017647 0ustar jcameronwheelGIF89a܀!,TXPI+mD 0qT,j*J[Ƹfe6`H,noMQ(JyI*hXh<;mailboxes/htmlarea/images/ed_show_border.gif0100644000567100000120000000015010020710424021222 0ustar jcameronwheelGIF89a3!,9c`ؼw,h޸蔥g:,x+]UXe;mailboxes/htmlarea/images/ed_splitcel.gif0100644000567100000120000000021710020710424020530 0ustar jcameronwheelGIF89a!,TH0I#Hzhdupj _cȤP\lPL٬\j Ն_9x%;mailboxes/htmlarea/images/ed_undo.gif0100644000567100000120000000012110020710424017650 0ustar jcameronwheelGIF89a!,"c 4EVy& UI*LL;mailboxes/htmlarea/images/fullscreen_maximize.gif0100644000567100000120000000014110020710424022302 0ustar jcameronwheelGIF89a!,8Xg ]pgTƉճyryj_pԄ]XPVq,;mailboxes/htmlarea/images/fullscreen_minimize.gif0100644000567100000120000000014110020710424022300 0ustar jcameronwheelGIF89a!,8sӤyzmXFtuȺ Ik 8+p'4Y](;mailboxes/htmlarea/images/insert_table.gif0100644000567100000120000000017110020710424020713 0ustar jcameronwheelGIF89a3!,>HI *{ǒ'r` BY `8|@Z&GXHWfՊe:Xl;