src/main/java/com/gitblit/FederationClient.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/authority/GitblitAuthority.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/manager/GitblitManager.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/manager/INotificationManager.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/manager/NotificationManager.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/models/Mailing.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/service/MailService.java | ●●●●● patch | view | raw | blame | history | |
src/test/java/com/gitblit/tests/MailTest.java | ●●●●● patch | view | raw | blame | history |
src/main/java/com/gitblit/FederationClient.java
@@ -32,6 +32,7 @@ import com.gitblit.manager.RuntimeManager; import com.gitblit.manager.UserManager; import com.gitblit.models.FederationModel; import com.gitblit.models.Mailing; import com.gitblit.service.FederationPullService; import com.gitblit.utils.FederationUtils; import com.gitblit.utils.StringUtils; @@ -178,23 +179,11 @@ } @Override public void sendMail(String subject, String message, String... toAddresses) { } @Override public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) { } @Override public void sendHtmlMail(String subject, String message, String... toAddresses) { } @Override public void sendHtmlMail(String from, String subject, String message, Collection<String> toAddresses) { } @Override public void sendHtmlMail(String from, String subject, String message, String... toAddresses) { public void send(Mailing mailing) { } } } src/main/java/com/gitblit/authority/GitblitAuthority.java
@@ -43,7 +43,6 @@ import java.security.cert.X509Certificate; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -51,12 +50,7 @@ import java.util.List; import java.util.Map; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.Message; import javax.mail.Multipart; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import javax.swing.ImageIcon; import javax.swing.InputVerifier; import javax.swing.JButton; @@ -93,6 +87,7 @@ import com.gitblit.Keys; import com.gitblit.client.HeaderPanel; import com.gitblit.client.Translation; import com.gitblit.models.Mailing; import com.gitblit.models.UserModel; import com.gitblit.service.MailService; import com.gitblit.utils.ArrayUtils; @@ -854,27 +849,17 @@ // send email try { if (mail.isReady()) { Message message = mail.createMessage(Arrays.asList(user.emailAddress)); message.setSubject("Your Gitblit client certificate for " + metadata.serverHostname); // body of email Mailing mailing = Mailing.newPlain(); mailing.subject = "Your Gitblit client certificate for " + metadata.serverHostname; mailing.setRecipients(user.emailAddress); String body = X509Utils.processTemplate(new File(folder, X509Utils.CERTS + File.separator + "mail.tmpl"), metadata); if (StringUtils.isEmpty(body)) { body = MessageFormat.format("Hi {0}\n\nHere is your client certificate bundle.\nInside the zip file are installation instructions.", user.getDisplayName()); } Multipart mp = new MimeMultipart(); MimeBodyPart messagePart = new MimeBodyPart(); messagePart.setText(body); mp.addBodyPart(messagePart); mailing.content = body; mailing.addAttachment(zip); // attach zip MimeBodyPart filePart = new MimeBodyPart(); FileDataSource fds = new FileDataSource(zip); filePart.setDataHandler(new DataHandler(fds)); filePart.setFileName(fds.getName()); mp.addBodyPart(filePart); message.setContent(mp); Message message = mail.createMessage(mailing); mail.sendNow(message); return true; src/main/java/com/gitblit/manager/GitblitManager.java
@@ -50,6 +50,7 @@ import com.gitblit.models.FederationSet; import com.gitblit.models.ForkModel; import com.gitblit.models.GitClientApplication; import com.gitblit.models.Mailing; import com.gitblit.models.Metric; import com.gitblit.models.ProjectModel; import com.gitblit.models.RegistrantAccessPermission; @@ -584,28 +585,13 @@ } @Override public void sendMail(String subject, String message, String... toAddresses) { notificationManager.sendMail(subject, message, toAddresses); } @Override public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) { notificationManager.sendHtmlMail(subject, message, toAddresses); } @Override public void sendHtmlMail(String subject, String message, String... toAddresses) { notificationManager.sendHtmlMail(subject, message, toAddresses); } @Override public void sendHtmlMail(String from, String subject, String message, Collection<String> toAddresses) { notificationManager.sendHtmlMail(from, subject, message, toAddresses); } @Override public void sendHtmlMail(String from, String subject, String message, String... toAddresses) { notificationManager.sendHtmlMail(from, subject, message, toAddresses); public void send(Mailing mail) { notificationManager.send(mail); } /* src/main/java/com/gitblit/manager/INotificationManager.java
@@ -17,6 +17,8 @@ import java.util.Collection; import com.gitblit.models.Mailing; public interface INotificationManager extends IManager { /** @@ -43,44 +45,14 @@ * @param message * @param toAddresses */ void sendMail(String subject, String message, String... toAddresses); /** * Notify users by email of something. * * @param subject * @param message * @param toAddresses */ void sendHtmlMail(String subject, String message, Collection<String> toAddresses); /** * Notify users by email of something. * * @param subject * @param message * @param toAddresses * @param mailing * @return the mail message object */ void sendHtmlMail(String subject, String message, String... toAddresses); /** * Notify users by email of something. * * @param from * @param subject * @param message * @param toAddresses */ void sendHtmlMail(String from, String subject, String message, Collection<String> toAddresses); /** * Notify users by email of something. * * @param from * @param subject * @param message * @param toAddresses */ void sendHtmlMail(String from, String subject, String message, String... toAddresses); void send(Mailing mailing); } src/main/java/com/gitblit/manager/NotificationManager.java
@@ -15,23 +15,19 @@ */ package com.gitblit.manager; import java.text.MessageFormat; import java.util.Collection; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.models.Mailing; import com.gitblit.service.MailService; /** @@ -50,19 +46,19 @@ private final IStoredSettings settings; private final MailService mailExecutor; private final MailService mailService; public NotificationManager(IStoredSettings settings) { this.settings = settings; this.mailExecutor = new MailService(settings); this.mailService = new MailService(settings); } @Override public NotificationManager start() { if (mailExecutor.isReady()) { if (mailService.isReady()) { int period = 2; logger.info("Mail service will process the queue every {} minutes.", period); scheduledExecutor.scheduleAtFixedRate(mailExecutor, 1, period, TimeUnit.MINUTES); scheduledExecutor.scheduleAtFixedRate(mailService, 1, period, TimeUnit.MINUTES); } else { logger.warn("Mail service disabled."); } @@ -83,8 +79,11 @@ */ @Override public void sendMailToAdministrators(String subject, String message) { List<String> toAddresses = settings.getStrings(Keys.mail.adminAddresses); sendMail(subject, message, toAddresses); Mailing mail = Mailing.newPlain(); mail.subject = subject; mail.content = message; mail.setRecipients(settings.getStrings(Keys.mail.adminAddresses)); send(mail); } /** @@ -96,41 +95,11 @@ */ @Override public void sendMail(String subject, String message, Collection<String> toAddresses) { this.sendMail(subject, message, toAddresses.toArray(new String[0])); } /** * Notify users by email of something. * * @param subject * @param message * @param toAddresses */ @Override public void sendMail(String subject, String message, String... toAddresses) { if (toAddresses == null || toAddresses.length == 0) { logger.debug(MessageFormat.format("Dropping message {0} because there are no recipients", subject)); return; } try { Message mail = mailExecutor.createMessage(toAddresses); if (mail != null) { mail.setSubject(subject); MimeBodyPart messagePart = new MimeBodyPart(); messagePart.setText(message, "utf-8"); messagePart.setHeader("Content-Type", "text/plain; charset=\"utf-8\""); messagePart.setHeader("Content-Transfer-Encoding", "quoted-printable"); MimeMultipart multiPart = new MimeMultipart(); multiPart.addBodyPart(messagePart); mail.setContent(multiPart); mailExecutor.queue(mail); } } catch (MessagingException e) { logger.error("Messaging error", e); } Mailing mail = Mailing.newPlain(); mail.subject = subject; mail.content = message; mail.setRecipients(toAddresses); send(mail); } /** @@ -142,66 +111,26 @@ */ @Override public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) { this.sendHtmlMail(null, subject, message, toAddresses.toArray(new String[0])); Mailing mail = Mailing.newHtml(); mail.content = message; mail.setRecipients(toAddresses); send(mail); } /** * Notify users by email of something. * * @param from * @param subject * @param message * @param toAddresses * @param mailing */ @Override public void sendHtmlMail(String from, String subject, String message, Collection<String> toAddresses) { this.sendHtmlMail(from, subject, message, toAddresses.toArray(new String[0])); } /** * Notify users by email of something. * * @param subject * @param message * @param toAddresses */ @Override public void sendHtmlMail(String subject, String message, String... toAddresses) { this.sendHtmlMail(null, message, toAddresses); } /** * Notify users by email of something. * * @param from * @param subject * @param message * @param toAddresses */ @Override public void sendHtmlMail(String from, String subject, String message, String... toAddresses) { if (toAddresses == null || toAddresses.length == 0) { logger.debug("Dropping message {} because there are no recipients", subject); public void send(Mailing mailing) { if (!mailing.hasRecipients()) { logger.debug("Dropping message {} because there are no recipients", mailing.subject); return; } try { Message mail = mailExecutor.createMessage(from, toAddresses); if (mail != null) { mail.setSubject(subject); MimeBodyPart messagePart = new MimeBodyPart(); messagePart.setText(message, "utf-8"); messagePart.setHeader("Content-Type", "text/html; charset=\"utf-8\""); messagePart.setHeader("Content-Transfer-Encoding", "quoted-printable"); MimeMultipart multiPart = new MimeMultipart(); multiPart.addBodyPart(messagePart); mail.setContent(multiPart); mailExecutor.queue(mail); } } catch (MessagingException e) { logger.error("Messaging error", e); Message msg = mailService.createMessage(mailing); if (msg != null) { mailService.queue(msg); } } src/main/java/com/gitblit/models/Mailing.java
New file @@ -0,0 +1,111 @@ /* * Copyright 2014 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.models; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * Encapsulates an email notification. * * @author James Moger * */ public class Mailing { public enum Type { plain, html } public final Type type; public final Set<String> toAddresses; public final Set<String> ccAddresses; public final List<File> attachments; public String from; public String subject; public String content; public String id; public static Mailing newHtml() { return new Mailing(Type.html); } public static Mailing newPlain() { return new Mailing(Type.plain); } private Mailing(Type type) { this.type = type; this.toAddresses = new TreeSet<String>(); this.ccAddresses = new TreeSet<String>(); this.attachments = new ArrayList<File>(); } public boolean hasRecipients() { return toAddresses.size() > 0; } public void setRecipients(String... addrs) { setRecipients(Arrays.asList(addrs)); } public void setRecipients(Collection<String> addrs) { toAddresses.clear(); for (String addr : addrs) { toAddresses.add(addr.toLowerCase()); } cleanup(); } public boolean hasCCs() { return ccAddresses.size() > 0; } public void setCCs(String... addrs) { setCCs(Arrays.asList(addrs)); } public void setCCs(Collection<String> addrs) { ccAddresses.clear(); for (String addr : addrs) { ccAddresses.add(addr.toLowerCase()); } cleanup(); } private void cleanup() { ccAddresses.removeAll(toAddresses); } public boolean hasAttachments() { return attachments.size() > 0; } public void addAttachment(File file) { attachments.add(file); } @Override public String toString() { return subject + "\n\n" + content; } } src/main/java/com/gitblit/service/MailService.java
@@ -15,30 +15,35 @@ */ package com.gitblit.service; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Queue; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.regex.Pattern; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.models.Mailing; import com.gitblit.utils.StringUtils; /** @@ -117,74 +122,108 @@ /** * Create a message. * * @param toAddresses * @param mailing * @return a message */ public Message createMessage(String... toAddresses) { return createMessage(null, Arrays.asList(toAddresses)); public Message createMessage(Mailing mailing) { if (mailing.subject == null) { mailing.subject = ""; } /** * Create a message. * * @param toAddresses * @return a message */ public Message createMessage(List<String> toAddresses) { return createMessage(null, toAddresses); if (mailing.content == null) { mailing.content = ""; } /** * Create a message. * * @param fromDisplayName * @param toAddresses * @return a message */ public Message createMessage(String fromDisplayName, String... toAddresses) { return createMessage(fromDisplayName, Arrays.asList(toAddresses)); } /** * Create a message. * * @param fromDisplayName * @param toAddresses * @return a message */ public Message createMessage(String fromDisplayName, List<String> toAddresses) { MimeMessage message = new MimeMessage(session); Message message = new MailMessageImpl(session, mailing.id); try { String fromAddress = settings.getString(Keys.mail.fromAddress, null); if (StringUtils.isEmpty(fromAddress)) { fromAddress = "gitblit@gitblit.com"; } InternetAddress from = new InternetAddress(fromAddress, fromDisplayName == null ? "Gitblit" : fromDisplayName); InternetAddress from = new InternetAddress(fromAddress, mailing.from == null ? "Gitblit" : mailing.from); message.setFrom(from); // determine unique set of addresses Set<String> uniques = new HashSet<String>(); for (String address : toAddresses) { uniques.add(address.toLowerCase()); } Pattern validEmail = Pattern .compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"); List<InternetAddress> tos = new ArrayList<InternetAddress>(); for (String address : uniques) { // validate & add TO recipients List<InternetAddress> to = new ArrayList<InternetAddress>(); for (String address : mailing.toAddresses) { if (StringUtils.isEmpty(address)) { continue; } if (validEmail.matcher(address).find()) { try { tos.add(new InternetAddress(address)); to.add(new InternetAddress(address)); } catch (Throwable t) { } } } // validate & add CC recipients List<InternetAddress> cc = new ArrayList<InternetAddress>(); for (String address : mailing.ccAddresses) { if (StringUtils.isEmpty(address)) { continue; } if (validEmail.matcher(address).find()) { try { cc.add(new InternetAddress(address)); } catch (Throwable t) { } } } if (settings.getBoolean(Keys.web.showEmailAddresses, true)) { // full disclosure of recipients if (to.size() > 0) { message.setRecipients(Message.RecipientType.TO, to.toArray(new InternetAddress[to.size()])); } if (cc.size() > 0) { message.setRecipients(Message.RecipientType.CC, cc.toArray(new InternetAddress[cc.size()])); } } else { // everyone is bcc'd List<InternetAddress> bcc = new ArrayList<InternetAddress>(); bcc.addAll(to); bcc.addAll(cc); message.setRecipients(Message.RecipientType.BCC, tos.toArray(new InternetAddress[tos.size()])); bcc.toArray(new InternetAddress[bcc.size()])); } message.setSentDate(new Date()); message.setSubject(mailing.subject); MimeBodyPart messagePart = new MimeBodyPart(); messagePart.setText(mailing.content, "utf-8"); //messagePart.setHeader("Content-Transfer-Encoding", "quoted-printable"); if (Mailing.Type.html == mailing.type) { messagePart.setHeader("Content-Type", "text/html; charset=\"utf-8\""); } else { messagePart.setHeader("Content-Type", "text/plain; charset=\"utf-8\""); } MimeMultipart multiPart = new MimeMultipart(); multiPart.addBodyPart(messagePart); // handle attachments if (mailing.hasAttachments()) { for (File file : mailing.attachments) { if (file.exists()) { MimeBodyPart filePart = new MimeBodyPart(); FileDataSource fds = new FileDataSource(file); filePart.setDataHandler(new DataHandler(fds)); filePart.setFileName(fds.getName()); multiPart.addBodyPart(filePart); } } } message.setContent(multiPart); } catch (Exception e) { logger.error("Failed to properly create message", e); } @@ -247,4 +286,26 @@ public void sendNow(Message message) throws Exception { Transport.send(message); } private static class MailMessageImpl extends MimeMessage { final String id; MailMessageImpl(Session session, String id) { super(session); this.id = id; } @Override protected void updateMessageID() throws MessagingException { if (!StringUtils.isEmpty(id)) { String hostname = "gitblit.com"; String refid = "<" + id + "@" + hostname + ">"; String mid = "<" + UUID.randomUUID().toString() + "@" + hostname + ">"; setHeader("References", refid); setHeader("In-Reply-To", refid); setHeader("Message-Id", mid); } } } } src/test/java/com/gitblit/tests/MailTest.java
@@ -21,6 +21,7 @@ import com.gitblit.FileSettings; import com.gitblit.Keys; import com.gitblit.models.Mailing; import com.gitblit.service.MailService; public class MailTest extends GitblitUnitTest { @@ -29,7 +30,9 @@ public void testSendMail() throws Exception { FileSettings settings = new FileSettings("mailtest.properties"); MailService mail = new MailService(settings); Message message = mail.createMessage(settings.getStrings(Keys.mail.adminAddresses)); Mailing mailing = Mailing.newPlain(); mailing.setRecipients(settings.getStrings(Keys.mail.adminAddresses)); Message message = mail.createMessage(mailing); message.setSubject("Test"); message.setText("Lägger till andra stycket i ny fil. UTF-8 encoded"); mail.queue(message);