1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/org/sonews/mlgw/Dispatcher.java Fri Jun 26 16:48:50 2009 +0200
1.3 @@ -0,0 +1,251 @@
1.4 +/*
1.5 + * SONEWS News Server
1.6 + * see AUTHORS for the list of contributors
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, either version 3 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License
1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 + */
1.21 +
1.22 +package org.sonews.mlgw;
1.23 +
1.24 +import java.io.IOException;
1.25 +import org.sonews.daemon.Config;
1.26 +import org.sonews.daemon.storage.Article;
1.27 +import org.sonews.util.io.ArticleInputStream;
1.28 +import org.sonews.daemon.storage.Database;
1.29 +import java.sql.SQLException;
1.30 +import java.util.ArrayList;
1.31 +import java.util.List;
1.32 +import java.util.Properties;
1.33 +import javax.mail.Address;
1.34 +import javax.mail.Authenticator;
1.35 +import javax.mail.Message;
1.36 +import javax.mail.MessagingException;
1.37 +import javax.mail.PasswordAuthentication;
1.38 +import javax.mail.Session;
1.39 +import javax.mail.Transport;
1.40 +import javax.mail.internet.InternetAddress;
1.41 +import javax.mail.internet.MimeMessage;
1.42 +import org.sonews.daemon.storage.Headers;
1.43 +import org.sonews.util.Log;
1.44 +import org.sonews.util.Stats;
1.45 +
1.46 +/**
1.47 + * Dispatches messages from mailing list or newsserver or vice versa.
1.48 + * @author Christian Lins
1.49 + * @since sonews/0.5.0
1.50 + */
1.51 +public class Dispatcher
1.52 +{
1.53 +
1.54 + static class PasswordAuthenticator extends Authenticator
1.55 + {
1.56 +
1.57 + @Override
1.58 + public PasswordAuthentication getPasswordAuthentication()
1.59 + {
1.60 + final String username =
1.61 + Config.getInstance().get(Config.MLSEND_USER, "user");
1.62 + final String password =
1.63 + Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
1.64 +
1.65 + return new PasswordAuthentication(username, password);
1.66 + }
1.67 +
1.68 + }
1.69 +
1.70 + /**
1.71 + * Posts a message that was received from a mailing list to the
1.72 + * appropriate newsgroup.
1.73 + * @param msg
1.74 + */
1.75 + public static boolean toGroup(final Message msg)
1.76 + {
1.77 + try
1.78 + {
1.79 + Address[] to = msg.getAllRecipients(); // includes TO/CC/BCC
1.80 + if(to == null || to.length <= 0)
1.81 + {
1.82 + Log.msg("Skipping message because no receipient!", true);
1.83 + return false;
1.84 + }
1.85 + else
1.86 + {
1.87 + boolean posted = false;
1.88 + for(Address toa : to) // Address can have '<' '>' around
1.89 + {
1.90 + if(!(toa instanceof InternetAddress))
1.91 + {
1.92 + continue;
1.93 + }
1.94 + String group = Database.getInstance()
1.95 + .getGroupForList((InternetAddress)toa);
1.96 + if(group != null)
1.97 + {
1.98 + Log.msg("Posting to group " + group, true);
1.99 +
1.100 + // Create new Article object
1.101 + Article article = new Article(msg);
1.102 + article.setGroup(group);
1.103 +
1.104 + // Write article to database
1.105 + if(!Database.getInstance().isArticleExisting(article.getMessageID()))
1.106 + {
1.107 + Database.getInstance().addArticle(article);
1.108 + Stats.getInstance().mailGatewayed(
1.109 + article.getHeader(Headers.NEWSGROUPS)[0]);
1.110 + }
1.111 + else
1.112 + {
1.113 + Log.msg("Article " + article.getMessageID() + " already existing.", true);
1.114 + // TODO: It may be possible that a ML mail is posted to several
1.115 + // ML addresses...
1.116 + }
1.117 + posted = true;
1.118 + }
1.119 + else
1.120 + {
1.121 + Log.msg("No group for " + toa, true);
1.122 + }
1.123 + } // end for
1.124 + return posted;
1.125 + }
1.126 + }
1.127 + catch(Exception ex)
1.128 + {
1.129 + ex.printStackTrace();
1.130 + return false;
1.131 + }
1.132 + }
1.133 +
1.134 + /**
1.135 + * Mails a message received through NNTP to the appropriate mailing list.
1.136 + */
1.137 + public static void toList(Article article)
1.138 + throws IOException, MessagingException, SQLException
1.139 + {
1.140 + // Get mailing lists for the group of this article
1.141 + List<String> listAddresses = new ArrayList<String>();
1.142 + String[] groupnames = article.getHeader(Headers.NEWSGROUPS)[0].split(",");
1.143 +
1.144 + for(String groupname : groupnames)
1.145 + {
1.146 + String listAddress = Database.getInstance().getListForGroup(groupname);
1.147 + if(listAddress != null)
1.148 + {
1.149 + listAddresses.add(listAddress);
1.150 + }
1.151 + }
1.152 +
1.153 + for(String listAddress : listAddresses)
1.154 + {
1.155 + // Compose message and send it via given SMTP-Host
1.156 + String smtpHost = Config.getInstance().get(Config.MLSEND_HOST, "localhost");
1.157 + int smtpPort = Config.getInstance().get(Config.MLSEND_PORT, 25);
1.158 + String smtpUser = Config.getInstance().get(Config.MLSEND_USER, "user");
1.159 + String smtpPw = Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
1.160 +
1.161 + Properties props = System.getProperties();
1.162 + props.put("mail.smtp.localhost",
1.163 + Config.getInstance().get(Config.HOSTNAME, "localhost"));
1.164 + props.put("mail.smtp.from", // Used for MAIL FROM command
1.165 + Config.getInstance().get(
1.166 + Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]));
1.167 + props.put("mail.smtp.host", smtpHost);
1.168 + props.put("mail.smtp.port", smtpPort);
1.169 + props.put("mail.smtp.auth", "true");
1.170 +
1.171 + Address[] address = new Address[1];
1.172 + address[0] = new InternetAddress(listAddress);
1.173 +
1.174 + ArticleInputStream in = new ArticleInputStream(article);
1.175 + Session session = Session.getDefaultInstance(props, new PasswordAuthenticator());
1.176 + MimeMessage msg = new MimeMessage(session, in);
1.177 + msg.setRecipient(Message.RecipientType.TO, address[0]);
1.178 + msg.setReplyTo(address);
1.179 + msg.removeHeader(Headers.NEWSGROUPS);
1.180 + msg.removeHeader(Headers.PATH);
1.181 + msg.removeHeader(Headers.LINES);
1.182 + msg.removeHeader(Headers.BYTES);
1.183 +
1.184 + if(Config.getInstance().get(Config.MLSEND_RW_SENDER, false))
1.185 + {
1.186 + rewriteSenderAddress(msg); // Set the SENDER address
1.187 + }
1.188 +
1.189 + if(Config.getInstance().get(Config.MLSEND_RW_FROM, false))
1.190 + {
1.191 + rewriteFromAddress(msg); // Set the FROM address
1.192 + }
1.193 +
1.194 + msg.saveChanges();
1.195 +
1.196 + // Send the mail
1.197 + Transport transport = session.getTransport("smtp");
1.198 + transport.connect(smtpHost, smtpPort, smtpUser, smtpPw);
1.199 + transport.sendMessage(msg, msg.getAllRecipients());
1.200 + transport.close();
1.201 +
1.202 + Stats.getInstance().mailGatewayed(article.getHeader(Headers.NEWSGROUPS)[0]);
1.203 + Log.msg("MLGateway: Mail " + article.getHeader("Subject")[0]
1.204 + + " was delivered to " + listAddress + ".", true);
1.205 + }
1.206 + }
1.207 +
1.208 + /**
1.209 + * Sets the SENDER header of the given MimeMessage. This might be necessary
1.210 + * for moderated groups that does not allow the "normal" FROM sender.
1.211 + * @param msg
1.212 + * @throws javax.mail.MessagingException
1.213 + */
1.214 + private static void rewriteSenderAddress(MimeMessage msg)
1.215 + throws MessagingException
1.216 + {
1.217 + String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
1.218 +
1.219 + if(mlAddress != null)
1.220 + {
1.221 + msg.setSender(new InternetAddress(mlAddress));
1.222 + }
1.223 + else
1.224 + {
1.225 + throw new MessagingException("Cannot rewrite SENDER header!");
1.226 + }
1.227 + }
1.228 +
1.229 + /**
1.230 + * Sets the FROM header of the given MimeMessage. This might be necessary
1.231 + * for moderated groups that does not allow the "normal" FROM sender.
1.232 + * @param msg
1.233 + * @throws javax.mail.MessagingException
1.234 + */
1.235 + private static void rewriteFromAddress(MimeMessage msg)
1.236 + throws MessagingException
1.237 + {
1.238 + Address[] froms = msg.getFrom();
1.239 + String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
1.240 +
1.241 + if(froms.length > 0 && froms[0] instanceof InternetAddress
1.242 + && mlAddress != null)
1.243 + {
1.244 + InternetAddress from = (InternetAddress)froms[0];
1.245 + from.setAddress(mlAddress);
1.246 + msg.setFrom(from);
1.247 + }
1.248 + else
1.249 + {
1.250 + throw new MessagingException("Cannot rewrite FROM header!");
1.251 + }
1.252 + }
1.253 +
1.254 +}