Compare commits
No commits in common. "f5639ddf442612e346163f0f39efe19f51d6649f" and "ba0a8f20de32b083becfb6da866ec1e32995b3de" have entirely different histories.
f5639ddf44
...
ba0a8f20de
38 changed files with 0 additions and 3503 deletions
21
.classpath
21
.classpath
|
|
@ -1,21 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry including="**/*.java" kind="src" output="target/classes" path="src">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="optional" value="true"/>
|
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
|
||||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="output" path="target/classes"/>
|
|
||||||
</classpath>
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
target/
|
|
||||||
sql/
|
|
||||||
hs_err*.log
|
|
||||||
37
.project
37
.project
|
|
@ -1,37 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>com.stephenschafer.email</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
|
||||||
<arguments>
|
|
||||||
</arguments>
|
|
||||||
</buildCommand>
|
|
||||||
</buildSpec>
|
|
||||||
<natures>
|
|
||||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
|
||||||
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
|
|
||||||
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
|
||||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
|
||||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
|
||||||
</natures>
|
|
||||||
</projectDescription>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<classpath>
|
|
||||||
<classpathentry excluding="**/bower_components/*|**/node_modules/*|**/*.min.js" kind="src" path="WebContent"/>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
|
|
||||||
<attributes>
|
|
||||||
<attribute name="hide" value="true"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
|
|
||||||
<classpathentry kind="output" path=""/>
|
|
||||||
</classpath>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
eclipse.preferences.version=1
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
|
||||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
|
||||||
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
|
||||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
|
||||||
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
|
|
||||||
org.eclipse.jdt.core.compiler.release=disabled
|
|
||||||
org.eclipse.jdt.core.compiler.source=1.8
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
activeProfiles=
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
resolveWorkspaceProjects=true
|
|
||||||
version=1
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
|
|
||||||
|
|
||||||
<wb-module deploy-name="com.stephenschafer.email-manager-0.0.1-SNAPSHOT">
|
|
||||||
|
|
||||||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
|
||||||
|
|
||||||
<wb-resource deploy-path="/" source-path="/WebContent" tag="defaultRootSource"/>
|
|
||||||
|
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
|
|
||||||
|
|
||||||
<property name="context-root" value="com.stephenschafer.email-manager"/>
|
|
||||||
|
|
||||||
<property name="java-output-path" value="/com.stephenschafer.email-manager/build/classes"/>
|
|
||||||
|
|
||||||
</wb-module>
|
|
||||||
|
|
||||||
</project-modules>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<faceted-project>
|
|
||||||
<fixed facet="jst.web"/>
|
|
||||||
<fixed facet="java"/>
|
|
||||||
<fixed facet="wst.jsdt.web"/>
|
|
||||||
<installed facet="java" version="1.8"/>
|
|
||||||
<installed facet="wst.jsdt.web" version="1.0"/>
|
|
||||||
<installed facet="jst.web" version="2.5"/>
|
|
||||||
</faceted-project>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
org.eclipse.wst.jsdt.launching.baseBrowserLibrary
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Window
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
disabled=06target
|
|
||||||
eclipse.preferences.version=1
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
Manifest-Version: 1.0
|
|
||||||
Class-Path:
|
|
||||||
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
|
||||||
xmlns:web="http://xmlns.jcp.org/xml/ns/javaee">
|
|
||||||
|
|
||||||
<session-config>
|
|
||||||
<session-timeout>1440</session-timeout>
|
|
||||||
</session-config>
|
|
||||||
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>PostMapping</servlet-name>
|
|
||||||
<servlet-class>com.stephenschafer.email.PostMapping</servlet-class>
|
|
||||||
<load-on-startup>1</load-on-startup>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>PostMapping</servlet-name>
|
|
||||||
<url-pattern>/post-mapping</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>NewAlias</servlet-name>
|
|
||||||
<servlet-class>com.stephenschafer.email.NewAlias</servlet-class>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>NewAlias</servlet-name>
|
|
||||||
<url-pattern>/new-alias</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>reset</servlet-name>
|
|
||||||
<servlet-class>com.stephenschafer.email.ResetSession</servlet-class>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>reset</servlet-name>
|
|
||||||
<url-pattern>/reset</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
|
|
||||||
<servlet>
|
|
||||||
<servlet-name>logout</servlet-name>
|
|
||||||
<servlet-class>com.stephenschafer.email.Logout</servlet-class>
|
|
||||||
</servlet>
|
|
||||||
|
|
||||||
<servlet-mapping>
|
|
||||||
<servlet-name>logout</servlet-name>
|
|
||||||
<url-pattern>/logout</url-pattern>
|
|
||||||
</servlet-mapping>
|
|
||||||
</web-app>
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
<%@ 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.Mapping"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Util"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.User"%>
|
|
||||||
<%
|
|
||||||
final String address = request.getParameter("address");
|
|
||||||
final boolean mobile = "true".equalsIgnoreCase(request.getParameter("mobile"));
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Util.updateSession(session);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final List<String> targetList = (List<String>) session.getAttribute("target-list");
|
|
||||||
final Mapping mapping = address == null ? null : Util.getMapping(address);
|
|
||||||
final String username = user.getName();
|
|
||||||
final String selectedTarget = "sandy".equals(username) ? "sandy" : "elephant".equals(username) ? "steve" : "";
|
|
||||||
final String header = mobile ? selectedTarget : "Mapping";
|
|
||||||
final String targetDisplay = mobile ? "display: none" : "";
|
|
||||||
final String disabledAttr = mapping == null ? "" : mapping.isDisabled() ? " checked" : "";
|
|
||||||
final String disableDisplay = mobile ? "display: none" : "";
|
|
||||||
final String descriptionValue = mapping == null ? "" : mapping.getDisplayDescription();
|
|
||||||
final String dateValue = mapping == null ? "" : mapping.getFormattedDate();
|
|
||||||
%>
|
|
||||||
<!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">
|
|
||||||
<title>Edit Mapping</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
table.mapping {
|
|
||||||
}
|
|
||||||
table.mapping tr.mapping {
|
|
||||||
}
|
|
||||||
table.mapping tr.mapping td:first-of-type {
|
|
||||||
padding-right: 10px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media only screen and (min-resolution:2x) {
|
|
||||||
body {
|
|
||||||
font-size: 300%;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
input[type="checkbox"] {
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
|
|
||||||
function targetChanged() {
|
|
||||||
var targetSelect = document.mapping.target;
|
|
||||||
var emailInput = document.mapping["email-address"];
|
|
||||||
var request = new XMLHttpRequest();
|
|
||||||
request.open("POST", "new-alias", true);
|
|
||||||
request.onreadystatechange = function() {
|
|
||||||
if(request.readyState != 4) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(request.status != 200) {
|
|
||||||
alert("Http error " + request.status + " on " + request.statusText);
|
|
||||||
debugger;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
var response = JSON.parse(request.responseText);
|
|
||||||
if(response.error != null) {
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
emailInput.value = response.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
debugger;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request.setRequestHeader("Content-Type", "application/json");
|
|
||||||
request.setRequestHeader("Accept", "application/json");
|
|
||||||
request.send(targetSelect.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body onload="targetChanged()">
|
|
||||||
<h1><%=header %></h1>
|
|
||||||
<form action="post-mapping" method="post" name="mapping">
|
|
||||||
<input type="hidden" name="new" value="<%=mapping == null ? "true" : "false" %>"/>
|
|
||||||
<input type="hidden" name="mobile" value="<%=mobile ? "true" : "false" %>"/>
|
|
||||||
<table class="mapping">
|
|
||||||
|
|
||||||
<tr style="<%=targetDisplay%>" >
|
|
||||||
<td>Target</td>
|
|
||||||
<td>
|
|
||||||
<select name="target" onchange="targetChanged()">
|
|
||||||
<%
|
|
||||||
for(final String target : targetList) {
|
|
||||||
final boolean selected = mapping != null ? target.equals(mapping.getTarget()) : selectedTarget.equals(target);
|
|
||||||
final String selectedAttr = selected ? " selected" : "";
|
|
||||||
%> <option value="<%=target%>"<%=selectedAttr%>><%=target%></option>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%> </select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Email Address</td>
|
|
||||||
<td>
|
|
||||||
<%
|
|
||||||
if(mapping == null) {
|
|
||||||
%> <input type="text" name="email-address" value="" size="24"/>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
%> <input type="hidden" name="email-address" value="<%=mapping.getAddress()%>" size="24"/>
|
|
||||||
<%=mapping.getAddress()%>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Description</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="description" value="<%=descriptionValue %>" size="24"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<%
|
|
||||||
if(mapping != null) {
|
|
||||||
%><tr>
|
|
||||||
<td>Date</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="date" value="<%=dateValue %>" size="10"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%><tr style="<%=disableDisplay %>">
|
|
||||||
<td>Disabled</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" name="disabled" value="true"<%=disabledAttr %>/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type="submit">Submit</button>
|
|
||||||
<%
|
|
||||||
if(!mobile) {
|
|
||||||
%> <button type="button" onclick="window.location.href='index.jsp'">List</button>
|
|
||||||
<button type="button" onclick="window.history.back()">Back</button>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%></div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
<%@ 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>
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
||||||
pageEncoding="UTF-8"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Util"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Configuration"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Session"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.User"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Logger"%>
|
|
||||||
<%
|
|
||||||
final boolean failed;
|
|
||||||
final String username = request.getParameter("username");
|
|
||||||
User user = null;
|
|
||||||
if ("post".equalsIgnoreCase(request.getMethod())) {
|
|
||||||
final String password = request.getParameter("password");
|
|
||||||
user = Util.login(username, password);
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final String privilegedHost = Configuration.INSTANCE.getPrivilegedHost();
|
|
||||||
if (username != null && privilegedHost != null ) {
|
|
||||||
String remoteHost = request.getRemoteHost();
|
|
||||||
if (privilegedHost.equals(remoteHost)) {
|
|
||||||
user = Util.login(username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
failed = false;
|
|
||||||
session.removeAttribute("email-session");
|
|
||||||
}
|
|
||||||
if (user != null) {
|
|
||||||
Session timesheetSession = new Session();
|
|
||||||
timesheetSession.setUser(user);
|
|
||||||
session.setAttribute("email-session", timesheetSession);
|
|
||||||
String returnServletPath = (String) session.getAttribute("return-servlet-path");
|
|
||||||
if (returnServletPath == null) {
|
|
||||||
returnServletPath = "/index.jsp";
|
|
||||||
}
|
|
||||||
String returnQueryString = (String) session.getAttribute("return-query-string");
|
|
||||||
if (returnQueryString == null) {
|
|
||||||
returnQueryString = "";
|
|
||||||
}
|
|
||||||
final String returnUrl = request.getContextPath() + returnServletPath + "?"
|
|
||||||
+ returnQueryString;
|
|
||||||
response.sendRedirect(returnUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
%><!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">
|
|
||||||
<title>Login</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-spacing: 0px;
|
|
||||||
}
|
|
||||||
table.td {
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
div.buttons {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
@media only screen and (min-resolution:2x) {
|
|
||||||
body {
|
|
||||||
font-size: 300%;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<%
|
|
||||||
if (failed) {
|
|
||||||
%><div class="fail">That didn't work.</div>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%><form name="login" action="login.jsp" method="post">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Username</td>
|
|
||||||
<td><input type="text" name="username" value="<%=username == null ? "" : username%>" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Password</td>
|
|
||||||
<td><input type="password" name="password" /></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type="submit">Login</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
<%@ 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.Mapping"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Util"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.User"%>
|
|
||||||
<%
|
|
||||||
final String address = request.getParameter("address");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Util.updateSession(session);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final List<String> targetList = (List<String>) session.getAttribute("target-list");
|
|
||||||
final Mapping mapping = address == null ? null : Util.getMapping(address);
|
|
||||||
final String username = user.getName();
|
|
||||||
final String header = "Mapping";
|
|
||||||
final String descriptionValue = mapping == null ? "" : mapping.getDisplayDescription();
|
|
||||||
final String dateValue = mapping == null ? "" : mapping.getFormattedDate();
|
|
||||||
%>
|
|
||||||
<!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">
|
|
||||||
<title>Mapping</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
table.mapping tr td {
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
table.mapping tr td:first-of-type {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
div.buttons {
|
|
||||||
margin-top: 2em;
|
|
||||||
}
|
|
||||||
@media only screen and (min-resolution:2x) {
|
|
||||||
body {
|
|
||||||
font-size: 300%;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
input[type="checkbox"] {
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5em;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body">
|
|
||||||
<h1><%=header %></h1>
|
|
||||||
<table class="mapping">
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Target</td>
|
|
||||||
<td>
|
|
||||||
<%=mapping.getTarget()%>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Email Address</td>
|
|
||||||
<td>
|
|
||||||
<%=mapping.getAddress()%>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Description</td>
|
|
||||||
<td>
|
|
||||||
<%=mapping.getDisplayDescription()%>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Date</td>
|
|
||||||
<td>
|
|
||||||
<%=mapping.getFormattedDate()%>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Disabled</td>
|
|
||||||
<td>
|
|
||||||
<%=mapping.isDisabled() ? "true" : "false" %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type="button" onclick="window.location.href='edit.jsp?mobile=true'">New</button>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
||||||
pageEncoding="UTF-8"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Util"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Session"%>
|
|
||||||
<%@ 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 message = null;
|
|
||||||
if ("post".equalsIgnoreCase(request.getMethod())) {
|
|
||||||
final String password1 = request.getParameter("password1");
|
|
||||||
final String password2 = request.getParameter("password2");
|
|
||||||
if (!password1.equals(password2)) {
|
|
||||||
message = "Passwords don't match.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Util.changePassword(user.getId(), password1);
|
|
||||||
response.sendRedirect("index.jsp");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message = null;
|
|
||||||
}
|
|
||||||
%><!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">
|
|
||||||
<title>Password</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-spacing: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.td {
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.buttons {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<%
|
|
||||||
if (message != null) {
|
|
||||||
%><div class="fail">
|
|
||||||
<%=message%>
|
|
||||||
</div>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
%><form name="register" action="register.jsp" method="post">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Password</td>
|
|
||||||
<td><input type="password" name="password1" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Confirm password</td>
|
|
||||||
<td><input type="password" name="password2" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Display name</td>
|
|
||||||
<td><input type="text" name="displayName" /></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type="submit">Register</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
|
||||||
pageEncoding="UTF-8"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Util"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.Session"%>
|
|
||||||
<%@ page import="com.stephenschafer.email.User"%>
|
|
||||||
<%
|
|
||||||
final String message;
|
|
||||||
if("post".equalsIgnoreCase(request.getMethod())) {
|
|
||||||
final String username = request.getParameter("username");
|
|
||||||
final String password1 = request.getParameter("password1");
|
|
||||||
final String password2 = request.getParameter("password2");
|
|
||||||
final String displayName = request.getParameter("displayName");
|
|
||||||
final boolean canWrite = "true".equals(request.getParameter("canWrite"));
|
|
||||||
if(!password1.equals(password2)) {
|
|
||||||
message = "Passwords don't match.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final User user = Util.register(username, password1, displayName, canWrite);
|
|
||||||
if(user != null) {
|
|
||||||
Session emailSession = new Session();
|
|
||||||
emailSession.setUser(user);
|
|
||||||
session.setAttribute("email-session", emailSession);
|
|
||||||
response.sendRedirect("index.jsp");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
message = "That didn't work.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
%><!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">
|
|
||||||
<title>Register</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-spacing: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.td {
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
div.buttons {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<%
|
|
||||||
if(message != null) {
|
|
||||||
|
|
||||||
%><div class="fail">
|
|
||||||
<%=message %>
|
|
||||||
</div>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
|
|
||||||
%><form name="register" action="register.jsp" method="post">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Username</td>
|
|
||||||
<td><input type="text" name="username"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Password</td>
|
|
||||||
<td><input type="password" name="password1"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Confirm password</td>
|
|
||||||
<td><input type="password" name="password2"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Display name</td>
|
|
||||||
<td><input type="text" name="displayName"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Can write</td>
|
|
||||||
<td><input type="checkbox" name="canWrite" value="true"/></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type="submit">Register</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
9
build
9
build
|
|
@ -1,9 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
|
||||||
ROOT=$(pwd)
|
|
||||||
mkdir -p logs
|
|
||||||
if ! mvn clean package > logs/build.log 2> logs/build.err.log; then
|
|
||||||
echo "build failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "success"
|
|
||||||
5
deploy
5
deploy
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
|
||||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
||||||
ssh pi@raspi "mv ~/tomcat/webapps/email.war ~/tomcat/webapps/email.war_$TIMESTAMP"
|
|
||||||
scp target/com.stephenschafer.email-manager-0.0.2-SNAPSHOT.war pi@raspi:~/tomcat/webapps/email.war
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
[INFO] Scanning for projects...
|
|
||||||
[INFO]
|
|
||||||
[INFO] --< com.stephenschafer.email-manager:com.stephenschafer.email-manager >--
|
|
||||||
[INFO] Building com.stephenschafer.email-manager 0.0.2-SNAPSHOT
|
|
||||||
[INFO] from pom.xml
|
|
||||||
[INFO] --------------------------------[ war ]---------------------------------
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- clean:3.2.0:clean (default-clean) @ com.stephenschafer.email-manager ---
|
|
||||||
[INFO] Deleting /disk1/home/sschafer/projects/com.stephenschafer.email/target
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- resources:3.3.1:resources (default-resources) @ com.stephenschafer.email-manager ---
|
|
||||||
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
|
|
||||||
[INFO] skip non existing resourceDirectory /disk1/home/sschafer/projects/com.stephenschafer.email/src/main/resources
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ com.stephenschafer.email-manager ---
|
|
||||||
[INFO] Recompiling the module because of changed source code.
|
|
||||||
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
|
|
||||||
[INFO] Compiling 14 source files with javac [debug target 1.8] to target/classes
|
|
||||||
[WARNING] bootstrap class path not set in conjunction with -source 8
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ com.stephenschafer.email-manager ---
|
|
||||||
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
|
|
||||||
[INFO] skip non existing resourceDirectory /disk1/home/sschafer/projects/com.stephenschafer.email/src/test/resources
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ com.stephenschafer.email-manager ---
|
|
||||||
[INFO] No sources to compile
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- surefire:3.2.2:test (default-test) @ com.stephenschafer.email-manager ---
|
|
||||||
[INFO] No tests to run.
|
|
||||||
[INFO]
|
|
||||||
[INFO] --- war:3.4.0:war (default-war) @ com.stephenschafer.email-manager ---
|
|
||||||
[INFO] Packaging webapp
|
|
||||||
[INFO] Assembling webapp [com.stephenschafer.email-manager] in [/disk1/home/sschafer/projects/com.stephenschafer.email/target/com.stephenschafer.email-manager-0.0.2-SNAPSHOT]
|
|
||||||
[INFO] Processing war project
|
|
||||||
[INFO] Copying webapp resources [/disk1/home/sschafer/projects/com.stephenschafer.email/WebContent]
|
|
||||||
[INFO] Building war: /disk1/home/sschafer/projects/com.stephenschafer.email/target/com.stephenschafer.email-manager-0.0.2-SNAPSHOT.war
|
|
||||||
[INFO] ------------------------------------------------------------------------
|
|
||||||
[INFO] BUILD SUCCESS
|
|
||||||
[INFO] ------------------------------------------------------------------------
|
|
||||||
[INFO] Total time: 2.078 s
|
|
||||||
[INFO] Finished at: 2024-11-28T08:07:33-07:00
|
|
||||||
[INFO] ------------------------------------------------------------------------
|
|
||||||
51
pom.xml
51
pom.xml
|
|
@ -1,51 +0,0 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>com.stephenschafer.email-manager</groupId>
|
|
||||||
<artifactId>com.stephenschafer.email-manager</artifactId>
|
|
||||||
<version>0.0.2-SNAPSHOT</version>
|
|
||||||
<packaging>war</packaging>
|
|
||||||
<build>
|
|
||||||
<sourceDirectory>src</sourceDirectory>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.13.0</version>
|
|
||||||
<configuration>
|
|
||||||
<source>1.8</source>
|
|
||||||
<target>1.8</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
|
||||||
<version>3.4.0</version>
|
|
||||||
<configuration>
|
|
||||||
<warSourceDirectory>WebContent</warSourceDirectory>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
|
||||||
<version>4.0.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<version>5.1.38</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-core</artifactId>
|
|
||||||
<version>2.18.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
<version>2.18.1</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import javax.naming.InitialContext;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
public class Configuration {
|
|
||||||
public static final Configuration INSTANCE;
|
|
||||||
private String jndiName;
|
|
||||||
private DbConnectionPool pool;
|
|
||||||
private String privilegedHost;
|
|
||||||
private String defaultDomain;
|
|
||||||
private boolean loaded;
|
|
||||||
|
|
||||||
private Configuration() {
|
|
||||||
jndiName = null;
|
|
||||||
pool = null;
|
|
||||||
loaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void load() throws IOException, ClassNotFoundException, SQLException {
|
|
||||||
if (loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Properties systemProps = System.getProperties();
|
|
||||||
final String catalinaHome = systemProps.getProperty("catalina.home");
|
|
||||||
String propertiesFileName = System.getenv("EMAIL_PROPERTIES");
|
|
||||||
if (propertiesFileName == null) {
|
|
||||||
propertiesFileName = catalinaHome + "/conf/Catalina/localhost/email.properties";
|
|
||||||
}
|
|
||||||
final File propertiesFile = new File(propertiesFileName);
|
|
||||||
final Properties properties = new Properties();
|
|
||||||
try (FileInputStream fis = new FileInputStream(propertiesFile)) {
|
|
||||||
properties.load(fis);
|
|
||||||
}
|
|
||||||
Logger.logFilename = properties.getProperty("log.filename");
|
|
||||||
Logger.log("********************************* Starting");
|
|
||||||
jndiName = properties.getProperty("db.jndi");
|
|
||||||
final String url = properties.getProperty("db.url");
|
|
||||||
final String username = properties.getProperty("db.username");
|
|
||||||
final String password = properties.getProperty("db.password");
|
|
||||||
if (jndiName == null) {
|
|
||||||
pool = new DbConnectionPool("com.mysql.jdbc.Driver", url, username, password);
|
|
||||||
}
|
|
||||||
privilegedHost = properties.getProperty("priv-host");
|
|
||||||
final String defaultDomain = properties.getProperty("default-domain");
|
|
||||||
this.defaultDomain = defaultDomain == null ? "schafer.cc" : defaultDomain;
|
|
||||||
Logger.log("initialized, jndiName = " + jndiName);
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Connection getConnection() throws SQLException, NamingException {
|
|
||||||
final String jndiName = getJndiName();
|
|
||||||
if (jndiName != null) {
|
|
||||||
final InitialContext initialContext = new InitialContext();
|
|
||||||
final DataSource datasource = (DataSource) initialContext.lookup(jndiName);
|
|
||||||
SQLException lastException = null;
|
|
||||||
int i = 0;
|
|
||||||
while (i < 4) {
|
|
||||||
try {
|
|
||||||
return datasource.getConnection();
|
|
||||||
}
|
|
||||||
catch (final SQLException e) {
|
|
||||||
Logger.log("Failed to get connection, " + (3 - i) + " retrys left", e);
|
|
||||||
lastException = e;
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000L);
|
|
||||||
}
|
|
||||||
catch (final InterruptedException ex) {
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lastException != null) {
|
|
||||||
throw lastException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getPool().getConnection(8, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getJndiName() {
|
|
||||||
return jndiName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJndiName(final String jndiName) {
|
|
||||||
this.jndiName = jndiName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbConnectionPool getPool() {
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPool(final DbConnectionPool pool) {
|
|
||||||
this.pool = pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
INSTANCE = new Configuration();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPrivilegedHost() {
|
|
||||||
return privilegedHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultDomain() {
|
|
||||||
return defaultDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultDomain(final String defaultDomain) {
|
|
||||||
this.defaultDomain = defaultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,693 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.sql.Array;
|
|
||||||
import java.sql.Blob;
|
|
||||||
import java.sql.CallableStatement;
|
|
||||||
import java.sql.Clob;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DatabaseMetaData;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.NClob;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.SQLClientInfoException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.SQLWarning;
|
|
||||||
import java.sql.SQLXML;
|
|
||||||
import java.sql.Savepoint;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.sql.Struct;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class DbConnectionPool implements Serializable {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static final Logger LOGGER;
|
|
||||||
private final String uRL;
|
|
||||||
private final String username;
|
|
||||||
private final String password;
|
|
||||||
private final String driver;
|
|
||||||
private final Queue<PooledConnection> connections;
|
|
||||||
private long openConnectionIndex;
|
|
||||||
private final Map<Long, OpenConnectionInfo> openConnections;
|
|
||||||
private long timeout;
|
|
||||||
|
|
||||||
public DbConnectionPool(final String dbDriver, final String dbName, final String dbUsername,
|
|
||||||
final String dbPassword) throws ClassNotFoundException, SQLException {
|
|
||||||
this.connections = new LinkedList<>();
|
|
||||||
this.openConnectionIndex = 0L;
|
|
||||||
this.openConnections = new HashMap<>();
|
|
||||||
this.timeout = 900000L;
|
|
||||||
this.driver = dbDriver;
|
|
||||||
this.uRL = dbName;
|
|
||||||
this.username = dbUsername;
|
|
||||||
this.password = dbPassword;
|
|
||||||
this.validateConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void validateConnection() throws ClassNotFoundException, SQLException {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST, "Testing connection pool");
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST, "Instantiating " + this.driver + "\n");
|
|
||||||
Class.forName(this.driver);
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST, "Connecting");
|
|
||||||
final Connection connection = DriverManager.getConnection(this.uRL, this.username,
|
|
||||||
this.password);
|
|
||||||
try {
|
|
||||||
final DatabaseMetaData dbmd = connection.getMetaData();
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST,
|
|
||||||
"Connection to " + dbmd.getDatabaseProductName() + " "
|
|
||||||
+ dbmd.getDatabaseProductVersion() + " successful.");
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void clear() throws SQLException {
|
|
||||||
synchronized (this) {
|
|
||||||
while (!this.connections.isEmpty()) {
|
|
||||||
final PooledConnection connection = this.connections.remove();
|
|
||||||
connection.reallyClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final PooledConnection getConnection(final int transactionIsolation,
|
|
||||||
final boolean readOnly, final boolean autoCommit) throws SQLException {
|
|
||||||
while (true) {
|
|
||||||
PooledConnection oldConnection;
|
|
||||||
final long timeout;
|
|
||||||
synchronized (this) {
|
|
||||||
if (this.connections.isEmpty()) {
|
|
||||||
oldConnection = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
oldConnection = this.connections.remove();
|
|
||||||
}
|
|
||||||
timeout = this.timeout;
|
|
||||||
}
|
|
||||||
if (oldConnection == null) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST, "Connecting");
|
|
||||||
SQLException exception = null;
|
|
||||||
int retryCount = 0;
|
|
||||||
while (retryCount < 10) {
|
|
||||||
Connection newConnection;
|
|
||||||
try {
|
|
||||||
newConnection = DriverManager.getConnection(this.uRL, this.username,
|
|
||||||
this.password);
|
|
||||||
}
|
|
||||||
catch (final SQLException e) {
|
|
||||||
if (!(e.getCause() instanceof SocketException)) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
exception = e;
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST, "Retrying", e);
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000L);
|
|
||||||
}
|
|
||||||
catch (final InterruptedException ex) {
|
|
||||||
}
|
|
||||||
++retryCount;
|
|
||||||
newConnection = null;
|
|
||||||
}
|
|
||||||
if (newConnection != null) {
|
|
||||||
newConnection.setAutoCommit(true);
|
|
||||||
newConnection.setTransactionIsolation(transactionIsolation);
|
|
||||||
newConnection.setReadOnly(readOnly);
|
|
||||||
newConnection.setAutoCommit(autoCommit);
|
|
||||||
final long index = this.incrementOpenConnectionCount();
|
|
||||||
return new PooledConnection(newConnection, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (exception != null) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (oldConnection != null) {
|
|
||||||
if (oldConnection.isClosed()) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING,
|
|
||||||
"Pooled connection was already closed");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Label_0439: {
|
|
||||||
Label_0428: {
|
|
||||||
if (timeout != 0L) {
|
|
||||||
if (System.currentTimeMillis()
|
|
||||||
- oldConnection.getLastAccess() >= timeout) {
|
|
||||||
break Label_0428;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
oldConnection.setAutoCommit(true);
|
|
||||||
oldConnection.setTransactionIsolation(transactionIsolation);
|
|
||||||
oldConnection.setReadOnly(readOnly);
|
|
||||||
oldConnection.setAutoCommit(autoCommit);
|
|
||||||
synchronized (this) {
|
|
||||||
final Long key = oldConnection.getIndex();
|
|
||||||
final OpenConnectionInfo info = this.openConnections.get(key);
|
|
||||||
if (info != null) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING,
|
|
||||||
"Overwriting open connection info: " + key + " "
|
|
||||||
+ info);
|
|
||||||
}
|
|
||||||
this.openConnections.put(key, new OpenConnectionInfo());
|
|
||||||
}
|
|
||||||
return oldConnection;
|
|
||||||
}
|
|
||||||
catch (final Exception e2) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.SEVERE,
|
|
||||||
"Unable to reuse DB connection", e2);
|
|
||||||
break Label_0439;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DbConnectionPool.LOGGER.log(Level.FINEST, "DB connection timed out");
|
|
||||||
try {
|
|
||||||
oldConnection.reallyClose();
|
|
||||||
}
|
|
||||||
catch (final Exception e2) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.SEVERE,
|
|
||||||
"Unable to really close DB connection", e2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long incrementOpenConnectionCount() {
|
|
||||||
synchronized (this) {
|
|
||||||
final long index = this.openConnectionIndex++;
|
|
||||||
final Long key = index;
|
|
||||||
final OpenConnectionInfo info = this.openConnections.get(key);
|
|
||||||
if (info != null) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING,
|
|
||||||
"Overwriting open connection info: " + key + " " + info);
|
|
||||||
}
|
|
||||||
this.openConnections.put(key, new OpenConnectionInfo());
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void add(final PooledConnection connection) {
|
|
||||||
synchronized (this) {
|
|
||||||
final OpenConnectionInfo info = this.openConnections.remove(connection.getIndex());
|
|
||||||
if (info == null) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING,
|
|
||||||
"adding orphaned connection: " + connection.getIndex());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.connections.offer(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final long getOpenConnectionIndex() {
|
|
||||||
synchronized (this) {
|
|
||||||
return this.openConnectionIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final OpenConnectionInfo getOpenConnectionInfo(final long index) {
|
|
||||||
synchronized (this) {
|
|
||||||
return this.openConnections.get(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getOpenConnectionCount() {
|
|
||||||
synchronized (this) {
|
|
||||||
return this.openConnections.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getPooledConnectionCount() {
|
|
||||||
synchronized (this) {
|
|
||||||
return this.connections.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
final StringBuilder buf = new StringBuilder();
|
|
||||||
buf.append("DB ");
|
|
||||||
buf.append(this.uRL);
|
|
||||||
buf.append(" ");
|
|
||||||
synchronized (this) {
|
|
||||||
buf.append("open: ");
|
|
||||||
buf.append(this.openConnections.size());
|
|
||||||
buf.append(", pooled: ");
|
|
||||||
buf.append(this.connections.size());
|
|
||||||
buf.append(", next: ");
|
|
||||||
buf.append(this.openConnectionIndex);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final long getTimeout() {
|
|
||||||
synchronized (this) {
|
|
||||||
return this.timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setTimeout(final long timeout) {
|
|
||||||
synchronized (this) {
|
|
||||||
this.timeout = timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getDriver() {
|
|
||||||
return this.driver;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getURL() {
|
|
||||||
return this.uRL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getPassword() {
|
|
||||||
return this.password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getUsername() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized Map<Long, Long> getOpenConnections() {
|
|
||||||
final Map<Long, Long> map = new HashMap<>();
|
|
||||||
for (final Long index : this.openConnections.keySet()) {
|
|
||||||
final OpenConnectionInfo info = this.openConnections.get(index);
|
|
||||||
map.put(index, info.timestamp);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
LOGGER = Logger.getLogger(DbConnectionPool.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class OpenConnectionInfo {
|
|
||||||
public final long timestamp;
|
|
||||||
private final List<StackTraceElement> stackTrace;
|
|
||||||
|
|
||||||
public OpenConnectionInfo() {
|
|
||||||
this.timestamp = System.currentTimeMillis();
|
|
||||||
final StackTraceElement[] steArray = Thread.currentThread().getStackTrace();
|
|
||||||
final List<StackTraceElement> stackTrace = new ArrayList<>(
|
|
||||||
steArray.length);
|
|
||||||
for (final StackTraceElement element : steArray) {
|
|
||||||
stackTrace.add(element);
|
|
||||||
}
|
|
||||||
this.stackTrace = Collections.unmodifiableList(
|
|
||||||
(List<? extends StackTraceElement>) stackTrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Timestamp: ");
|
|
||||||
sb.append(new Date(this.timestamp));
|
|
||||||
sb.append("\n");
|
|
||||||
for (final StackTraceElement element : this.stackTrace) {
|
|
||||||
sb.append(element);
|
|
||||||
sb.append("\n");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PooledConnection implements Connection {
|
|
||||||
private final Connection connection;
|
|
||||||
private long lastAccess;
|
|
||||||
private boolean autoCommit;
|
|
||||||
private boolean readOnly;
|
|
||||||
private final long index;
|
|
||||||
|
|
||||||
public PooledConnection(final Connection connection, final long index) {
|
|
||||||
this.lastAccess = System.currentTimeMillis();
|
|
||||||
this.autoCommit = false;
|
|
||||||
this.readOnly = false;
|
|
||||||
this.index = index;
|
|
||||||
this.connection = connection;
|
|
||||||
try {
|
|
||||||
this.autoCommit = connection.getAutoCommit();
|
|
||||||
}
|
|
||||||
catch (final SQLException e) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING, "Unable to get auto commit", e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
this.readOnly = connection.isReadOnly();
|
|
||||||
}
|
|
||||||
catch (final SQLException e) {
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING, "Unable to get read only", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearPool() throws SQLException {
|
|
||||||
DbConnectionPool.this.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String nativeSQL(final String sql) throws SQLException {
|
|
||||||
return this.connection.nativeSQL(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return this.connection.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Class<?>> getTypeMap() throws SQLException {
|
|
||||||
return this.connection.getTypeMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PreparedStatement prepareStatement(final String sql) throws SQLException {
|
|
||||||
final PreparedStatement stmt = this.connection.prepareStatement(sql);
|
|
||||||
if (this.connection.getAutoCommit() != this.autoCommit
|
|
||||||
|| this.connection.isReadOnly() != this.readOnly) {
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
String sep = "";
|
|
||||||
if (this.connection.getAutoCommit() != this.autoCommit) {
|
|
||||||
sb.append(sep);
|
|
||||||
sep = " and ";
|
|
||||||
sb.append("autoCommit has changed from " + this.autoCommit);
|
|
||||||
}
|
|
||||||
if (this.connection.isReadOnly() != this.readOnly) {
|
|
||||||
sb.append(sep);
|
|
||||||
sep = " and ";
|
|
||||||
sb.append("readOnly has changed from " + this.readOnly);
|
|
||||||
}
|
|
||||||
sb.append(" in ");
|
|
||||||
sb.append(stmt);
|
|
||||||
DbConnectionPool.LOGGER.log(Level.WARNING, sb.toString());
|
|
||||||
}
|
|
||||||
return stmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTransactionIsolation(final int level) throws SQLException {
|
|
||||||
this.connection.setTransactionIsolation(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCatalog() throws SQLException {
|
|
||||||
return this.connection.getCatalog();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTransactionIsolation() throws SQLException {
|
|
||||||
return this.connection.getTransactionIsolation();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
|
|
||||||
this.connection.releaseSavepoint(savepoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHoldability() throws SQLException {
|
|
||||||
return this.connection.getHoldability();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CallableStatement prepareCall(final String sql, final int resultSetType,
|
|
||||||
final int resultSetConcurrency, final int resultSetHoldability)
|
|
||||||
throws SQLException {
|
|
||||||
return this.connection.prepareCall(sql, resultSetType, resultSetConcurrency,
|
|
||||||
resultSetHoldability);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getAutoCommit() throws SQLException {
|
|
||||||
return this.connection.getAutoCommit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Statement createStatement() throws SQLException {
|
|
||||||
return this.connection.createStatement();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CallableStatement prepareCall(final String sql) throws SQLException {
|
|
||||||
return this.connection.prepareCall(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAutoCommit(final boolean autoCommit) throws SQLException {
|
|
||||||
this.autoCommit = autoCommit;
|
|
||||||
this.connection.setAutoCommit(autoCommit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys)
|
|
||||||
throws SQLException {
|
|
||||||
return this.connection.prepareStatement(sql, autoGeneratedKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadOnly(final boolean readOnly) throws SQLException {
|
|
||||||
this.readOnly = readOnly;
|
|
||||||
this.connection.setReadOnly(readOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CallableStatement prepareCall(final String sql, final int resultSetType,
|
|
||||||
final int resultSetConcurrency) throws SQLException {
|
|
||||||
return this.connection.prepareCall(sql, resultSetType, resultSetConcurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SQLWarning getWarnings() throws SQLException {
|
|
||||||
return this.connection.getWarnings();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PreparedStatement prepareStatement(final String sql, final int resultSetType,
|
|
||||||
final int resultSetConcurrency) throws SQLException {
|
|
||||||
return this.connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
return this.connection.equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes)
|
|
||||||
throws SQLException {
|
|
||||||
return this.connection.prepareStatement(sql, columnIndexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isClosed() throws SQLException {
|
|
||||||
return this.connection.isClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PreparedStatement prepareStatement(final String sql, final int resultSetType,
|
|
||||||
final int resultSetConcurrency, final int resultSetHoldability)
|
|
||||||
throws SQLException {
|
|
||||||
return this.connection.prepareStatement(sql, resultSetType, resultSetConcurrency,
|
|
||||||
resultSetHoldability);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void commit() throws SQLException {
|
|
||||||
this.connection.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearWarnings() throws SQLException {
|
|
||||||
this.connection.clearWarnings();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCatalog(final String catalog) throws SQLException {
|
|
||||||
this.connection.setCatalog(catalog);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
DbConnectionPool.this.add(this);
|
|
||||||
this.lastAccess = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reallyClose() throws SQLException {
|
|
||||||
this.connection.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.connection.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DatabaseMetaData getMetaData() throws SQLException {
|
|
||||||
return this.connection.getMetaData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rollback() throws SQLException {
|
|
||||||
this.connection.rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Savepoint setSavepoint(final String name) throws SQLException {
|
|
||||||
return this.connection.setSavepoint(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isReadOnly() throws SQLException {
|
|
||||||
return this.connection.isReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Statement createStatement(final int resultSetType, final int resultSetConcurrency)
|
|
||||||
throws SQLException {
|
|
||||||
return this.connection.createStatement(resultSetType, resultSetConcurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rollback(final Savepoint savepoint) throws SQLException {
|
|
||||||
this.connection.rollback(savepoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PreparedStatement prepareStatement(final String sql, final String[] columnNames)
|
|
||||||
throws SQLException {
|
|
||||||
return this.connection.prepareStatement(sql, columnNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Savepoint setSavepoint() throws SQLException {
|
|
||||||
return this.connection.setSavepoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Statement createStatement(final int resultSetType, final int resultSetConcurrency,
|
|
||||||
final int resultSetHoldability) throws SQLException {
|
|
||||||
return this.connection.createStatement(resultSetType, resultSetConcurrency,
|
|
||||||
resultSetHoldability);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
|
|
||||||
this.connection.setTypeMap(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setHoldability(final int holdability) throws SQLException {
|
|
||||||
this.connection.setHoldability(holdability);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastAccess() {
|
|
||||||
return this.lastAccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Array createArrayOf(final String arg0, final Object[] arg1) throws SQLException {
|
|
||||||
return this.connection.createArrayOf(arg0, arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Blob createBlob() throws SQLException {
|
|
||||||
return this.connection.createBlob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Clob createClob() throws SQLException {
|
|
||||||
return this.connection.createClob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NClob createNClob() throws SQLException {
|
|
||||||
return this.connection.createNClob();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SQLXML createSQLXML() throws SQLException {
|
|
||||||
return this.connection.createSQLXML();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Struct createStruct(final String arg0, final Object[] arg1) throws SQLException {
|
|
||||||
return this.connection.createStruct(arg0, arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Properties getClientInfo() throws SQLException {
|
|
||||||
return this.connection.getClientInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getClientInfo(final String arg0) throws SQLException {
|
|
||||||
return this.connection.getClientInfo(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(final int arg0) throws SQLException {
|
|
||||||
return this.connection.isValid(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setClientInfo(final Properties arg0) throws SQLClientInfoException {
|
|
||||||
this.connection.setClientInfo(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setClientInfo(final String arg0, final String arg1)
|
|
||||||
throws SQLClientInfoException {
|
|
||||||
this.connection.setClientInfo(arg0, arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWrapperFor(final Class<?> arg0) throws SQLException {
|
|
||||||
return this.connection.isWrapperFor(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T unwrap(final Class<T> arg0) throws SQLException {
|
|
||||||
return this.connection.unwrap(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getIndex() {
|
|
||||||
return this.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSchema(final String schema) throws SQLException {
|
|
||||||
this.connection.setSchema(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSchema() throws SQLException {
|
|
||||||
return this.connection.getSchema();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void abort(final Executor executor) throws SQLException {
|
|
||||||
this.connection.abort(executor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNetworkTimeout(final Executor executor, final int milliseconds)
|
|
||||||
throws SQLException {
|
|
||||||
this.connection.setNetworkTimeout(executor, milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getNetworkTimeout() throws SQLException {
|
|
||||||
return this.connection.getNetworkTimeout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,190 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
|
|
||||||
import com.stephenschafer.email.Util.SaveMappingsResult;
|
|
||||||
|
|
||||||
public class GlobalCache {
|
|
||||||
public static final GlobalCache INSTANCE = new GlobalCache();
|
|
||||||
private static final Pattern COMMENT_PATTERN = Pattern.compile("^ *# *(.*)$");
|
|
||||||
private static final Pattern DATE_PATTERN = Pattern.compile(
|
|
||||||
"^ *# *@([0-9]{4}-[0-9]{2}-[0-9]{2})$");
|
|
||||||
private static final Pattern MAPPING_PATTERN = Pattern.compile("^ *([^ ]+) +(.*)$");
|
|
||||||
private static final Pattern DISABLED_PATTERN = Pattern.compile("^ *# *- *([^ ]+) +(.*)$");
|
|
||||||
private boolean initialized = false;
|
|
||||||
|
|
||||||
public synchronized void initialize() throws IOException, SQLException, NamingException {
|
|
||||||
if (!initialized) {
|
|
||||||
if (Util.getMappingsCountFromDb() == 0) {
|
|
||||||
parseVirtualFile();
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized static void parseVirtualFile()
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
Logger.log("parsing virtual file");
|
|
||||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
final File file = new File("/etc/postfix/virtual");
|
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
|
||||||
String line = reader.readLine();
|
|
||||||
String previousComment = null;
|
|
||||||
Date previousDate = null;
|
|
||||||
while (line != null) {
|
|
||||||
final Matcher disabledMatcher = DISABLED_PATTERN.matcher(line);
|
|
||||||
if (disabledMatcher.matches()) {
|
|
||||||
final String address = disabledMatcher.group(1);
|
|
||||||
final String target = disabledMatcher.group(2);
|
|
||||||
final Mapping mapping = new Mapping(address, target, previousComment,
|
|
||||||
previousDate, true);
|
|
||||||
Util.addMappingToDb(mapping);
|
|
||||||
previousComment = null;
|
|
||||||
previousDate = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Matcher datedCommentMatcher = DATE_PATTERN.matcher(line);
|
|
||||||
if (datedCommentMatcher.matches()) {
|
|
||||||
try {
|
|
||||||
final String dateString = datedCommentMatcher.group(1);
|
|
||||||
Logger.log(String.format("found date: %s", dateString));
|
|
||||||
previousDate = df.parse(dateString);
|
|
||||||
}
|
|
||||||
catch (final ParseException e) {
|
|
||||||
Logger.log("Failed to parse date from virtual", e);
|
|
||||||
previousDate = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Matcher commentMatcher = COMMENT_PATTERN.matcher(line);
|
|
||||||
if (commentMatcher.matches()) {
|
|
||||||
previousComment = commentMatcher.group(1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Matcher mappingMatcher = MAPPING_PATTERN.matcher(line);
|
|
||||||
if (mappingMatcher.matches()) {
|
|
||||||
final String from = mappingMatcher.group(1);
|
|
||||||
final String to = mappingMatcher.group(2);
|
|
||||||
final Mapping mapping = new Mapping(from, to, previousComment,
|
|
||||||
previousDate, false);
|
|
||||||
Util.addMappingToDb(mapping);
|
|
||||||
previousComment = null;
|
|
||||||
previousDate = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
line = reader.readLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized SaveMappingsResult writeVirtualFile()
|
|
||||||
throws IOException, InterruptedException, SQLException, NamingException {
|
|
||||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
final File userHome = new File(System.getProperty("user.home"));
|
|
||||||
final File stagingDir = new File(userHome, "staging");
|
|
||||||
stagingDir.mkdirs();
|
|
||||||
final File file = new File(stagingDir, "virtual");
|
|
||||||
if (file.exists()) {
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
file.createNewFile();
|
|
||||||
try (PrintWriter writer = new PrintWriter(new FileWriter(file))) {
|
|
||||||
final List<Mapping> list = Util.getMappingsFromDb();
|
|
||||||
for (final Mapping mapping : list) {
|
|
||||||
final String description = mapping.getDescription();
|
|
||||||
if (description != null) {
|
|
||||||
final Date date = mapping.getDate();
|
|
||||||
if (date != null) {
|
|
||||||
writer.println(String.format("#@%s", df.format(date)));
|
|
||||||
}
|
|
||||||
writer.println(String.format("# %s", description));
|
|
||||||
}
|
|
||||||
final boolean disabled = mapping.isDisabled();
|
|
||||||
if (disabled) {
|
|
||||||
writer.print("#-");
|
|
||||||
}
|
|
||||||
writer.println(String.format("%s %s", mapping.getAddress(), mapping.getTarget()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final Process process = Runtime.getRuntime().exec(
|
|
||||||
new File(userHome, "update-virtual").getAbsolutePath());
|
|
||||||
final String error = Util.streamToString(process.getErrorStream());
|
|
||||||
final String output = Util.streamToString(process.getInputStream());
|
|
||||||
final int exitValue = process.waitFor();
|
|
||||||
return new SaveMappingsResult() {
|
|
||||||
@Override
|
|
||||||
public int getExitValue() {
|
|
||||||
return exitValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getOutput() {
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getError() {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized boolean addressExists(final String address)
|
|
||||||
throws SQLException, NamingException, IOException {
|
|
||||||
initialize();
|
|
||||||
return Util.getMappingFromDb(address) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void addMapping(final Mapping mapping)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
initialize();
|
|
||||||
Util.addMappingToDb(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void addHistory(final Mapping mapping)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
initialize();
|
|
||||||
Util.addHistoryToDb(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateMapping(final Mapping mapping)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
initialize();
|
|
||||||
Util.updateMappingToDb(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized Mapping getMapping(final String address)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
initialize();
|
|
||||||
return Util.getMappingFromDb(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized List<Mapping> getMappings()
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
initialize();
|
|
||||||
return Util.getMappingsFromDb();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized List<String> getAliases(final String target)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
initialize();
|
|
||||||
return Util.getAliasesFromDb(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class Logger {
|
|
||||||
public static String logFilename;
|
|
||||||
public static boolean debugLogging;
|
|
||||||
|
|
||||||
public static void debugLog(final Object message) {
|
|
||||||
if (Logger.debugLogging) {
|
|
||||||
log(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void debugLog(final Object message, final Throwable t) {
|
|
||||||
if (Logger.debugLogging) {
|
|
||||||
log(message, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(final Object message) {
|
|
||||||
log(message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(final Object message, final Throwable t) {
|
|
||||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ");
|
|
||||||
try {
|
|
||||||
final String filename = Logger.logFilename;
|
|
||||||
if (filename == null) {
|
|
||||||
final PrintStream out = System.out;
|
|
||||||
out.print(df.format(new Date()));
|
|
||||||
out.print(" ");
|
|
||||||
out.println(message);
|
|
||||||
if (t != null) {
|
|
||||||
t.printStackTrace(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final File file = new File(filename);
|
|
||||||
final FileWriter fw = new FileWriter(file, true);
|
|
||||||
final PrintWriter pw = new PrintWriter(fw);
|
|
||||||
try {
|
|
||||||
pw.print(df.format(new Date()));
|
|
||||||
pw.print(" ");
|
|
||||||
pw.println(message);
|
|
||||||
if (t != null) {
|
|
||||||
t.printStackTrace(pw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
pw.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (final IOException e) {
|
|
||||||
System.out.println("Logger: Unable to log " + message);
|
|
||||||
if (t != null) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
log("Log failure caused by:");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
Logger.logFilename = null;
|
|
||||||
Logger.debugLogging = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
public class Logout extends HttpServlet {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
Util.logout(req.getSession());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
|
|
||||||
public class Mapping {
|
|
||||||
private static final Pattern ADDRESS_PATTERN = Pattern.compile("^([^@]+)@(.*)$");
|
|
||||||
private final String address;
|
|
||||||
private final String target;
|
|
||||||
private final String description;
|
|
||||||
private final Date date;
|
|
||||||
private final boolean disabled;
|
|
||||||
|
|
||||||
public Mapping(final String address, final String target, final String description,
|
|
||||||
final Date date, final boolean disabled) {
|
|
||||||
this.address = address;
|
|
||||||
this.target = target;
|
|
||||||
this.description = description;
|
|
||||||
this.date = date;
|
|
||||||
this.disabled = disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTarget() {
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayDescription() {
|
|
||||||
if (description == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisabled() {
|
|
||||||
return disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDomain() {
|
|
||||||
final Matcher matcher = ADDRESS_PATTERN.matcher(address);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
return matcher.group(2);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
final Matcher matcher = ADDRESS_PATTERN.matcher(address);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
return matcher.group(1);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean qualifies(final User user) throws SQLException, NamingException {
|
|
||||||
final List<Target> validTargets = user.getValidTargets();
|
|
||||||
if (validTargets == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (final Target validTarget : validTargets) {
|
|
||||||
if (validTarget.getAddress().equals(target)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDate() {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFormattedDate() {
|
|
||||||
if (date == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
return df.format(date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
public class NewAlias extends HttpServlet {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
try {
|
|
||||||
final InputStream inputStream = request.getInputStream();
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
final byte[] buffer = new byte[0x1000];
|
|
||||||
int bytesRead = inputStream.read(buffer);
|
|
||||||
while (bytesRead >= 0) {
|
|
||||||
final String string = new String(buffer, 0, bytesRead);
|
|
||||||
sb.append(string);
|
|
||||||
bytesRead = inputStream.read(buffer);
|
|
||||||
}
|
|
||||||
String target = sb.toString();
|
|
||||||
final int indexOfAt = target.indexOf("@");
|
|
||||||
if (indexOfAt >= 0) {
|
|
||||||
target = target.substring(0, indexOfAt);
|
|
||||||
}
|
|
||||||
final String address = getAddress(target);
|
|
||||||
final PrintWriter out = response.getWriter();
|
|
||||||
out.println("{\"value\":\"" + address + "\"}");
|
|
||||||
}
|
|
||||||
catch (final Exception e) {
|
|
||||||
throw new ServletException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getAddress(final String target)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
final String defaultDomain = Configuration.INSTANCE.getDefaultDomain();
|
|
||||||
final String patternString = target + "([0-9]+)@" + defaultDomain.replace(".", "\\.");
|
|
||||||
Logger.log("pattern = " + patternString);
|
|
||||||
final Pattern pattern = Pattern.compile(patternString);
|
|
||||||
final List<String> aliasList = Util.getAliases(target);
|
|
||||||
Logger.log("aliasList = " + aliasList);
|
|
||||||
final Set<Integer> indexSet = new HashSet<>();
|
|
||||||
for (final String alias : aliasList) {
|
|
||||||
final Matcher matcher = pattern.matcher(alias);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
indexSet.add(Integer.valueOf(matcher.group(1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final List<Integer> indexList = new ArrayList<>(indexSet);
|
|
||||||
Collections.sort(indexList);
|
|
||||||
Logger.log("indexList = " + indexList);
|
|
||||||
Integer prevIndex = null;
|
|
||||||
for (final Integer index : indexList) {
|
|
||||||
if (prevIndex == null && index.intValue() > 1) {
|
|
||||||
prevIndex = Integer.valueOf(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (prevIndex != null && index.intValue() - prevIndex.intValue() > 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prevIndex = index;
|
|
||||||
}
|
|
||||||
int useIndex = 1;
|
|
||||||
if (prevIndex != null) {
|
|
||||||
useIndex = prevIndex.intValue() + 1;
|
|
||||||
}
|
|
||||||
Logger.log("useIndex = " + useIndex);
|
|
||||||
return target + useIndex + "@" + defaultDomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
public class PostMapping extends HttpServlet {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(final ServletConfig config) throws ServletException {
|
|
||||||
try {
|
|
||||||
Configuration.INSTANCE.load();
|
|
||||||
GlobalCache.INSTANCE.initialize();
|
|
||||||
}
|
|
||||||
catch (final Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
super.init(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
try {
|
|
||||||
final boolean newMapping = "true".equals(request.getParameter("new"));
|
|
||||||
final boolean mobile = "true".equals(request.getParameter("mobile"));
|
|
||||||
final String address = request.getParameter("email-address");
|
|
||||||
final String description = request.getParameter("description");
|
|
||||||
final String target = request.getParameter("target");
|
|
||||||
final boolean disabled = "true".equalsIgnoreCase(request.getParameter("disabled"));
|
|
||||||
if (newMapping) {
|
|
||||||
if (Util.addressExists(address)) {
|
|
||||||
response.sendError(404, "Address already exists");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (address == null || address.length() == 0) {
|
|
||||||
response.sendError(400, "Please supply an address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (address.indexOf('@') < 0) {
|
|
||||||
response.sendError(400, "Not a valid email address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Date date = new Date();
|
|
||||||
final Mapping mapping = new Mapping(address, target, description, date, disabled);
|
|
||||||
Util.addMapping(mapping);
|
|
||||||
Util.addHistory(mapping);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!Util.addressExists(address)) {
|
|
||||||
response.sendError(404, "Address does not exist");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final String dateString = request.getParameter("date");
|
|
||||||
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
|
||||||
Date date;
|
|
||||||
try {
|
|
||||||
date = dateString != null && dateString.trim().length() > 0
|
|
||||||
? df.parse(dateString)
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
catch (final ParseException e1) {
|
|
||||||
date = null;
|
|
||||||
}
|
|
||||||
final Mapping mapping = new Mapping(address, target, description, date, disabled);
|
|
||||||
Util.updateMapping(mapping);
|
|
||||||
Util.addHistory(mapping);
|
|
||||||
}
|
|
||||||
Util.SaveMappingsResult result;
|
|
||||||
try {
|
|
||||||
result = Util.saveMappings();
|
|
||||||
}
|
|
||||||
catch (final InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
if (result != null && result.getExitValue() != 0) {
|
|
||||||
final PrintWriter out = response.getWriter();
|
|
||||||
out.println("saveMappings returned " + result.getExitValue());
|
|
||||||
out.println("Error:");
|
|
||||||
out.println(result.getError());
|
|
||||||
out.println("Output:");
|
|
||||||
out.println(result.getOutput());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
response.sendRedirect(mobile ? "mapping.jsp?address=" + address : "index.jsp");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (final Exception e) {
|
|
||||||
throw new ServletException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
public class ResetSession extends HttpServlet {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
Util.resetSession(req.getSession());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
public class Server {
|
|
||||||
private final String serverName;
|
|
||||||
|
|
||||||
public Server(final String serverName) {
|
|
||||||
this.serverName = serverName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getServerName() {
|
|
||||||
return serverName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
public class Session {
|
|
||||||
private User user;
|
|
||||||
|
|
||||||
public User getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUser(final User user) {
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class Target {
|
|
||||||
private final int id;
|
|
||||||
private final String address;
|
|
||||||
private final String description;
|
|
||||||
private final Date created;
|
|
||||||
|
|
||||||
public Target(final int id, final String address, final String description,
|
|
||||||
final Date created) {
|
|
||||||
if (address == null) {
|
|
||||||
throw new IllegalArgumentException("address may not be null");
|
|
||||||
}
|
|
||||||
if (created == null) {
|
|
||||||
throw new IllegalArgumentException("created may not be null");
|
|
||||||
}
|
|
||||||
this.id = id;
|
|
||||||
this.address = address;
|
|
||||||
this.description = description;
|
|
||||||
this.created = created;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getCreated() {
|
|
||||||
return created;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (!(obj instanceof Target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final Target that = (Target) obj;
|
|
||||||
return this.id == that.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return super.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
|
|
||||||
public class User {
|
|
||||||
private final int id;
|
|
||||||
private final String name;
|
|
||||||
private final String displayName;
|
|
||||||
private final boolean canWrite;
|
|
||||||
|
|
||||||
public User(final int id, final String name, final String displayName, final boolean canWrite) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.canWrite = canWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayName() {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCanWrite() {
|
|
||||||
return canWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Target> getValidTargets() throws SQLException, NamingException {
|
|
||||||
if ("elephant".equals(name)) {
|
|
||||||
return null; // all targets are valid
|
|
||||||
}
|
|
||||||
return Util.getTargetsForUser(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,697 +0,0 @@
|
||||||
package com.stephenschafer.email;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.sql.Types;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
|
|
||||||
public class Util {
|
|
||||||
private Util() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void resetSession(final HttpSession session) {
|
|
||||||
session.removeAttribute("target-list");
|
|
||||||
session.removeAttribute("domain-list");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateSession(final HttpSession session)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
if (session.getAttribute("target-list") != null) {
|
|
||||||
Logger.log("Util.updateSession session is already up to date");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final User user = identify(session);
|
|
||||||
final Set<String> targetSet = new HashSet<>();
|
|
||||||
final Set<String> domainSet = new HashSet<>();
|
|
||||||
for (final Mapping mapping : GlobalCache.INSTANCE.getMappings()) {
|
|
||||||
if (mapping.qualifies(user)) {
|
|
||||||
targetSet.add(mapping.getTarget());
|
|
||||||
}
|
|
||||||
if (mapping.qualifies(user)) {
|
|
||||||
final String domain = mapping.getDomain();
|
|
||||||
if (domain != null) {
|
|
||||||
domainSet.add(domain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Logger.log("Util.updateSession targets: " + targetSet.size());
|
|
||||||
Logger.log("Util.updateSession domains: " + domainSet.size());
|
|
||||||
final List<String> targetList = new ArrayList<>(targetSet);
|
|
||||||
Collections.sort(targetList);
|
|
||||||
final List<String> domainList = new ArrayList<>(domainSet);
|
|
||||||
Collections.sort(domainList);
|
|
||||||
session.setAttribute("target-list", targetList);
|
|
||||||
session.setAttribute("domain-list", domainList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User register(final String username, final String password,
|
|
||||||
final String displayName, final boolean canWrite)
|
|
||||||
throws NoSuchAlgorithmException, SQLException, NamingException {
|
|
||||||
final SecureRandom random = new SecureRandom();
|
|
||||||
final byte[] salt = new byte[64];
|
|
||||||
random.nextBytes(salt);
|
|
||||||
final byte[] passwordBytes = password.getBytes();
|
|
||||||
final byte[] saltPlusPassword = new byte[salt.length + passwordBytes.length];
|
|
||||||
int i = 0;
|
|
||||||
for (final byte b : salt) {
|
|
||||||
saltPlusPassword[i++] = b;
|
|
||||||
}
|
|
||||||
for (final byte b : passwordBytes) {
|
|
||||||
saltPlusPassword[i++] = b;
|
|
||||||
}
|
|
||||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
||||||
md.update(saltPlusPassword);
|
|
||||||
final byte[] digest = md.digest();
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "insert into user"
|
|
||||||
+ " (username, password, salt, display_name, can_write)"
|
|
||||||
+ " values (?, ?, ?, ?, ?)";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql,
|
|
||||||
PreparedStatement.RETURN_GENERATED_KEYS);
|
|
||||||
try {
|
|
||||||
statement.setString(1, username);
|
|
||||||
statement.setBytes(2, digest);
|
|
||||||
statement.setBytes(3, salt);
|
|
||||||
statement.setString(4, displayName);
|
|
||||||
statement.setBoolean(5, canWrite);
|
|
||||||
final int rowCount = statement.executeUpdate();
|
|
||||||
if (rowCount == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final ResultSet resultSet = statement.getGeneratedKeys();
|
|
||||||
try {
|
|
||||||
if (resultSet.next()) {
|
|
||||||
final int id = resultSet.getInt(1);
|
|
||||||
return new User(id, username, displayName, canWrite);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void changePassword(final int id, final String password)
|
|
||||||
throws NoSuchAlgorithmException, SQLException, NamingException {
|
|
||||||
final SecureRandom random = new SecureRandom();
|
|
||||||
final byte[] salt = new byte[64];
|
|
||||||
random.nextBytes(salt);
|
|
||||||
final byte[] passwordBytes = password.getBytes();
|
|
||||||
final byte[] saltPlusPassword = new byte[salt.length + passwordBytes.length];
|
|
||||||
int i = 0;
|
|
||||||
for (final byte b : salt) {
|
|
||||||
saltPlusPassword[i++] = b;
|
|
||||||
}
|
|
||||||
for (final byte b : passwordBytes) {
|
|
||||||
saltPlusPassword[i++] = b;
|
|
||||||
}
|
|
||||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
||||||
md.update(saltPlusPassword);
|
|
||||||
final byte[] digest = md.digest();
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "update user set" + " password = ?, salt = ?" + " where id = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
statement.setBytes(1, digest);
|
|
||||||
statement.setBytes(2, salt);
|
|
||||||
statement.executeUpdate();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User login(final String username, final String password)
|
|
||||||
throws SQLException, NamingException, NoSuchAlgorithmException {
|
|
||||||
Logger.log("Util.login " + username);
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "select id, password, salt, display_name, can_write, username"
|
|
||||||
+ " from user where username = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
statement.setString(1, username);
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
if (!resultSet.next()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int i = 0;
|
|
||||||
final int id = resultSet.getInt(++i);
|
|
||||||
final byte[] passwordDigestBytes = resultSet.getBytes(++i);
|
|
||||||
final byte[] salt = resultSet.getBytes(++i);
|
|
||||||
final String displayName = resultSet.getString(++i);
|
|
||||||
final boolean canWrite = resultSet.getBoolean(++i);
|
|
||||||
final String actualUsername = resultSet.getString(++i);
|
|
||||||
final byte[] passwordBytes = password.getBytes();
|
|
||||||
final byte[] saltPlusPassword = new byte[salt.length + passwordBytes.length];
|
|
||||||
i = 0;
|
|
||||||
for (final byte b : salt) {
|
|
||||||
saltPlusPassword[i++] = b;
|
|
||||||
}
|
|
||||||
for (final byte b : passwordBytes) {
|
|
||||||
saltPlusPassword[i++] = b;
|
|
||||||
}
|
|
||||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
||||||
md.update(saltPlusPassword);
|
|
||||||
final byte[] digest = md.digest();
|
|
||||||
if (Arrays.equals(passwordDigestBytes, digest)) {
|
|
||||||
Logger.log(username + " successfully logged in");
|
|
||||||
return new User(id, actualUsername, displayName, canWrite);
|
|
||||||
}
|
|
||||||
Logger.log(username + " failed to log in");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User login(final String username)
|
|
||||||
throws SQLException, NamingException, NoSuchAlgorithmException {
|
|
||||||
Logger.log("Util.login " + username);
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "select id, display_name, can_write, username"
|
|
||||||
+ " from user where username = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
statement.setString(1, username);
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
if (!resultSet.next()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int i = 0;
|
|
||||||
final int id = resultSet.getInt(++i);
|
|
||||||
final String displayName = resultSet.getString(++i);
|
|
||||||
final boolean canWrite = resultSet.getBoolean(++i);
|
|
||||||
final String actualUsername = resultSet.getString(++i);
|
|
||||||
return new User(id, actualUsername, displayName, canWrite);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int getMappingsCountFromDb() throws SQLException, NamingException {
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "select count(*) from mapping";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
if (resultSet.next()) {
|
|
||||||
return resultSet.getInt(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<String> getAliasesFromDb(final String target) throws SQLException, NamingException {
|
|
||||||
final List<String> list = new ArrayList<>();
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "select distinct m.address" + " from mapping m"
|
|
||||||
+ " inner join target t on t.id = m.target_id" + " where t.address = ?"
|
|
||||||
+ " order by 1";
|
|
||||||
Logger.log(sql);
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
Logger.log("target = " + target);
|
|
||||||
statement.setString(1, target);
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
while (resultSet.next()) {
|
|
||||||
list.add(resultSet.getString(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
Logger.log(String.format("returning %d aliases", Integer.valueOf(list.size())));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<Mapping> getMappingsFromDb() throws SQLException, NamingException {
|
|
||||||
final List<Mapping> list = new ArrayList<>();
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "select m.address, t.address, m.description, m.created, m.disabled"
|
|
||||||
+ " from mapping m" + " inner join target t on t.id = m.target_id" + " order by 1";
|
|
||||||
Logger.log(sql);
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
while (resultSet.next()) {
|
|
||||||
int i = 0;
|
|
||||||
final String address = resultSet.getString(++i);
|
|
||||||
final String target = resultSet.getString(++i);
|
|
||||||
final String description = resultSet.getString(++i);
|
|
||||||
final Timestamp created = resultSet.getTimestamp(++i);
|
|
||||||
final boolean disabled = resultSet.getBoolean(++i);
|
|
||||||
final Mapping mapping = new Mapping(address, target, description, created,
|
|
||||||
disabled);
|
|
||||||
list.add(mapping);
|
|
||||||
Logger.debugLog(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
Logger.log(String.format("returning %d mappings", Integer.valueOf(list.size())));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Mapping getMappingFromDb(final String address) throws SQLException, NamingException {
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final String sql = "select t.address, m.description, m.created, m.disabled"
|
|
||||||
+ " from mapping m" + " inner join target t on t.id = m.target_id"
|
|
||||||
+ " where m.address = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
statement.setString(1, address);
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
if (resultSet.next()) {
|
|
||||||
int i = 0;
|
|
||||||
final String target = resultSet.getString(++i);
|
|
||||||
final String description = resultSet.getString(++i);
|
|
||||||
final Timestamp created = resultSet.getTimestamp(++i);
|
|
||||||
final boolean disabled = resultSet.getBoolean(++i);
|
|
||||||
return new Mapping(address, target, description, created, disabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Target getTarget(final Connection connection, final String address)
|
|
||||||
throws SQLException {
|
|
||||||
if (address == null) {
|
|
||||||
throw new IllegalArgumentException("address may not be null");
|
|
||||||
}
|
|
||||||
Target target = null;
|
|
||||||
boolean targetFound = false;
|
|
||||||
try {
|
|
||||||
target = getTargetFromDb(connection, address);
|
|
||||||
targetFound = true;
|
|
||||||
}
|
|
||||||
catch (final TargetNotFoundException e) {
|
|
||||||
}
|
|
||||||
if (!targetFound) {
|
|
||||||
target = addTargetToDb(connection, address, "");
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addMappingToDb(final Mapping mapping) throws SQLException, NamingException {
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final Target target = getTarget(connection, mapping.getTarget());
|
|
||||||
final String sql = "insert into mapping"
|
|
||||||
+ " (address, target_id, description, created, disabled)"
|
|
||||||
+ " values (?, ?, ?, ?, ?)";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql,
|
|
||||||
PreparedStatement.RETURN_GENERATED_KEYS);
|
|
||||||
try {
|
|
||||||
int i = 0;
|
|
||||||
statement.setString(++i, mapping.getAddress());
|
|
||||||
statement.setInt(++i, target.getId());
|
|
||||||
statement.setString(++i, mapping.getDescription());
|
|
||||||
final Date created = mapping.getDate();
|
|
||||||
if (created == null) {
|
|
||||||
statement.setNull(++i, Types.TIMESTAMP);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
statement.setTimestamp(++i, new Timestamp(created.getTime()));
|
|
||||||
}
|
|
||||||
statement.setBoolean(++i, mapping.isDisabled());
|
|
||||||
statement.executeUpdate();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateMappingToDb(final Mapping mapping) throws SQLException, NamingException {
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final Target target = getTarget(connection, mapping.getTarget());
|
|
||||||
final String sql = "update mapping set"
|
|
||||||
+ " target_id = ?, description = ?, created = ?, disabled = ?"
|
|
||||||
+ " where address = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql,
|
|
||||||
PreparedStatement.RETURN_GENERATED_KEYS);
|
|
||||||
try {
|
|
||||||
int i = 0;
|
|
||||||
statement.setInt(++i, target.getId());
|
|
||||||
statement.setString(++i, mapping.getDescription());
|
|
||||||
final Date created = mapping.getDate();
|
|
||||||
if (created == null) {
|
|
||||||
statement.setNull(++i, Types.TIMESTAMP);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
statement.setTimestamp(++i, new Timestamp(created.getTime()));
|
|
||||||
}
|
|
||||||
statement.setBoolean(++i, mapping.isDisabled());
|
|
||||||
statement.setString(++i, mapping.getAddress());
|
|
||||||
statement.executeUpdate();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int addHistoryToDb(final Mapping mapping) throws SQLException, NamingException {
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
final Target target = getTarget(connection, mapping.getTarget());
|
|
||||||
final String sql = "insert into history"
|
|
||||||
+ " (address, target_id, description, created, changed, disabled)"
|
|
||||||
+ " values (?, ?, ?, ?, ?, ?)";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql,
|
|
||||||
PreparedStatement.RETURN_GENERATED_KEYS);
|
|
||||||
try {
|
|
||||||
int i = 0;
|
|
||||||
statement.setString(++i, mapping.getAddress());
|
|
||||||
statement.setInt(++i, target.getId());
|
|
||||||
statement.setString(++i, mapping.getDescription());
|
|
||||||
final Date created = mapping.getDate();
|
|
||||||
if (created == null) {
|
|
||||||
statement.setNull(++i, Types.TIMESTAMP);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
statement.setTimestamp(++i, new Timestamp(created.getTime()));
|
|
||||||
}
|
|
||||||
statement.setTimestamp(++i, new Timestamp(System.currentTimeMillis()));
|
|
||||||
statement.setBoolean(++i, mapping.isDisabled());
|
|
||||||
final int rowCount = statement.executeUpdate();
|
|
||||||
if (rowCount == 0) {
|
|
||||||
throw new RuntimeException("Failed to insert new mapping");
|
|
||||||
}
|
|
||||||
final ResultSet resultSet = statement.getGeneratedKeys();
|
|
||||||
try {
|
|
||||||
if (resultSet.next()) {
|
|
||||||
return resultSet.getInt(1);
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Failed to get new mapping id");
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TargetNotFoundException extends Exception {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Target getTargetFromDb(final Connection connection, final String address)
|
|
||||||
throws SQLException, TargetNotFoundException {
|
|
||||||
if (address == null) {
|
|
||||||
throw new IllegalArgumentException("address may not be null");
|
|
||||||
}
|
|
||||||
final String sql = "select id, description, created from target where address = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
statement.setString(1, address);
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
if (resultSet.next()) {
|
|
||||||
final int id = resultSet.getInt(1);
|
|
||||||
final String description = resultSet.getString(2);
|
|
||||||
final Timestamp created = resultSet.getTimestamp(3);
|
|
||||||
return new Target(id, address, description, created);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
throw new TargetNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Target addTargetToDb(final Connection connection, final String address,
|
|
||||||
final String description) throws SQLException {
|
|
||||||
if (address == null) {
|
|
||||||
throw new IllegalArgumentException("address may not be null");
|
|
||||||
}
|
|
||||||
final Timestamp created = new Timestamp(System.currentTimeMillis());
|
|
||||||
final String sql = "insert into target (address, description, created)"
|
|
||||||
+ " values (?, ?, ?)";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql,
|
|
||||||
PreparedStatement.RETURN_GENERATED_KEYS);
|
|
||||||
try {
|
|
||||||
int i = 0;
|
|
||||||
statement.setString(++i, address);
|
|
||||||
statement.setString(++i, description);
|
|
||||||
statement.setTimestamp(++i, created);
|
|
||||||
final int rowCount = statement.executeUpdate();
|
|
||||||
if (rowCount == 0) {
|
|
||||||
throw new RuntimeException("Failed to insert new target");
|
|
||||||
}
|
|
||||||
final ResultSet resultSet = statement.getGeneratedKeys();
|
|
||||||
try {
|
|
||||||
if (resultSet.next()) {
|
|
||||||
final int id = resultSet.getInt(1);
|
|
||||||
return new Target(id, address, description, created);
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Failed to get new target id");
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Target> getTargetsForUser(final User user)
|
|
||||||
throws SQLException, NamingException {
|
|
||||||
final Connection connection = Configuration.INSTANCE.getConnection();
|
|
||||||
try {
|
|
||||||
return getTargetsForUser(connection, user);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
connection.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Target> getTargetsForUser(final Connection connection, final User user)
|
|
||||||
throws SQLException {
|
|
||||||
final List<Target> list = new ArrayList<>();
|
|
||||||
final String sql = "select t.id, t.address, t.description, t.created"
|
|
||||||
+ " from target t inner join user_target ut on t.id = ut.target_id"
|
|
||||||
+ " where ut.user_id = ?";
|
|
||||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
|
||||||
try {
|
|
||||||
statement.setInt(1, user.getId());
|
|
||||||
final ResultSet resultSet = statement.executeQuery();
|
|
||||||
try {
|
|
||||||
while (resultSet.next()) {
|
|
||||||
int i = 0;
|
|
||||||
final int id = resultSet.getInt(++i);
|
|
||||||
final String address = resultSet.getString(++i);
|
|
||||||
final String description = resultSet.getString(++i);
|
|
||||||
final Date created = resultSet.getDate(++i);
|
|
||||||
final Target target = new Target(id, address, description, created);
|
|
||||||
list.add(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logout(final HttpSession session) {
|
|
||||||
if (session == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
session.removeAttribute("email-session");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User identify(final HttpSession session) {
|
|
||||||
if (session == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final Object object = session.getAttribute("email-session");
|
|
||||||
if (object == null || !(object instanceof Session)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final Session appSession = (Session) object;
|
|
||||||
return appSession.getUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface SaveMappingsResult {
|
|
||||||
int getExitValue();
|
|
||||||
|
|
||||||
String getOutput();
|
|
||||||
|
|
||||||
String getError();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String streamToString(final InputStream inputStream) throws IOException {
|
|
||||||
final Reader reader = new InputStreamReader(inputStream);
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
final char[] buffer = new char[0x1000];
|
|
||||||
int charsRead = reader.read(buffer);
|
|
||||||
while (charsRead >= 0) {
|
|
||||||
sb.append(buffer, 0, charsRead);
|
|
||||||
charsRead = reader.read(buffer);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean addressExists(final String address)
|
|
||||||
throws SQLException, NamingException, IOException {
|
|
||||||
return GlobalCache.INSTANCE.addressExists(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addMapping(final Mapping mapping)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
GlobalCache.INSTANCE.addMapping(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateMapping(final Mapping mapping)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
GlobalCache.INSTANCE.updateMapping(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addHistory(final Mapping mapping)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
GlobalCache.INSTANCE.addHistory(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Mapping getMapping(final String address)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
return GlobalCache.INSTANCE.getMapping(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SaveMappingsResult saveMappings()
|
|
||||||
throws IOException, InterruptedException, SQLException, NamingException {
|
|
||||||
return GlobalCache.INSTANCE.writeVirtualFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Mapping> getMappings() throws IOException, SQLException, NamingException {
|
|
||||||
return GlobalCache.INSTANCE.getMappings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> getAliases(final String target)
|
|
||||||
throws IOException, SQLException, NamingException {
|
|
||||||
return GlobalCache.INSTANCE.getAliases(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue