package com.baselet.gui;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
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 javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baselet.control.config.Config;
import com.baselet.control.config.ConfigMail;
import com.baselet.control.constants.Constants;
import com.baselet.control.enums.Program;
import com.baselet.control.util.Path;
import com.baselet.diagram.CurrentDiagram;
import com.baselet.diagram.Notifier;
import com.baselet.diagram.io.DiagramFileHandler;
public class MailPanel extends JPanel {
private static final Logger log = LoggerFactory.getLogger(MailPanel.class);
private static final long serialVersionUID = 1L;
/**
* Some int and String
*/
private final int paddingTop = 1;
private final int paddingBottom = 1;
private final int outerPaddingLeft = 15;
private final int outerPaddingRight = 15;
private final int halfHorizontalDividerSpace = 2;
private final int verticalDividerSpace = 10;
/**
* Components
*/
private final GridBagLayout layout = new GridBagLayout();
private final JLabel lb_from = new JLabel("From:");
private final JTextField tf_from = new JTextField();
private final JLink lnk_smtpInfo = new JLink(Program.getInstance().getWebsite() + "/smtp.htm", "What is SMTP?");
private final JLabel lb_smtp = new JLabel("SMTP:");
private final JTextField tf_smtp = new JTextField();
private final JCheckBox cb_smtp_auth = new JCheckBox();
private final JLabel lb_smtpUser = new JLabel("User:");
private final JTextField tf_smtpUser = new JTextField();
private final JLabel lb_smtpPW = new JLabel("PW:");
private final JPasswordField pf_smtpPW = new JPasswordField();
private final JCheckBox cb_pwSave = new JCheckBox();
private final JLabel lb_to = new JLabel("To:");
private final JTextField tf_to = new JTextField();
private final JLabel lb_cc = new JLabel("CC:");
private final JTextField tf_cc = new JTextField();
private final JLabel lb_bcc = new JLabel("BCC:");
private final JTextField tf_bcc = new JTextField();
private final JLabel lb_subject = new JLabel("Subject:");
private final JTextField tf_subject = new JTextField();
private final JTextArea ta_text = new JTextArea(5, 5);
JScrollPane sp_text = new JScrollPane(ta_text);
private final JCheckBox cb_attachXml = new JCheckBox();
private final JCheckBox cb_attachGif = new JCheckBox();
private final JCheckBox cb_attachPdf = new JCheckBox();
private final JButton bt_send = new JButton("Send");
private final JButton bt_cancel = new JButton("Cancel");
private final JPanel panel_attachments = new JPanel(new FlowLayout(FlowLayout.LEFT));
private final JPanel panel_attachmentsWithButton = new JPanel(layout);
// the padding between lines is different for the labels and text components of the grid bag layout
private final Insets paddingLeftLabel = new Insets(paddingTop, outerPaddingLeft, paddingBottom, halfHorizontalDividerSpace);
private final Insets paddingMessagebox = new Insets(paddingTop, outerPaddingLeft, paddingBottom, outerPaddingRight);
private final Insets paddingText = new Insets(paddingTop, halfHorizontalDividerSpace, paddingBottom, outerPaddingRight);
private final Insets paddingCheckbox = new Insets(paddingTop - 2, halfHorizontalDividerSpace, paddingBottom - 2, outerPaddingRight);
private final Insets paddingRightLabel = new Insets(paddingTop, halfHorizontalDividerSpace, paddingBottom, halfHorizontalDividerSpace);
private final Insets noPadding = new Insets(0, 0, 0, 0);
// the label doesn't get any additional space. it's always as short as possible
private final double noWeight = 0;
private final double fullWeight = 1;
private final double leftWeight = 0.75;
private final double rightWeight = 0.25;
// the constraint int to fill the width
private final int fillWidth = GridBagConstraints.HORIZONTAL;
private final int fillBoth = GridBagConstraints.BOTH;
public MailPanel() {
initAndFillComponents();
setLayout(layout);
setSize(new Dimension(0, Config.getInstance().getMail_split_position()));
int line = 0;
addComponent(this, layout, Box.createRigidArea(new Dimension(0, verticalDividerSpace)), 0, line, 10, 1, fillWidth, fullWeight, 0, noPadding);
line++;
addComponent(this, layout, lb_to, 0, line, 1, 1, fillWidth, noWeight, 0, paddingLeftLabel);
addComponent(this, layout, tf_to, 1, line, 1, 1, fillWidth, leftWeight, 0, paddingText);
addComponent(this, layout, lb_from, 2, line, 1, 1, fillWidth, noWeight, 0, paddingRightLabel);
addComponent(this, layout, tf_from, 3, line, 1, 1, fillWidth, rightWeight, 0, paddingRightLabel);
addComponent(this, layout, lnk_smtpInfo, 4, line, 1, 1, fillWidth, noWeight, 0, paddingText);
line++;
addComponent(this, layout, lb_cc, 0, line, 1, 1, fillWidth, noWeight, 0, paddingLeftLabel);
addComponent(this, layout, tf_cc, 1, line, 1, 1, fillWidth, leftWeight, 0, paddingText);
addComponent(this, layout, lb_smtp, 2, line, 1, 1, fillWidth, noWeight, 0, paddingRightLabel);
addComponent(this, layout, tf_smtp, 3, line, 1, 1, fillWidth, rightWeight, 0, paddingRightLabel);
addComponent(this, layout, cb_smtp_auth, 4, line, 1, 1, fillWidth, noWeight, 0, paddingText);
line++;
addComponent(this, layout, lb_bcc, 0, line, 1, 1, fillWidth, noWeight, 0, paddingLeftLabel);
addComponent(this, layout, tf_bcc, 1, line, 1, 1, fillWidth, leftWeight, 0, paddingText);
addComponent(this, layout, lb_smtpUser, 2, line, 1, 1, fillWidth, noWeight, 0, paddingRightLabel);
addComponent(this, layout, tf_smtpUser, 3, line, 1, 1, fillWidth, rightWeight, 0, paddingRightLabel);
line++;
addComponent(this, layout, lb_subject, 0, line, 1, 1, fillWidth, noWeight, 0, paddingLeftLabel);
addComponent(this, layout, tf_subject, 1, line, 1, 1, fillWidth, leftWeight, 0, paddingText);
addComponent(this, layout, lb_smtpPW, 2, line, 1, 1, fillWidth, noWeight, 0, paddingRightLabel);
addComponent(this, layout, pf_smtpPW, 3, line, 1, 1, fillWidth, rightWeight, 0, paddingRightLabel);
addComponent(this, layout, cb_pwSave, 4, line, 1, 1, fillWidth, noWeight, 0, paddingCheckbox);
line++;
addComponent(this, layout, Box.createRigidArea(new Dimension(0, verticalDividerSpace)), 0, line, 10, 1, fillWidth, fullWeight, 0, noPadding);
line++;
addComponent(this, layout, sp_text, 0, line, 5, 1, fillBoth, leftWeight, 1, paddingMessagebox);
line++;
addComponent(this, layout, panel_attachmentsWithButton, 1, line, 5, 1, fillWidth, fullWeight, 0, noPadding);
line++;
addComponent(this, layout, Box.createRigidArea(new Dimension(0, verticalDividerSpace)), 0, line, 4, 1, fillWidth, fullWeight, 0, noPadding);
}
private void initAndFillComponents() {
ta_text.setText(Constants.getDefaultMailtext());
cb_pwSave.setText("save in config");
cb_attachXml.setText("attach " + Program.getInstance().getExtension().toUpperCase());
cb_attachGif.setText("attach GIF");
cb_attachPdf.setText("attach PDF");
cb_smtp_auth.setText("authentication");
bt_send.addActionListener(new SendActionListener());
bt_cancel.addActionListener(new CancelActionListener());
cb_smtp_auth.addActionListener(new AuthentificationActionListener());
// Set Tooltips
String adressToolTip = "Separate multiple adresses with ','";
cb_pwSave.setToolTipText("WARNING: The password is stored as plain text in " + Program.getInstance().getConfigName());
tf_from.setToolTipText(adressToolTip);
tf_to.setToolTipText(adressToolTip);
tf_cc.setToolTipText(adressToolTip);
tf_bcc.setToolTipText(adressToolTip);
// Fill Attachment Panel
panel_attachments.add(cb_attachXml);
panel_attachments.add(Box.createRigidArea(new Dimension(5, 0)));
panel_attachments.add(cb_attachGif);
panel_attachments.add(Box.createRigidArea(new Dimension(5, 0)));
panel_attachments.add(cb_attachPdf);
// Fill the superpanel which holds attachments and the send button
addComponent(panel_attachmentsWithButton, layout, panel_attachments, 0, 0, 1, 1, fillWidth, fullWeight, 0, noPadding);
addComponent(panel_attachmentsWithButton, layout, bt_send, 1, 0, 1, 1, fillWidth, fullWeight, 0, paddingText);
addComponent(panel_attachmentsWithButton, layout, bt_cancel, 2, 0, 1, 1, fillWidth, fullWeight, 0, paddingText);
setAllFonts();
readConstants();
checkVisibilityOfSmtpAuth();
}
private void sendMail() {
/**
* Initialize some variables and objects
*/
String smtpHost = tf_smtp.getText();
String smtpUser = tf_smtpUser.getText();
String smtpPW = String.valueOf(pf_smtpPW.getPassword());
String from = tf_from.getText();
String[] to = removeWhitespaceAndSplitAt(tf_to.getText());
String[] cc = removeWhitespaceAndSplitAt(tf_cc.getText());
String[] bcc = removeWhitespaceAndSplitAt(tf_bcc.getText());
String subject = tf_subject.getText();
String text = ta_text.getText();
boolean useSmtpAuthentication = false;
File diagramXml = null;
File diagramGif = null;
File diagramPdf = null;
int nrOfAttachments = 0;
// Set SMTP Authentication if the user or password field isn't empty
if (!smtpUser.isEmpty() || !smtpPW.isEmpty()) {
useSmtpAuthentication = true;
}
// Create the temp diagrams to send
try {
final String diagramName = "diagram_" + new SimpleDateFormat("yyyyMMdd_hhmmss").format(new Date());
DiagramFileHandler fileHandler = CurrentDiagram.getInstance().getDiagramHandler().getFileHandler();
if (cb_attachXml.isSelected()) {
nrOfAttachments++;
diagramXml = fileHandler.doSaveTempDiagram(diagramName, Program.getInstance().getExtension());
}
if (cb_attachGif.isSelected()) {
nrOfAttachments++;
diagramGif = fileHandler.doSaveTempDiagram(diagramName, "gif");
}
if (cb_attachPdf.isSelected()) {
nrOfAttachments++;
diagramPdf = fileHandler.doSaveTempDiagram(diagramName, "pdf");
}
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "There has been an error with your diagram. Please make sure it's not empty.", "Diagram Error", JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
return;
}
/**
* Check if all necessary fields are filled
*/
String errorMsg = null;
if (smtpHost.isEmpty()) {
errorMsg = "The SMTP field must not be empty";
}
else if (from.isEmpty()) {
errorMsg = "The FROM field must not be empty";
}
else if (to.length == 0) {
errorMsg = "The TO field must not be empty";
}
if (errorMsg != null) {
JOptionPane.showMessageDialog(this, errorMsg, "Error", JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
return;
}
/**
* Set up the mail
*/
try {
// Get system properties and session
Properties props = System.getProperties();
Session session = Session.getInstance(props);
// Define message and it's parts
MimeMessage message = new MimeMessage(session);
MimeBodyPart textPart = new MimeBodyPart();
MimeBodyPart[] attachmentPart = new MimeBodyPart[nrOfAttachments];
for (int i = 0; i < nrOfAttachments; i++) {
attachmentPart[i] = new MimeBodyPart();
}
// Build multipart message
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textPart);
for (int i = 0; i < nrOfAttachments; i++) {
multipart.addBodyPart(attachmentPart[i]);
}
message.setContent(multipart);
/**
* Fill the message properties
*/
// Set the SMTP Host
props.put("mail.smtp.host", smtpHost);
// We want to close the connection immediately after sending
props.put("mail.smtp.quitwait", "false");
// We want to use encryption if needed
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.ssl.protocols", "SSLv3 TLSv1");
// If authentication is needed we set it to true
if (useSmtpAuthentication) {
props.put("mail.smtp.auth", "true");
}
else {
props.put("mail.smtp.auth", "false");
}
// Set all recipients of any kind (TO, CC, BCC)
message.setFrom(new InternetAddress(from));
for (String element : to) {
message.addRecipient(Message.RecipientType.TO, new InternetAddress(element));
}
for (String element : cc) {
message.addRecipient(Message.RecipientType.CC, new InternetAddress(element));
}
for (String element : bcc) {
message.addRecipient(Message.RecipientType.BCC, new InternetAddress(element));
}
// Set subject, text and attachment
message.setSubject(subject);
textPart.setText(text);
int i = 0;
if (cb_attachXml.isSelected()) {
attachmentPart[i++].attachFile(diagramXml);
}
if (cb_attachGif.isSelected()) {
attachmentPart[i++].attachFile(diagramGif);
}
if (cb_attachPdf.isSelected()) {
attachmentPart[i++].attachFile(diagramPdf);
}
/**
* Send message (if no authentication is used, we use the short variant to send a mail
*/
if (useSmtpAuthentication) {
Transport transport = session.getTransport("smtp");
try {
transport.connect(smtpHost, smtpUser, smtpPW);
transport.sendMessage(message, message.getAllRecipients());
} finally {
transport.close();
}
}
else { // No SMTP Authentication
Transport.send(message);
}
Notifier.getInstance().showInfo("Email sent");
closePanel();
}
catch (MessagingException e) {
log.error("SMTP Error", e);
JOptionPane.showMessageDialog(this, "There has been an error with your smtp server." + Constants.NEWLINE + "Please recheck your smtp server and login data.", "SMTP Error", JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
} catch (IOException e) {
log.error("Mail Error", e);
JOptionPane.showMessageDialog(this, "There has been an error sending your mail." + Constants.NEWLINE + "Please recheck your input data.", "Sending Error", JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
} catch (Throwable e) {
log.error("Mail Error", e);
JOptionPane.showMessageDialog(this, "There has been an error sending your mail." + Constants.NEWLINE + "Please recheck your input data.", "Sending Error", JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
} finally {
if (diagramXml != null) {
Path.safeDeleteFile(diagramXml, false);
}
if (diagramGif != null) {
Path.safeDeleteFile(diagramGif, false);
}
if (diagramPdf != null) {
Path.safeDeleteFile(diagramPdf, false);
}
}
}
/**
* Adds a component to this panel
*
* @param gbl
* The GridBagLayout of this component
* @param c
* The Component to add
* @param x
* The x value of grid where the component starts
* @param y
* The y value of grid where the component starts
* @param width
* How many spaces of the grid's width will be used by the component
* @param height
* How many spaces of the grid's height will be used by the component
* @param fill
* If the component's display area is larger than the component's requested size this param determines whether and how to resize the component
* @param weightx
* Specifies how to distribute extra horizontal space.
* @param weighty
* Specifies how to distribute extra vertical space.
* @param insets
* Specifies the external padding of the component (= minimum amount of space between the component and the edges of its display area)
*/
private void addComponent(JPanel panel, GridBagLayout gbl, Component c, int x, int y, int width, int height, int fill, double weightx, double weighty, Insets insets) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = width;
gbc.gridheight = height;
gbc.fill = fill;
gbc.weightx = weightx;
gbc.weighty = weighty;
gbc.insets = insets;
gbl.setConstraints(c, gbc);
panel.add(c);
}
private String[] removeWhitespaceAndSplitAt(String inputString) {
if (inputString.isEmpty()) {
return new String[] {};
}
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < inputString.length(); i++) {
if (inputString.charAt(i) != ' ') {
sb.append(inputString.charAt(i));
}
}
return sb.toString().split(",");
}
private void storeConstants() {
ConfigMail cfgMail = ConfigMail.getInstance();
cfgMail.setMail_smtp(tf_smtp.getText());
cfgMail.setMail_smtp_auth(cb_smtp_auth.isSelected());
cfgMail.setMail_smtp_user(tf_smtpUser.getText());
cfgMail.setMail_smtp_pw_store(cb_pwSave.isSelected());
if (cb_pwSave.isSelected()) {
cfgMail.setMail_smtp_pw(String.valueOf(pf_smtpPW.getPassword()));
}
else {
cfgMail.setMail_smtp_pw("");
}
cfgMail.setMail_from(tf_from.getText());
cfgMail.setMail_to(tf_to.getText());
cfgMail.setMail_cc(tf_cc.getText());
cfgMail.setMail_bcc(tf_bcc.getText());
cfgMail.setMail_xml(cb_attachXml.isSelected());
cfgMail.setMail_gif(cb_attachGif.isSelected());
cfgMail.setMail_pdf(cb_attachPdf.isSelected());
}
private void readConstants() {
ConfigMail cfgMail = ConfigMail.getInstance();
tf_smtp.setText(cfgMail.getMail_smtp());
cb_smtp_auth.setSelected(cfgMail.isMail_smtp_auth());
tf_smtpUser.setText(cfgMail.getMail_smtp_user());
cb_pwSave.setSelected(cfgMail.isMail_smtp_pw_store());
pf_smtpPW.setText(cfgMail.getMail_smtp_pw());
tf_from.setText(cfgMail.getMail_from());
tf_to.setText(cfgMail.getMail_to());
tf_cc.setText(cfgMail.getMail_cc());
tf_bcc.setText(cfgMail.getMail_bcc());
cb_attachXml.setSelected(cfgMail.isMail_xml());
cb_attachGif.setSelected(cfgMail.isMail_gif());
cb_attachPdf.setSelected(cfgMail.isMail_pdf());
}
private void setAllFonts() {
Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 12);
Font fontBold = new Font(Font.SANS_SERIF, Font.BOLD, 12);
Font fontSmallItalic = new Font(Font.SANS_SERIF, Font.ITALIC, 10);
lb_smtp.setFont(fontBold);
tf_smtp.setFont(font);
lb_smtpUser.setFont(fontBold);
tf_smtpUser.setFont(font);
lb_smtpPW.setFont(fontBold);
pf_smtpPW.setFont(font);
lb_from.setFont(fontBold);
tf_from.setFont(font);
lb_to.setFont(fontBold);
tf_to.setFont(font);
lb_cc.setFont(fontBold);
tf_cc.setFont(font);
lb_bcc.setFont(fontBold);
tf_bcc.setFont(font);
lb_subject.setFont(fontBold);
tf_subject.setFont(font);
ta_text.setFont(font);
cb_attachXml.setFont(fontBold);
cb_attachGif.setFont(fontBold);
cb_attachPdf.setFont(fontBold);
lnk_smtpInfo.setFont(fontSmallItalic);
cb_smtp_auth.setFont(fontSmallItalic);
cb_pwSave.setFont(fontSmallItalic);
}
public void closePanel() {
storeConstants();
Config.getInstance().setMail_split_position((int) this.getSize().getHeight());
CurrentGui.getInstance().getGui().setMailPanelEnabled(false);
}
private class SendActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
sendMail();
}
}
private class CancelActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
closePanel();
}
}
private void checkVisibilityOfSmtpAuth() {
boolean val = cb_smtp_auth.isSelected();
lb_smtpUser.setVisible(val);
tf_smtpUser.setVisible(val);
lb_smtpPW.setVisible(val);
pf_smtpPW.setVisible(val);
cb_pwSave.setVisible(val);
if (!val) {
tf_smtpUser.setText("");
pf_smtpPW.setText("");
cb_pwSave.setSelected(false);
}
repaint();
}
private class AuthentificationActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
checkVisibilityOfSmtpAuth();
}
}
}