package Legacy.plugins.CENO.FreenetInterface;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Flags;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.search.FlagTerm;
import org.apache.commons.compress.utils.IOUtils;
import com.sun.mail.smtp.SMTPTransport;
public class FreemailAPI {
private static final String localHost = "127.0.0.1";
private static final int smtpPort = 4025;
private static final int imapPort = 4143;
/**
* Inner class that extends javax mail Authenticator.
* Handles authentication with Freemail's SMTPHandler during the
* creation of the SMTPTransport session.
*/
private static class SMTPAuthenticator extends Authenticator {
String freemail, password;
/**
* SMTPAuthenticator constructor
* @param freemail
* @param password
*/
public SMTPAuthenticator(String freemail, String password) {
this.freemail = freemail;
this.password = password;
}
/**
* If freemail and password are set and not empty, return a PasswordAuthentication instance.
* Unless, return null.
*
* In case of null, Freemail SMTPHandler throws an AuthenticationFailedException
*/
@Override
public PasswordAuthentication getPasswordAuthentication() {
if (freemail != null && !freemail.isEmpty()) {
if (password != null && !password.isEmpty()) {
return new PasswordAuthentication(freemail, password);
}
}
return null;
}
}
/**
* Static method that sends a freemail over SMTP
*
* @param freemailFrom the sender freemail
* @param freemailTo the list of recipients' freemails
* @param subject the subject of the freemail
* @param content the content (plain text body) of the freemail
* @param password the password to use for authentication with freemail's SMTP handler
* @return true, if the freemail was sent successfully
*/
public static synchronized boolean sendFreemail(String freemailFrom, String freemailTo[], String subject, String content, String password) {
Session smtpSession = prepareSMTPSession(freemailFrom, password);
if (smtpSession == null) {
return false;
}
SMTPTransport smtpTransport = doConnectSMTP(smtpSession, freemailFrom, password);
if (smtpTransport != null) {
Message msg = prepareMessage(smtpSession, freemailFrom, freemailTo, subject, content);
if (msg != null) {
try {
Transport.send(msg, msg.getAllRecipients());
smtpTransport.close();
} catch (MessagingException e) {
//TODO Handle 550 bridge freemail not found because bridge's WOT has no trust value
// by sending fcp message > add trust value 75 to the WOT identity of the freemail
e.printStackTrace();
return false;
}
return true;
}
}
return false;
}
private static Session prepareSMTPSession(String smtpUser, String smtpPassword) {
Properties props = System.getProperties();
props.put("mail.smtp.host", localHost);
props.put("mail.smtp.port", smtpPort);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.user", smtpUser);
props.put("mail.smtp.connectiontimeout", "5000");
Session session = null;
try {
session = Session.getInstance(props, new SMTPAuthenticator(smtpUser, smtpPassword));
} catch (IllegalStateException e) {
e.printStackTrace();
}
return session;
}
private static Session prepareIMAPSession(String imapUser, String imapPassword) {
Properties props = System.getProperties();
props.put("mail.imap.host", localHost);
props.put("mail.imap.port", imapPort);
props.put("mail.imap.connectiontimeout", "5000");
Session session = null;
try {
session = Session.getInstance(props);
} catch (IllegalStateException e) {
e.printStackTrace();
}
return session;
}
private static Message prepareMessage(Session smtpSession, String freemailFrom, String freemailTo[], String subect, String content) {
Message msg = new MimeMessage(smtpSession);
try {
msg.setFrom(new InternetAddress(freemailFrom));
for (String recipient : freemailTo) {
msg.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient));
}
msg.setSubject(subect);
msg.setText(content);
} catch (MessagingException e) {
return null;
}
return msg;
}
private static SMTPTransport doConnectSMTP(Session session, String smtpUser, String smtpPassword) {
SMTPTransport smtpTransport = null;
try {
smtpTransport = (SMTPTransport)session.getTransport("smtp");
} catch (NoSuchProviderException e) {
return null;
}
try {
smtpTransport.connect(smtpUser, smtpPassword);
} catch (MessagingException e) {
e.printStackTrace();
return null;
}
return smtpTransport;
}
/**
* Get an array of the unread freemails of a folder via IMAP
*
* @param freemail the freemail user
* @param password freemail user's password
* @param inboxFolder the folder to search for undread freemails
* @param shouldDelete if {@code true}, delete unread messages after retrieval
* @return a Message array of the unread freemails, an empty array if there are no unread
* freemails and {@code null} if there was an error
*/
public static synchronized String[] getUnreadMailsSubject(String freemail, String password, String mailFolder, boolean shouldDelete) {
Message[] unreadMessages = getMessages(freemail, password, mailFolder, shouldDelete, Flags.Flag.SEEN, false);
if (unreadMessages == null) {
return null;
}
String[] mailsSubject = new String[unreadMessages.length];
for (int i=0; i<unreadMessages.length; i++) {
try {
mailsSubject[i] = unreadMessages[i].getSubject();
} catch (MessagingException e) {
mailsSubject[i] = "Invalid freemail subject";
}
}
return mailsSubject;
}
public static synchronized String[] getMailsContentFrom(String freemail, String freemailFrom, String password, String mailFolder) {
Message[] messages = getMailsFrom(freemail, freemailFrom, password, mailFolder);
ArrayList<String> mailsBody = new ArrayList<String>();
ByteArrayOutputStream contentStr = new ByteArrayOutputStream();
for (Message message : messages) {
try {
if (!message.getContentType().startsWith("text/plain")) {
continue;
}
message.writeTo(contentStr);
mailsBody.add(contentStr.toString());
} catch (IOException e) {
continue;
} catch (MessagingException e) {
continue;
}
}
return (String[]) mailsBody.toArray();
}
public static synchronized Message[] getMailsFrom(String freemail, String freemailFrom, String password, String mailFolder) {
Message[] allMessages = getMessages(freemail, password, mailFolder, false, null, false);
ArrayList<Message> mailsFrom = new ArrayList<Message>();
for (Message message : allMessages) {
try {
if (message.getFrom()[0].equals(freemailFrom)) {
mailsFrom.add(message);
}
} catch (MessagingException e) {
continue;
}
}
return (Message[]) mailsFrom.toArray();
}
private static Message[] getMessages(String freemail, String password, String mailFolder, boolean shouldDelete, Flag flag, boolean flagBool) {
Store store = null;
Folder folder = null;
try {
Session session = prepareIMAPSession(freemail, password);
if (session == null) {
return null;
}
store = session.getStore("imap");
store.connect(localHost, freemail, password);
folder = store.getFolder(mailFolder);
if (folder == null || !folder.exists()) {
return null;
}
folder.open(Folder.READ_WRITE);
Message[] messages;
if (flag != null) {
messages = folder.search(new FlagTerm(new Flags(flag), flagBool));
} else {
messages = folder.getMessages();
}
if (shouldDelete) {
for (Message message : messages) {
message.setFlag(Flag.DELETED, true);
}
}
// Once the folder is closed, messages cannot be read. Therefore we need to
// return a copy of them in a new array.
Message[] messagesCopy = new Message[messages.length];
for (int i=0; i<messages.length; i++) {
messagesCopy[i] = new MimeMessage((MimeMessage) messages[i]);
}
// Close the folder and expunge (remove) all mails with the DELETED flag
folder.close(true);
store.close();
return messagesCopy;
} catch (Exception ex) {
ex.printStackTrace();
try {
if (store != null) {
store.close();
}
if (folder != null) {
// Close the folder without expunging the mails
folder.close(false);
}
} catch (MessagingException e) {
e.printStackTrace();
}
return null;
}
}
private static String getShortFreemailAddr(String freemailAddress) {
return freemailAddress.split("@|\\.")[1];
}
private static String getShortIdentityURI(String identityRequestURI) {
return identityRequestURI.split("@|,")[1];
}
private static Path getAccountDir(String freemailAccount) throws UnsupportedEncodingException {
return Paths.get("freemail-wot/data", getShortFreemailAddr(freemailAccount) + "/");
}
public static boolean copyAccprops(String freemailAccount) {
// Check if an account for the CENO client identity already exists
// If it doesn't exist, create the corresponding directory
Path accpropsPath = null;
try {
accpropsPath = getAccountDir(freemailAccount);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
}
if (Files.isDirectory(accpropsPath)) {
return true;
}
try {
Files.createDirectories(accpropsPath);
} catch (IOException e) {
e.printStackTrace();
return false;
}
// Copy the accprops to the directory created
InputStream accpropsIn = FreemailAPI.class.getResourceAsStream("Freemail/resources/accprops");
if (accpropsIn == null) {
return false;
}
FileOutputStream accpropsOut = null;
try {
accpropsOut = new FileOutputStream(accpropsPath + "/accprops");
} catch (FileNotFoundException e) {
return false;
}
try {
IOUtils.copy(accpropsIn, accpropsOut);
accpropsIn.close();
accpropsOut.flush();
accpropsOut.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public static boolean setRandomNextMsgNumber(String freemailAccount, String freemailTo) {
Path outboxPath;
try {
outboxPath = Paths.get(getAccountDir(freemailAccount).toString(), "outbox", getShortFreemailAddr(freemailTo));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
}
try {
PrintWriter pwIndex = new PrintWriter(outboxPath + "/index");
pwIndex.print("nextMessageNumber=");
pwIndex.println((int) (Math.random() * (Integer.MAX_VALUE * 0.8)));
pwIndex.close();
} catch (IOException e) {
return false;
}
return true;
}
public static boolean clearOutboxLog(String freemailAccount, String identityFrom) {
Path outboxPath;
try {
outboxPath = Paths.get(getAccountDir(freemailAccount).toString(), "outbox", getShortIdentityURI(identityFrom));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
}
File outboxFiles = new File(outboxPath.toString());
if (!outboxFiles.isDirectory()) {
return false;
}
for (File outboxFile : outboxFiles.listFiles()) {
if (!outboxFile.isDirectory()) {
outboxFile.delete();
}
}
return true;
}
public static boolean clearOutboxMessages(String freemailAccount, String freemailTo) {
Path outboxPath;
try {
outboxPath = Paths.get(getAccountDir(freemailAccount).toString(), "outbox", getShortFreemailAddr(freemailTo));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
}
File outboxFiles = new File(outboxPath.toString());
if (!outboxFiles.isDirectory()) {
return false;
}
for (File outboxFile : outboxFiles.listFiles()) {
if (!outboxFile.isDirectory()) {
outboxFile.delete();
}
}
return true;
}
public static abstract class Freemail {
private String freemailFrom;
private String[] freemailTo;
private String subject;
private String body;
public Freemail(String freemailFrom, String[] freemailTo, String subject, String body) {
this.setFreemailFrom(freemailFrom);
this.setFreemailTo(freemailTo);
this.setSubject(subject);
this.setBody(body);
}
public String getFreemailFrom() {
return freemailFrom;
}
public void setFreemailFrom(String freemailFrom) {
this.freemailFrom = freemailFrom;
}
public String[] getFreemailTo() {
return freemailTo;
}
public void setFreemailTo(String[] freemailTo) {
this.freemailTo = freemailTo;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
}