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 java.util.ArrayList;
chris@1: import java.util.List;
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.internet.InternetAddress;
chris@3: import org.sonews.config.Config;
chris@3: import org.sonews.storage.Article;
chris@3: import org.sonews.storage.Headers;
chris@3: import org.sonews.storage.StorageBackendException;
chris@3: import org.sonews.storage.StorageManager;
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@3: Config.inst().get(Config.MLSEND_USER, "user");
chris@1: final String password =
chris@3: Config.inst().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@3: to = msg.getReplyTo();
chris@3: }
chris@3:
chris@3: if(to == null || to.length <= 0)
chris@3: {
chris@3: Log.msg("Skipping message because no recipient!", false);
chris@1: return false;
chris@1: }
chris@1: else
chris@1: {
chris@3: boolean posted = false;
chris@3: List newsgroups = new ArrayList();
chris@3:
chris@3: for (Address toa : to) // Address can have '<' '>' around
chris@1: {
chris@3: if (toa instanceof InternetAddress)
chris@1: {
chris@3: List groups = StorageManager.current()
chris@3: .getGroupsForList((InternetAddress)toa);
chris@3: newsgroups.addAll(groups);
chris@1: }
chris@3: }
chris@3:
chris@3: if (newsgroups.size() > 0)
chris@3: {
chris@3: StringBuilder groups = new StringBuilder();
chris@3: for(int n = 0; n < newsgroups.size(); n++)
chris@1: {
chris@3: groups.append(newsgroups.get(n));
chris@3: if(n + 1 != newsgroups.size())
chris@3: {
chris@3: groups.append(',');
chris@3: }
chris@3: }
chris@3: Log.msg("Posting to group " + groups.toString(), true);
chris@1:
chris@3: // Create new Article object
chris@3: Article article = new Article(msg);
chris@3: article.setGroup(groups.toString());
chris@3: article.removeHeader(Headers.REPLY_TO);
chris@3: article.removeHeader(Headers.TO);
chris@3:
chris@3: // Write article to database
chris@3: if(!StorageManager.current().isArticleExisting(article.getMessageID()))
chris@3: {
chris@3: StorageManager.current().addArticle(article);
chris@3: Stats.getInstance().mailGatewayed(
chris@3: article.getHeader(Headers.NEWSGROUPS)[0]);
chris@1: }
chris@1: else
chris@1: {
chris@3: Log.msg("Article " + article.getMessageID() + " already existing.", true);
chris@1: }
chris@3: posted = true;
chris@3: }
chris@3: else
chris@3: {
chris@3: StringBuilder buf = new StringBuilder();
chris@3: for(Address toa : to)
chris@3: {
chris@3: buf.append(' ');
chris@3: buf.append(toa.toString());
chris@3: }
chris@3: Log.msg("No group for" + buf.toString(), false);
chris@3: }
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@3: throws IOException, MessagingException, StorageBackendException
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@3: String listAddress = StorageManager.current().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@3: String smtpHost = Config.inst().get(Config.MLSEND_HOST, "localhost");
chris@3: int smtpPort = Config.inst().get(Config.MLSEND_PORT, 25);
chris@3: String smtpUser = Config.inst().get(Config.MLSEND_USER, "user");
chris@3: String smtpPw = Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
chris@3: String smtpFrom = Config.inst().get(
chris@3: Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]);
chris@1:
chris@3: // TODO: Make Article cloneable()
chris@3: String group = article.getHeader(Headers.NEWSGROUPS)[0];
chris@3: article.getMessageID(); // Make sure an ID is existing
chris@3: article.removeHeader(Headers.NEWSGROUPS);
chris@3: article.removeHeader(Headers.PATH);
chris@3: article.removeHeader(Headers.LINES);
chris@3: article.removeHeader(Headers.BYTES);
chris@1:
chris@3: article.setHeader("To", listAddress);
chris@3: article.setHeader("Reply-To", listAddress);
chris@1:
chris@3: if(Config.inst().get(Config.MLSEND_RW_SENDER, false))
chris@1: {
chris@3: rewriteSenderAddress(article); // Set the SENDER address
chris@1: }
chris@1:
chris@3: SMTPTransport smtpTransport = new SMTPTransport(smtpHost, smtpPort);
chris@3: smtpTransport.send(article, smtpFrom, listAddress);
chris@3: smtpTransport.close();
chris@1:
chris@3: Stats.getInstance().mailGatewayed(group);
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@3: private static void rewriteSenderAddress(Article msg)
chris@1: throws MessagingException
chris@1: {
chris@3: String mlAddress = Config.inst().get(Config.MLSEND_ADDRESS, null);
chris@1:
chris@1: if(mlAddress != null)
chris@1: {
chris@3: msg.setHeader(Headers.SENDER, 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: }