chris@1: /*
chris@1: * SONEWS News Server
chris@1: * see AUTHORS for the list of contributors
chris@1: *
chris@1: * This program is free software: you can redistribute it and/or modify
chris@1: * it under the terms of the GNU General Public License as published by
chris@1: * the Free Software Foundation, either version 3 of the License, or
chris@1: * (at your option) any later version.
chris@1: *
chris@1: * This program is distributed in the hope that it will be useful,
chris@1: * but WITHOUT ANY WARRANTY; without even the implied warranty of
chris@1: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
chris@1: * GNU General Public License for more details.
chris@1: *
chris@1: * You should have received a copy of the GNU General Public License
chris@1: * along with this program. If not, see .
chris@1: */
chris@1:
chris@1: package org.sonews.mlgw;
chris@1:
chris@1: import java.io.IOException;
chris@1: import org.sonews.daemon.Config;
chris@1: import org.sonews.daemon.storage.Article;
chris@1: import org.sonews.util.io.ArticleInputStream;
chris@1: import org.sonews.daemon.storage.Database;
chris@1: import java.sql.SQLException;
chris@1: import java.util.ArrayList;
chris@1: import java.util.List;
chris@1: import java.util.Properties;
chris@1: import javax.mail.Address;
chris@1: import javax.mail.Authenticator;
chris@1: import javax.mail.Message;
chris@1: import javax.mail.MessagingException;
chris@1: import javax.mail.PasswordAuthentication;
chris@1: import javax.mail.Session;
chris@1: import javax.mail.Transport;
chris@1: import javax.mail.internet.InternetAddress;
chris@1: import javax.mail.internet.MimeMessage;
chris@1: import org.sonews.daemon.storage.Headers;
chris@1: import org.sonews.util.Log;
chris@1: import org.sonews.util.Stats;
chris@1:
chris@1: /**
chris@1: * Dispatches messages from mailing list or newsserver or vice versa.
chris@1: * @author Christian Lins
chris@1: * @since sonews/0.5.0
chris@1: */
chris@1: public class Dispatcher
chris@1: {
chris@1:
chris@1: static class PasswordAuthenticator extends Authenticator
chris@1: {
chris@1:
chris@1: @Override
chris@1: public PasswordAuthentication getPasswordAuthentication()
chris@1: {
chris@1: final String username =
chris@1: Config.getInstance().get(Config.MLSEND_USER, "user");
chris@1: final String password =
chris@1: Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
chris@1:
chris@1: return new PasswordAuthentication(username, password);
chris@1: }
chris@1:
chris@1: }
chris@1:
chris@1: /**
chris@1: * Posts a message that was received from a mailing list to the
chris@1: * appropriate newsgroup.
chris@1: * @param msg
chris@1: */
chris@1: public static boolean toGroup(final Message msg)
chris@1: {
chris@1: try
chris@1: {
chris@1: Address[] to = msg.getAllRecipients(); // includes TO/CC/BCC
chris@1: if(to == null || to.length <= 0)
chris@1: {
chris@1: Log.msg("Skipping message because no receipient!", true);
chris@1: return false;
chris@1: }
chris@1: else
chris@1: {
chris@1: boolean posted = false;
chris@1: for(Address toa : to) // Address can have '<' '>' around
chris@1: {
chris@1: if(!(toa instanceof InternetAddress))
chris@1: {
chris@1: continue;
chris@1: }
chris@1: String group = Database.getInstance()
chris@1: .getGroupForList((InternetAddress)toa);
chris@1: if(group != null)
chris@1: {
chris@1: Log.msg("Posting to group " + group, true);
chris@1:
chris@1: // Create new Article object
chris@1: Article article = new Article(msg);
chris@1: article.setGroup(group);
chris@1:
chris@1: // Write article to database
chris@1: if(!Database.getInstance().isArticleExisting(article.getMessageID()))
chris@1: {
chris@1: Database.getInstance().addArticle(article);
chris@1: Stats.getInstance().mailGatewayed(
chris@1: article.getHeader(Headers.NEWSGROUPS)[0]);
chris@1: }
chris@1: else
chris@1: {
chris@1: Log.msg("Article " + article.getMessageID() + " already existing.", true);
chris@1: // TODO: It may be possible that a ML mail is posted to several
chris@1: // ML addresses...
chris@1: }
chris@1: posted = true;
chris@1: }
chris@1: else
chris@1: {
chris@1: Log.msg("No group for " + toa, true);
chris@1: }
chris@1: } // end for
chris@1: return posted;
chris@1: }
chris@1: }
chris@1: catch(Exception ex)
chris@1: {
chris@1: ex.printStackTrace();
chris@1: return false;
chris@1: }
chris@1: }
chris@1:
chris@1: /**
chris@1: * Mails a message received through NNTP to the appropriate mailing list.
chris@1: */
chris@1: public static void toList(Article article)
chris@1: throws IOException, MessagingException, SQLException
chris@1: {
chris@1: // Get mailing lists for the group of this article
chris@1: List listAddresses = new ArrayList();
chris@1: String[] groupnames = article.getHeader(Headers.NEWSGROUPS)[0].split(",");
chris@1:
chris@1: for(String groupname : groupnames)
chris@1: {
chris@1: String listAddress = Database.getInstance().getListForGroup(groupname);
chris@1: if(listAddress != null)
chris@1: {
chris@1: listAddresses.add(listAddress);
chris@1: }
chris@1: }
chris@1:
chris@1: for(String listAddress : listAddresses)
chris@1: {
chris@1: // Compose message and send it via given SMTP-Host
chris@1: String smtpHost = Config.getInstance().get(Config.MLSEND_HOST, "localhost");
chris@1: int smtpPort = Config.getInstance().get(Config.MLSEND_PORT, 25);
chris@1: String smtpUser = Config.getInstance().get(Config.MLSEND_USER, "user");
chris@1: String smtpPw = Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
chris@1:
chris@1: Properties props = System.getProperties();
chris@1: props.put("mail.smtp.localhost",
chris@1: Config.getInstance().get(Config.HOSTNAME, "localhost"));
chris@1: props.put("mail.smtp.from", // Used for MAIL FROM command
chris@1: Config.getInstance().get(
chris@1: Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]));
chris@1: props.put("mail.smtp.host", smtpHost);
chris@1: props.put("mail.smtp.port", smtpPort);
chris@1: props.put("mail.smtp.auth", "true");
chris@1:
chris@1: Address[] address = new Address[1];
chris@1: address[0] = new InternetAddress(listAddress);
chris@1:
chris@1: ArticleInputStream in = new ArticleInputStream(article);
chris@1: Session session = Session.getDefaultInstance(props, new PasswordAuthenticator());
chris@1: MimeMessage msg = new MimeMessage(session, in);
chris@1: msg.setRecipient(Message.RecipientType.TO, address[0]);
chris@1: msg.setReplyTo(address);
chris@1: msg.removeHeader(Headers.NEWSGROUPS);
chris@1: msg.removeHeader(Headers.PATH);
chris@1: msg.removeHeader(Headers.LINES);
chris@1: msg.removeHeader(Headers.BYTES);
chris@1:
chris@1: if(Config.getInstance().get(Config.MLSEND_RW_SENDER, false))
chris@1: {
chris@1: rewriteSenderAddress(msg); // Set the SENDER address
chris@1: }
chris@1:
chris@1: if(Config.getInstance().get(Config.MLSEND_RW_FROM, false))
chris@1: {
chris@1: rewriteFromAddress(msg); // Set the FROM address
chris@1: }
chris@1:
chris@1: msg.saveChanges();
chris@1:
chris@1: // Send the mail
chris@1: Transport transport = session.getTransport("smtp");
chris@1: transport.connect(smtpHost, smtpPort, smtpUser, smtpPw);
chris@1: transport.sendMessage(msg, msg.getAllRecipients());
chris@1: transport.close();
chris@1:
chris@1: Stats.getInstance().mailGatewayed(article.getHeader(Headers.NEWSGROUPS)[0]);
chris@1: Log.msg("MLGateway: Mail " + article.getHeader("Subject")[0]
chris@1: + " was delivered to " + listAddress + ".", true);
chris@1: }
chris@1: }
chris@1:
chris@1: /**
chris@1: * Sets the SENDER header of the given MimeMessage. This might be necessary
chris@1: * for moderated groups that does not allow the "normal" FROM sender.
chris@1: * @param msg
chris@1: * @throws javax.mail.MessagingException
chris@1: */
chris@1: private static void rewriteSenderAddress(MimeMessage msg)
chris@1: throws MessagingException
chris@1: {
chris@1: String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
chris@1:
chris@1: if(mlAddress != null)
chris@1: {
chris@1: msg.setSender(new InternetAddress(mlAddress));
chris@1: }
chris@1: else
chris@1: {
chris@1: throw new MessagingException("Cannot rewrite SENDER header!");
chris@1: }
chris@1: }
chris@1:
chris@1: /**
chris@1: * Sets the FROM header of the given MimeMessage. This might be necessary
chris@1: * for moderated groups that does not allow the "normal" FROM sender.
chris@1: * @param msg
chris@1: * @throws javax.mail.MessagingException
chris@1: */
chris@1: private static void rewriteFromAddress(MimeMessage msg)
chris@1: throws MessagingException
chris@1: {
chris@1: Address[] froms = msg.getFrom();
chris@1: String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
chris@1:
chris@1: if(froms.length > 0 && froms[0] instanceof InternetAddress
chris@1: && mlAddress != null)
chris@1: {
chris@1: InternetAddress from = (InternetAddress)froms[0];
chris@1: from.setAddress(mlAddress);
chris@1: msg.setFrom(from);
chris@1: }
chris@1: else
chris@1: {
chris@1: throw new MessagingException("Cannot rewrite FROM header!");
chris@1: }
chris@1: }
chris@1:
chris@1: }