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