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: }