361 lines
8.9 KiB
Text
361 lines
8.9 KiB
Text
|
|
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||
|
|
<%@ page import="java.util.Map"%>
|
||
|
|
<%@ page import="java.util.HashMap"%>
|
||
|
|
<%@ page import="java.util.List"%>
|
||
|
|
<%@ page import="java.util.ArrayList"%>
|
||
|
|
<%@ page import="java.util.Set"%>
|
||
|
|
<%@ page import="java.util.HashSet"%>
|
||
|
|
<%@ page import="java.util.Collections"%>
|
||
|
|
<%@ page import="java.util.Comparator"%>
|
||
|
|
<%@ page import="com.stephenschafer.email.Logger"%>
|
||
|
|
<%@ page import="com.stephenschafer.email.Mapping"%>
|
||
|
|
<%@ page import="com.stephenschafer.email.Util"%>
|
||
|
|
<%@ page import="com.stephenschafer.email.User"%>
|
||
|
|
<%
|
||
|
|
final User user = Util.identify(session);
|
||
|
|
if (user == null) {
|
||
|
|
session.setAttribute("return-servlet-path", request.getServletPath());
|
||
|
|
session.setAttribute("return-query-string", request.getQueryString());
|
||
|
|
response.sendRedirect("login.jsp");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
String domainString = request.getParameter("domain");
|
||
|
|
if(domainString == null) {
|
||
|
|
domainString = (String)session.getAttribute("domain-filter");
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
session.setAttribute("domain-filter", domainString);
|
||
|
|
}
|
||
|
|
String targetString = request.getParameter("target");
|
||
|
|
if(targetString == null) {
|
||
|
|
targetString = (String)session.getAttribute("target-filter");
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
session.setAttribute("target-filter", targetString);
|
||
|
|
}
|
||
|
|
String hideDisabledString = request.getParameter("hide-disabled");
|
||
|
|
/*
|
||
|
|
if(hideDisabledString == null) {
|
||
|
|
hideDisabledString = (String) session.getAttribute("hide-disabled-filter");
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
session.setAttribute("hide-disabled-filter", hideDisabledString);
|
||
|
|
}
|
||
|
|
*/
|
||
|
|
final boolean hideDisabled = "hide".equals(hideDisabledString);
|
||
|
|
Util.updateSession(session);
|
||
|
|
@SuppressWarnings("unchecked")
|
||
|
|
final List<String> targetList = (List<String>) session.getAttribute("target-list");
|
||
|
|
@SuppressWarnings("unchecked")
|
||
|
|
final List<String> domainList = (List<String>) session.getAttribute("domain-list");
|
||
|
|
final List<Mapping> mappings = Util.getMappings();
|
||
|
|
Logger.log(String.format("got %d mappings", Integer.valueOf(mappings.size())));
|
||
|
|
final List<String> domainOptions = new ArrayList<>();
|
||
|
|
boolean domainFound = false;
|
||
|
|
for(final String domain : domainList) {
|
||
|
|
final String selected;
|
||
|
|
if(domain.equals(domainString)) {
|
||
|
|
domainFound = true;
|
||
|
|
selected = " selected";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
selected = "";
|
||
|
|
}
|
||
|
|
domainOptions.add(String.format("<option value=\"%s\"%s>%s</option>", domain, selected, domain));
|
||
|
|
}
|
||
|
|
if(!domainFound) {
|
||
|
|
domainString = null;
|
||
|
|
session.removeAttribute("domain-filter");
|
||
|
|
}
|
||
|
|
final List<String> targetOptions = new ArrayList<>();
|
||
|
|
boolean targetFound = false;
|
||
|
|
for(final String target : targetList) {
|
||
|
|
final String selected;
|
||
|
|
if(target.equals(targetString)) {
|
||
|
|
targetFound = true;
|
||
|
|
selected = " selected";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
selected = "";
|
||
|
|
}
|
||
|
|
targetOptions.add(String.format("<option value=\"%s\"%s>%s</option>", target, selected, target));
|
||
|
|
}
|
||
|
|
if(!targetFound) {
|
||
|
|
targetString = null;
|
||
|
|
session.removeAttribute("target-filter");
|
||
|
|
}
|
||
|
|
final Map<String, Set<String>> names = new HashMap<>();
|
||
|
|
%>
|
||
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
|
<html>
|
||
|
|
<head>
|
||
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
|
<meta name=""viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>Virtual Addresses</title>
|
||
|
|
<style>
|
||
|
|
body {
|
||
|
|
font-family: sans-serif;
|
||
|
|
font-size: 10pt;
|
||
|
|
color: #333;
|
||
|
|
}
|
||
|
|
button {
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
input {
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
select {
|
||
|
|
font-family: inherit;
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
table {
|
||
|
|
font-family: inherit;
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
table.mappings {
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping {
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping td {
|
||
|
|
padding-left: 10px;
|
||
|
|
padding-right: 10px;
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping td:first-of-type {
|
||
|
|
padding-left: 0px;
|
||
|
|
padding-right: 10px;
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping td:last-of-type {
|
||
|
|
padding-left: 10px;
|
||
|
|
padding-right: 0px;
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping.disabled {
|
||
|
|
color: #999;
|
||
|
|
}
|
||
|
|
table.mappings tr.divider td {
|
||
|
|
height: 1px;
|
||
|
|
border-bottom: 1px solid #000;
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping td.address {
|
||
|
|
white-space: nowrap;
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping td.date {
|
||
|
|
white-space: nowrap;
|
||
|
|
}
|
||
|
|
a {
|
||
|
|
text-decoration: none;
|
||
|
|
color: #333;
|
||
|
|
}
|
||
|
|
table.mappings tr.mapping.disabled a {
|
||
|
|
color: #999;
|
||
|
|
}
|
||
|
|
div.new {
|
||
|
|
margin-bottom: 10px;
|
||
|
|
}
|
||
|
|
div.new button {
|
||
|
|
color: red;
|
||
|
|
}
|
||
|
|
@media only screen and (min-resolution:2x) {
|
||
|
|
body {
|
||
|
|
font-size: 300%;
|
||
|
|
}
|
||
|
|
h1 {
|
||
|
|
display: none;
|
||
|
|
}
|
||
|
|
div.new>button {
|
||
|
|
display: block;
|
||
|
|
margin-bottom: .5em;
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
div.new>input {
|
||
|
|
display: block;
|
||
|
|
margin-bottom: .5em;
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
div.new>select {
|
||
|
|
display: block;
|
||
|
|
margin-bottom: .5em;
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
div.new>label {
|
||
|
|
display: block;
|
||
|
|
margin-bottom: .5em;
|
||
|
|
font-size: inherit;
|
||
|
|
}
|
||
|
|
table.mappings>tbody>tr.mapping>td {
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
<script>
|
||
|
|
|
||
|
|
<%
|
||
|
|
if(domainString != null) {
|
||
|
|
out.println(String.format("var domain = \"%s\";\n", domainString));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
out.println("var domain = null;\n");
|
||
|
|
}
|
||
|
|
if(targetString != null) {
|
||
|
|
out.println(String.format("var target = \"%s\";\n", targetString));
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
out.println("var target = null;\n");
|
||
|
|
}
|
||
|
|
out.println("var hideDisabled = " + hideDisabled + ";\n");
|
||
|
|
%>
|
||
|
|
function doQuery() {
|
||
|
|
var args = [];
|
||
|
|
if(domain != null) {
|
||
|
|
args.push({name: "domain", value: domain});
|
||
|
|
}
|
||
|
|
if(target != null) {
|
||
|
|
args.push({name: "target", value: target});
|
||
|
|
}
|
||
|
|
if(hideDisabled) {
|
||
|
|
args.push({name: "hide-disabled", value: "hide"});
|
||
|
|
}
|
||
|
|
for(var i = 0; i < args.length; i++) {
|
||
|
|
var arg = args[i];
|
||
|
|
args[i] = arg.name + "=" + arg.value;
|
||
|
|
}
|
||
|
|
args = args.join("&");
|
||
|
|
var href = "index.jsp";
|
||
|
|
if(args != "") {
|
||
|
|
href += "?" + args;
|
||
|
|
}
|
||
|
|
window.location.href = href;
|
||
|
|
}
|
||
|
|
|
||
|
|
function selectDomain(select) {
|
||
|
|
domain = select.value;
|
||
|
|
doQuery();
|
||
|
|
}
|
||
|
|
|
||
|
|
function selectTarget(select) {
|
||
|
|
target = select.value;
|
||
|
|
doQuery();
|
||
|
|
}
|
||
|
|
|
||
|
|
function addressFilter(input) {
|
||
|
|
textFilter(input, "address");
|
||
|
|
}
|
||
|
|
|
||
|
|
function descriptionFilter(input) {
|
||
|
|
textFilter(input, "description");
|
||
|
|
}
|
||
|
|
|
||
|
|
function textFilter(input, name) {
|
||
|
|
var regex = new RegExp(input.value == "" ? ".*" : input.value, "i");
|
||
|
|
var tds = document.body.querySelectorAll("table.mappings tr.mapping td." + name);
|
||
|
|
for(var i = 0; i < tds.length; i++) {
|
||
|
|
var td = tds[i];
|
||
|
|
var address = td.textContent;
|
||
|
|
var show = regex.test(address);
|
||
|
|
var tr = td.parentNode;
|
||
|
|
tr.style.display = show ? "" : "none";
|
||
|
|
var tr = tr.nextSibling;
|
||
|
|
while(tr != null) {
|
||
|
|
if(tr.nodeName == "TR") {
|
||
|
|
tr.style.display = show ? "" : "none";
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
tr = tr.nextSibling;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
</script>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<h1>Virtual Addresses</h1>
|
||
|
|
<div class="new">
|
||
|
|
<button type="button" onclick="window.location.href='edit.jsp'">Add a new mapping</button>
|
||
|
|
<input type="text" name="address-filter" onkeyup="addressFilter(this)" placeholder="address"/>
|
||
|
|
<select onchange="selectDomain(this)">
|
||
|
|
<option value="">All domains</option>
|
||
|
|
<%
|
||
|
|
for(final String option : domainOptions) {
|
||
|
|
%> <%=option %>
|
||
|
|
<%
|
||
|
|
}
|
||
|
|
%> </select>
|
||
|
|
<select onchange="selectTarget(this)">
|
||
|
|
<option value="">All targets</option>
|
||
|
|
<%
|
||
|
|
for(final String option : targetOptions) {
|
||
|
|
%> <%=option %>
|
||
|
|
<%
|
||
|
|
}
|
||
|
|
%> </select>
|
||
|
|
<input type="text" name="description-filter" onkeyup="descriptionFilter(this)" placeholder="description"/>
|
||
|
|
<%
|
||
|
|
final String hideDisabledChecked = hideDisabled ? " checked" : "";
|
||
|
|
%> <label>
|
||
|
|
|
||
|
|
<input type="checkbox" name="hide-disabled" value="hide"<%=hideDisabledChecked %>
|
||
|
|
onclick="hideDisabled = this.checked; doQuery()"/> Hide disabled
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
<table class="mappings">
|
||
|
|
<%
|
||
|
|
for(final Mapping mapping : mappings) {
|
||
|
|
if(!mapping.qualifies(user)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if(domainString != null && domainString.trim().length() > 0 && !domainString.equals(mapping.getDomain())) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if(targetString != null && targetString.trim().length() > 0 && !targetString.equals(mapping.getTarget())) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if(hideDisabled && mapping.isDisabled()) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
final String disabledClass = mapping.isDisabled() ? " disabled" : "";
|
||
|
|
%><tr class="mapping<%=disabledClass%>">
|
||
|
|
<td class="address"><a href="edit.jsp?address=<%=mapping.getAddress()%>"><%=mapping.getAddress()%></a></td>
|
||
|
|
<td class="target"><%=mapping.getTarget()%></td>
|
||
|
|
<td class="description"><%=mapping.getDisplayDescription()%></td>
|
||
|
|
<td class="disabled"><%=mapping.isDisabled() ? "disabled" : "" %></td>
|
||
|
|
<td class="date"><%=mapping.getFormattedDate() %></td>
|
||
|
|
</tr>
|
||
|
|
<tr class="divider">
|
||
|
|
<td colspan="5"></td>
|
||
|
|
</tr>
|
||
|
|
|
||
|
|
<%
|
||
|
|
if(!mapping.isDisabled()) {
|
||
|
|
String mappingDomain = mapping.getDomain();
|
||
|
|
if(mappingDomain == null) {
|
||
|
|
mappingDomain = "";
|
||
|
|
}
|
||
|
|
Set<String> namesForDomain = names.get(mappingDomain);
|
||
|
|
if(namesForDomain == null) {
|
||
|
|
namesForDomain = new HashSet<>();
|
||
|
|
names.put(mappingDomain, namesForDomain);
|
||
|
|
}
|
||
|
|
namesForDomain.add(mapping.getName());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
%></table>
|
||
|
|
<%
|
||
|
|
final List<String> domains = new ArrayList<>(names.keySet());
|
||
|
|
Collections.sort(domains);
|
||
|
|
for(String mappingDomain : domains) {
|
||
|
|
List<String> namesForDomain = new ArrayList<>(names.get(mappingDomain));
|
||
|
|
Collections.sort(namesForDomain);
|
||
|
|
%><div class="names">
|
||
|
|
<h2>Names for <%=mappingDomain %></h2>
|
||
|
|
<%
|
||
|
|
String sep = "";
|
||
|
|
for(final String name : namesForDomain) {
|
||
|
|
out.print(sep);
|
||
|
|
sep = ", ";
|
||
|
|
out.println(name);
|
||
|
|
}
|
||
|
|
%></div>
|
||
|
|
<%
|
||
|
|
}
|
||
|
|
%></body>
|
||
|
|
</html>
|