1.1 --- a/src/org/sonews/mlgw/Dispatcher.java Sun Aug 29 17:43:58 2010 +0200
1.2 +++ b/src/org/sonews/mlgw/Dispatcher.java Tue Jun 07 11:55:22 2011 +0200
1.3 @@ -43,267 +43,233 @@
1.4 * @author Christian Lins
1.5 * @since sonews/0.5.0
1.6 */
1.7 -public class Dispatcher
1.8 +public class Dispatcher
1.9 {
1.10
1.11 - static class PasswordAuthenticator extends Authenticator
1.12 - {
1.13 -
1.14 - @Override
1.15 - public PasswordAuthentication getPasswordAuthentication()
1.16 - {
1.17 - final String username =
1.18 - Config.inst().get(Config.MLSEND_USER, "user");
1.19 - final String password =
1.20 - Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
1.21 + static class PasswordAuthenticator extends Authenticator
1.22 + {
1.23
1.24 - return new PasswordAuthentication(username, password);
1.25 - }
1.26 -
1.27 - }
1.28 + @Override
1.29 + public PasswordAuthentication getPasswordAuthentication()
1.30 + {
1.31 + final String username =
1.32 + Config.inst().get(Config.MLSEND_USER, "user");
1.33 + final String password =
1.34 + Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
1.35
1.36 - /**
1.37 - * Chunks out the email address of the full List-Post header field.
1.38 - * @param listPostValue
1.39 - * @return The matching email address or null
1.40 - */
1.41 - private static String chunkListPost(String listPostValue)
1.42 - {
1.43 - // listPostValue is of form "<mailto:dev@openoffice.org>"
1.44 - Pattern mailPattern = Pattern.compile("(\\w+[-|.])*\\w+@(\\w+.)+\\w+");
1.45 - Matcher mailMatcher = mailPattern.matcher(listPostValue);
1.46 - if(mailMatcher.find())
1.47 - {
1.48 - return listPostValue.substring(mailMatcher.start(), mailMatcher.end());
1.49 - }
1.50 - else
1.51 - {
1.52 - return null;
1.53 - }
1.54 - }
1.55 + return new PasswordAuthentication(username, password);
1.56 + }
1.57 + }
1.58
1.59 - /**
1.60 - * This method inspects the header of the given message, trying
1.61 - * to find the most appropriate recipient.
1.62 - * @param msg
1.63 - * @param fallback If this is false only List-Post and X-List-Post headers
1.64 - * are examined.
1.65 - * @return null or fitting group name for the given message.
1.66 - */
1.67 - private static List<String> getGroupFor(final Message msg, final boolean fallback)
1.68 - throws MessagingException, StorageBackendException
1.69 - {
1.70 - List<String> groups = null;
1.71 + /**
1.72 + * Chunks out the email address of the full List-Post header field.
1.73 + * @param listPostValue
1.74 + * @return The matching email address or null
1.75 + */
1.76 + private static String chunkListPost(String listPostValue)
1.77 + {
1.78 + // listPostValue is of form "<mailto:dev@openoffice.org>"
1.79 + Pattern mailPattern = Pattern.compile("(\\w+[-|.])*\\w+@(\\w+.)+\\w+");
1.80 + Matcher mailMatcher = mailPattern.matcher(listPostValue);
1.81 + if (mailMatcher.find()) {
1.82 + return listPostValue.substring(mailMatcher.start(), mailMatcher.end());
1.83 + } else {
1.84 + return null;
1.85 + }
1.86 + }
1.87
1.88 - // Is there a List-Post header?
1.89 - String[] listPost = msg.getHeader(Headers.LIST_POST);
1.90 - InternetAddress listPostAddr;
1.91 + /**
1.92 + * This method inspects the header of the given message, trying
1.93 + * to find the most appropriate recipient.
1.94 + * @param msg
1.95 + * @param fallback If this is false only List-Post and X-List-Post headers
1.96 + * are examined.
1.97 + * @return null or fitting group name for the given message.
1.98 + */
1.99 + private static List<String> getGroupFor(final Message msg, final boolean fallback)
1.100 + throws MessagingException, StorageBackendException
1.101 + {
1.102 + List<String> groups = null;
1.103
1.104 - if(listPost == null || listPost.length == 0 || "".equals(listPost[0]))
1.105 - {
1.106 - // Is there a X-List-Post header?
1.107 - listPost = msg.getHeader(Headers.X_LIST_POST);
1.108 - }
1.109 + // Is there a List-Post header?
1.110 + String[] listPost = msg.getHeader(Headers.LIST_POST);
1.111 + InternetAddress listPostAddr;
1.112
1.113 - if(listPost != null && listPost.length > 0
1.114 - && !"".equals(listPost[0]) && chunkListPost(listPost[0]) != null)
1.115 - {
1.116 - // listPost[0] is of form "<mailto:dev@openoffice.org>"
1.117 - listPost[0] = chunkListPost(listPost[0]);
1.118 - listPostAddr = new InternetAddress(listPost[0], false);
1.119 - groups = StorageManager.current().getGroupsForList(listPostAddr.getAddress());
1.120 - }
1.121 - else if(fallback)
1.122 - {
1.123 - Log.get().info("Using fallback recipient discovery for: " + msg.getSubject());
1.124 - groups = new ArrayList<String>();
1.125 - // Fallback to TO/CC/BCC addresses
1.126 - Address[] to = msg.getAllRecipients();
1.127 - for(Address toa : to) // Address can have '<' '>' around
1.128 - {
1.129 - if(toa instanceof InternetAddress)
1.130 - {
1.131 - List<String> g = StorageManager.current()
1.132 - .getGroupsForList(((InternetAddress)toa).getAddress());
1.133 - groups.addAll(g);
1.134 - }
1.135 - }
1.136 - }
1.137 -
1.138 - return groups;
1.139 - }
1.140 -
1.141 - /**
1.142 - * Posts a message that was received from a mailing list to the
1.143 - * appropriate newsgroup.
1.144 - * If the message already exists in the storage, this message checks
1.145 - * if it must be posted in an additional group. This can happen for
1.146 - * crosspostings in different mailing lists.
1.147 - * @param msg
1.148 - */
1.149 - public static boolean toGroup(final Message msg)
1.150 - {
1.151 - if(msg == null)
1.152 + if (listPost == null || listPost.length == 0 || "".equals(listPost[0])) {
1.153 + // Is there a X-List-Post header?
1.154 + listPost = msg.getHeader(Headers.X_LIST_POST);
1.155 + }
1.156 +
1.157 + if (listPost != null && listPost.length > 0
1.158 + && !"".equals(listPost[0]) && chunkListPost(listPost[0]) != null) {
1.159 + // listPost[0] is of form "<mailto:dev@openoffice.org>"
1.160 + listPost[0] = chunkListPost(listPost[0]);
1.161 + listPostAddr = new InternetAddress(listPost[0], false);
1.162 + groups = StorageManager.current().getGroupsForList(listPostAddr.getAddress());
1.163 + } else if (fallback) {
1.164 + Log.get().info("Using fallback recipient discovery for: " + msg.getSubject());
1.165 + groups = new ArrayList<String>();
1.166 + // Fallback to TO/CC/BCC addresses
1.167 + Address[] to = msg.getAllRecipients();
1.168 + for (Address toa : to) // Address can have '<' '>' around
1.169 + {
1.170 + if (toa instanceof InternetAddress) {
1.171 + List<String> g = StorageManager.current().getGroupsForList(((InternetAddress) toa).getAddress());
1.172 + groups.addAll(g);
1.173 + }
1.174 + }
1.175 + }
1.176 +
1.177 + return groups;
1.178 + }
1.179 +
1.180 + /**
1.181 + * Posts a message that was received from a mailing list to the
1.182 + * appropriate newsgroup.
1.183 + * If the message already exists in the storage, this message checks
1.184 + * if it must be posted in an additional group. This can happen for
1.185 + * crosspostings in different mailing lists.
1.186 + * @param msg
1.187 + */
1.188 + public static boolean toGroup(final Message msg)
1.189 {
1.190 - throw new IllegalArgumentException("Argument 'msg' must not be null!");
1.191 - }
1.192 + if (msg == null) {
1.193 + throw new IllegalArgumentException("Argument 'msg' must not be null!");
1.194 + }
1.195
1.196 - try
1.197 - {
1.198 - // Create new Article object
1.199 - Article article = new Article(msg);
1.200 - boolean posted = false;
1.201 + try {
1.202 + // Create new Article object
1.203 + Article article = new Article(msg);
1.204 + boolean posted = false;
1.205
1.206 - // Check if this mail is already existing the storage
1.207 - boolean updateReq =
1.208 - StorageManager.current().isArticleExisting(article.getMessageID());
1.209 + // Check if this mail is already existing the storage
1.210 + boolean updateReq =
1.211 + StorageManager.current().isArticleExisting(article.getMessageID());
1.212
1.213 - List<String> newsgroups = getGroupFor(msg, !updateReq);
1.214 - List<String> oldgroups = new ArrayList<String>();
1.215 - if(updateReq)
1.216 - {
1.217 - // Check for duplicate entries of the same group
1.218 - Article oldArticle = StorageManager.current().getArticle(article.getMessageID());
1.219 - if(oldArticle != null)
1.220 - {
1.221 - List<Group> oldGroups = oldArticle.getGroups();
1.222 - for(Group oldGroup : oldGroups)
1.223 - {
1.224 - if(!newsgroups.contains(oldGroup.getName()))
1.225 - {
1.226 - oldgroups.add(oldGroup.getName());
1.227 - }
1.228 - }
1.229 + List<String> newsgroups = getGroupFor(msg, !updateReq);
1.230 + List<String> oldgroups = new ArrayList<String>();
1.231 + if (updateReq) {
1.232 + // Check for duplicate entries of the same group
1.233 + Article oldArticle = StorageManager.current().getArticle(article.getMessageID());
1.234 + if (oldArticle != null) {
1.235 + List<Group> oldGroups = oldArticle.getGroups();
1.236 + for (Group oldGroup : oldGroups) {
1.237 + if (!newsgroups.contains(oldGroup.getName())) {
1.238 + oldgroups.add(oldGroup.getName());
1.239 + }
1.240 + }
1.241 + }
1.242 + }
1.243 +
1.244 + if (newsgroups.size() > 0) {
1.245 + newsgroups.addAll(oldgroups);
1.246 + StringBuilder groups = new StringBuilder();
1.247 + for (int n = 0; n < newsgroups.size(); n++) {
1.248 + groups.append(newsgroups.get(n));
1.249 + if (n + 1 != newsgroups.size()) {
1.250 + groups.append(',');
1.251 + }
1.252 + }
1.253 + Log.get().info("Posting to group " + groups.toString());
1.254 +
1.255 + article.setGroup(groups.toString());
1.256 + //article.removeHeader(Headers.REPLY_TO);
1.257 + //article.removeHeader(Headers.TO);
1.258 +
1.259 + // Write article to database
1.260 + if (updateReq) {
1.261 + Log.get().info("Updating " + article.getMessageID()
1.262 + + " with additional groups");
1.263 + StorageManager.current().delete(article.getMessageID());
1.264 + StorageManager.current().addArticle(article);
1.265 + } else {
1.266 + Log.get().info("Gatewaying " + article.getMessageID() + " to "
1.267 + + article.getHeader(Headers.NEWSGROUPS)[0]);
1.268 + StorageManager.current().addArticle(article);
1.269 + Stats.getInstance().mailGatewayed(
1.270 + article.getHeader(Headers.NEWSGROUPS)[0]);
1.271 + }
1.272 + posted = true;
1.273 + } else {
1.274 + StringBuilder buf = new StringBuilder();
1.275 + for (Address toa : msg.getAllRecipients()) {
1.276 + buf.append(' ');
1.277 + buf.append(toa.toString());
1.278 + }
1.279 + buf.append(" " + article.getHeader(Headers.LIST_POST)[0]);
1.280 + Log.get().warning("No group for" + buf.toString());
1.281 + }
1.282 + return posted;
1.283 + } catch (Exception ex) {
1.284 + ex.printStackTrace();
1.285 + return false;
1.286 }
1.287 - }
1.288 + }
1.289
1.290 - if(newsgroups.size() > 0)
1.291 - {
1.292 - newsgroups.addAll(oldgroups);
1.293 - StringBuilder groups = new StringBuilder();
1.294 - for(int n = 0; n < newsgroups.size(); n++)
1.295 - {
1.296 - groups.append(newsgroups.get(n));
1.297 - if (n + 1 != newsgroups.size())
1.298 - {
1.299 - groups.append(',');
1.300 - }
1.301 - }
1.302 - Log.get().info("Posting to group " + groups.toString());
1.303 + /**
1.304 + * Mails a message received through NNTP to the appropriate mailing list.
1.305 + * This method MAY be called several times by PostCommand for the same
1.306 + * article.
1.307 + */
1.308 + public static void toList(Article article, String group)
1.309 + throws IOException, MessagingException, StorageBackendException
1.310 + {
1.311 + // Get mailing lists for the group of this article
1.312 + List<String> rcptAddresses = StorageManager.current().getListsForGroup(group);
1.313
1.314 - article.setGroup(groups.toString());
1.315 - //article.removeHeader(Headers.REPLY_TO);
1.316 - //article.removeHeader(Headers.TO);
1.317 + if (rcptAddresses == null || rcptAddresses.size() == 0) {
1.318 + Log.get().warning("No ML-address for " + group + " found.");
1.319 + return;
1.320 + }
1.321
1.322 - // Write article to database
1.323 - if(updateReq)
1.324 - {
1.325 - Log.get().info("Updating " + article.getMessageID()
1.326 - + " with additional groups");
1.327 - StorageManager.current().delete(article.getMessageID());
1.328 - StorageManager.current().addArticle(article);
1.329 - }
1.330 - else
1.331 - {
1.332 - Log.get().info("Gatewaying " + article.getMessageID() + " to "
1.333 - + article.getHeader(Headers.NEWSGROUPS)[0]);
1.334 - StorageManager.current().addArticle(article);
1.335 - Stats.getInstance().mailGatewayed(
1.336 - article.getHeader(Headers.NEWSGROUPS)[0]);
1.337 - }
1.338 - posted = true;
1.339 - }
1.340 - else
1.341 - {
1.342 - StringBuilder buf = new StringBuilder();
1.343 - for (Address toa : msg.getAllRecipients())
1.344 - {
1.345 - buf.append(' ');
1.346 - buf.append(toa.toString());
1.347 - }
1.348 - buf.append(" " + article.getHeader(Headers.LIST_POST)[0]);
1.349 - Log.get().warning("No group for" + buf.toString());
1.350 - }
1.351 - return posted;
1.352 - }
1.353 - catch(Exception ex)
1.354 - {
1.355 - ex.printStackTrace();
1.356 - return false;
1.357 - }
1.358 - }
1.359 -
1.360 - /**
1.361 - * Mails a message received through NNTP to the appropriate mailing list.
1.362 - * This method MAY be called several times by PostCommand for the same
1.363 - * article.
1.364 - */
1.365 - public static void toList(Article article, String group)
1.366 - throws IOException, MessagingException, StorageBackendException
1.367 - {
1.368 - // Get mailing lists for the group of this article
1.369 - List<String> rcptAddresses = StorageManager.current().getListsForGroup(group);
1.370 + for (String rcptAddress : rcptAddresses) {
1.371 + // Compose message and send it via given SMTP-Host
1.372 + String smtpHost = Config.inst().get(Config.MLSEND_HOST, "localhost");
1.373 + int smtpPort = Config.inst().get(Config.MLSEND_PORT, 25);
1.374 + String smtpUser = Config.inst().get(Config.MLSEND_USER, "user");
1.375 + String smtpPw = Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
1.376 + String smtpFrom = Config.inst().get(
1.377 + Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]);
1.378
1.379 - if(rcptAddresses == null || rcptAddresses.size() == 0)
1.380 - {
1.381 - Log.get().warning("No ML-address for " + group + " found.");
1.382 - return;
1.383 - }
1.384 + // TODO: Make Article cloneable()
1.385 + article.getMessageID(); // Make sure an ID is existing
1.386 + article.removeHeader(Headers.NEWSGROUPS);
1.387 + article.removeHeader(Headers.PATH);
1.388 + article.removeHeader(Headers.LINES);
1.389 + article.removeHeader(Headers.BYTES);
1.390
1.391 - for(String rcptAddress : rcptAddresses)
1.392 - {
1.393 - // Compose message and send it via given SMTP-Host
1.394 - String smtpHost = Config.inst().get(Config.MLSEND_HOST, "localhost");
1.395 - int smtpPort = Config.inst().get(Config.MLSEND_PORT, 25);
1.396 - String smtpUser = Config.inst().get(Config.MLSEND_USER, "user");
1.397 - String smtpPw = Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
1.398 - String smtpFrom = Config.inst().get(
1.399 - Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]);
1.400 + article.setHeader("To", rcptAddress);
1.401 + //article.setHeader("Reply-To", listAddress);
1.402
1.403 - // TODO: Make Article cloneable()
1.404 - article.getMessageID(); // Make sure an ID is existing
1.405 - article.removeHeader(Headers.NEWSGROUPS);
1.406 - article.removeHeader(Headers.PATH);
1.407 - article.removeHeader(Headers.LINES);
1.408 - article.removeHeader(Headers.BYTES);
1.409 + if (Config.inst().get(Config.MLSEND_RW_SENDER, false)) {
1.410 + rewriteSenderAddress(article); // Set the SENDER address
1.411 + }
1.412
1.413 - article.setHeader("To", rcptAddress);
1.414 - //article.setHeader("Reply-To", listAddress);
1.415 + SMTPTransport smtpTransport = new SMTPTransport(smtpHost, smtpPort);
1.416 + smtpTransport.send(article, smtpFrom, rcptAddress);
1.417 + smtpTransport.close();
1.418
1.419 - if (Config.inst().get(Config.MLSEND_RW_SENDER, false))
1.420 - {
1.421 - rewriteSenderAddress(article); // Set the SENDER address
1.422 - }
1.423 + Stats.getInstance().mailGatewayed(group);
1.424 + Log.get().info("MLGateway: Mail " + article.getHeader("Subject")[0]
1.425 + + " was delivered to " + rcptAddress + ".");
1.426 + }
1.427 + }
1.428
1.429 - SMTPTransport smtpTransport = new SMTPTransport(smtpHost, smtpPort);
1.430 - smtpTransport.send(article, smtpFrom, rcptAddress);
1.431 - smtpTransport.close();
1.432 + /**
1.433 + * Sets the SENDER header of the given MimeMessage. This might be necessary
1.434 + * for moderated groups that does not allow the "normal" FROM sender.
1.435 + * @param msg
1.436 + * @throws javax.mail.MessagingException
1.437 + */
1.438 + private static void rewriteSenderAddress(Article msg)
1.439 + throws MessagingException
1.440 + {
1.441 + String mlAddress = Config.inst().get(Config.MLSEND_ADDRESS, null);
1.442
1.443 - Stats.getInstance().mailGatewayed(group);
1.444 - Log.get().info("MLGateway: Mail " + article.getHeader("Subject")[0]
1.445 - + " was delivered to " + rcptAddress + ".");
1.446 - }
1.447 - }
1.448 -
1.449 - /**
1.450 - * Sets the SENDER header of the given MimeMessage. This might be necessary
1.451 - * for moderated groups that does not allow the "normal" FROM sender.
1.452 - * @param msg
1.453 - * @throws javax.mail.MessagingException
1.454 - */
1.455 - private static void rewriteSenderAddress(Article msg)
1.456 - throws MessagingException
1.457 - {
1.458 - String mlAddress = Config.inst().get(Config.MLSEND_ADDRESS, null);
1.459 -
1.460 - if(mlAddress != null)
1.461 - {
1.462 - msg.setHeader(Headers.SENDER, mlAddress);
1.463 - }
1.464 - else
1.465 - {
1.466 - throw new MessagingException("Cannot rewrite SENDER header!");
1.467 - }
1.468 - }
1.469 -
1.470 + if (mlAddress != null) {
1.471 + msg.setHeader(Headers.SENDER, mlAddress);
1.472 + } else {
1.473 + throw new MessagingException("Cannot rewrite SENDER header!");
1.474 + }
1.475 + }
1.476 }