org/sonews/mlgw/Dispatcher.java
changeset 35 ed84c8bdd87b
parent 34 9f0b95aafaa3
child 36 c404a87db5b7
     1.1 --- a/org/sonews/mlgw/Dispatcher.java	Sun Aug 29 17:04:25 2010 +0200
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,301 +0,0 @@
     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 java.util.ArrayList;
    1.26 -import java.util.List;
    1.27 -import java.util.regex.Matcher;
    1.28 -import java.util.regex.Pattern;
    1.29 -import javax.mail.Address;
    1.30 -import javax.mail.Authenticator;
    1.31 -import javax.mail.Message;
    1.32 -import javax.mail.MessagingException;
    1.33 -import javax.mail.PasswordAuthentication;
    1.34 -import javax.mail.internet.InternetAddress;
    1.35 -import org.sonews.config.Config;
    1.36 -import org.sonews.storage.Article;
    1.37 -import org.sonews.storage.Group;
    1.38 -import org.sonews.storage.Headers;
    1.39 -import org.sonews.storage.StorageBackendException;
    1.40 -import org.sonews.storage.StorageManager;
    1.41 -import org.sonews.util.Log;
    1.42 -import org.sonews.util.Stats;
    1.43 -
    1.44 -/**
    1.45 - * Dispatches messages from mailing list to newsserver or vice versa.
    1.46 - * @author Christian Lins
    1.47 - * @since sonews/0.5.0
    1.48 - */
    1.49 -public class Dispatcher 
    1.50 -{
    1.51 -
    1.52 -  static class PasswordAuthenticator extends Authenticator
    1.53 -  {
    1.54 -    
    1.55 -    @Override
    1.56 -    public PasswordAuthentication getPasswordAuthentication()
    1.57 -    {
    1.58 -      final String username = 
    1.59 -        Config.inst().get(Config.MLSEND_USER, "user");
    1.60 -      final String password = 
    1.61 -        Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
    1.62 -
    1.63 -      return new PasswordAuthentication(username, password);
    1.64 -    }
    1.65 -    
    1.66 -  }
    1.67 -
    1.68 -  /**
    1.69 -   * Chunks out the email address of the full List-Post header field.
    1.70 -   * @param listPostValue
    1.71 -   * @return The matching email address or null
    1.72 -   */
    1.73 -  private static String chunkListPost(String listPostValue)
    1.74 -  {
    1.75 -    // listPostValue is of form "<mailto:dev@openoffice.org>"
    1.76 -    Pattern mailPattern = Pattern.compile("(\\w+[-|.])*\\w+@(\\w+.)+\\w+");
    1.77 -    Matcher mailMatcher = mailPattern.matcher(listPostValue);
    1.78 -    if(mailMatcher.find())
    1.79 -    {
    1.80 -      return listPostValue.substring(mailMatcher.start(), mailMatcher.end());
    1.81 -    }
    1.82 -    else
    1.83 -    {
    1.84 -      return null;
    1.85 -    }
    1.86 -  }
    1.87 -
    1.88 -  /**
    1.89 -   * This method inspects the header of the given message, trying
    1.90 -   * to find the most appropriate recipient.
    1.91 -   * @param msg
    1.92 -   * @param fallback If this is false only List-Post and X-List-Post headers
    1.93 -   *                 are examined.
    1.94 -   * @return null or fitting group name for the given message.
    1.95 -   */
    1.96 -  private static List<String> getGroupFor(final Message msg, final boolean fallback)
    1.97 -    throws MessagingException, StorageBackendException
    1.98 -  {
    1.99 -    List<String> groups = null;
   1.100 -
   1.101 -    // Is there a List-Post header?
   1.102 -    String[]        listPost = msg.getHeader(Headers.LIST_POST);
   1.103 -    InternetAddress listPostAddr;
   1.104 -
   1.105 -    if(listPost == null || listPost.length == 0 || "".equals(listPost[0]))
   1.106 -    {
   1.107 -      // Is there a X-List-Post header?
   1.108 -      listPost = msg.getHeader(Headers.X_LIST_POST);
   1.109 -    }
   1.110 -
   1.111 -    if(listPost != null && listPost.length > 0 
   1.112 -      && !"".equals(listPost[0]) && chunkListPost(listPost[0]) != null)
   1.113 -    {
   1.114 -      // listPost[0] is of form "<mailto:dev@openoffice.org>"
   1.115 -      listPost[0]  = chunkListPost(listPost[0]);
   1.116 -      listPostAddr = new InternetAddress(listPost[0], false);
   1.117 -      groups = StorageManager.current().getGroupsForList(listPostAddr.getAddress());
   1.118 -    }
   1.119 -    else if(fallback)
   1.120 -    {
   1.121 -      Log.get().info("Using fallback recipient discovery for: " + msg.getSubject());
   1.122 -      groups = new ArrayList<String>();
   1.123 -      // Fallback to TO/CC/BCC addresses
   1.124 -      Address[] to = msg.getAllRecipients();
   1.125 -      for(Address toa : to) // Address can have '<' '>' around
   1.126 -      {
   1.127 -        if(toa instanceof InternetAddress)
   1.128 -        {
   1.129 -          List<String> g = StorageManager.current()
   1.130 -            .getGroupsForList(((InternetAddress)toa).getAddress());
   1.131 -          groups.addAll(g);
   1.132 -        }
   1.133 -      }
   1.134 -    }
   1.135 -    
   1.136 -    return groups;
   1.137 -  }
   1.138 -  
   1.139 -  /**
   1.140 -   * Posts a message that was received from a mailing list to the 
   1.141 -   * appropriate newsgroup.
   1.142 -   * If the message already exists in the storage, this message checks
   1.143 -   * if it must be posted in an additional group. This can happen for
   1.144 -   * crosspostings in different mailing lists.
   1.145 -   * @param msg
   1.146 -   */
   1.147 -  public static boolean toGroup(final Message msg)
   1.148 -  {
   1.149 -    try
   1.150 -    {
   1.151 -      // Create new Article object
   1.152 -      Article article = new Article(msg);
   1.153 -      boolean posted  = false;
   1.154 -
   1.155 -      // Check if this mail is already existing the storage
   1.156 -      boolean updateReq = 
   1.157 -        StorageManager.current().isArticleExisting(article.getMessageID());
   1.158 -
   1.159 -      List<String> newsgroups = getGroupFor(msg, !updateReq);
   1.160 -      List<String> oldgroups  = new ArrayList<String>();
   1.161 -      if(updateReq)
   1.162 -      {
   1.163 -        // Check for duplicate entries of the same group
   1.164 -        Article oldArticle = StorageManager.current().getArticle(article.getMessageID());
   1.165 -        List<Group> oldGroups = oldArticle.getGroups();
   1.166 -        for(Group oldGroup : oldGroups)
   1.167 -        {
   1.168 -          if(!newsgroups.contains(oldGroup.getName()))
   1.169 -          {
   1.170 -            oldgroups.add(oldGroup.getName());
   1.171 -          }
   1.172 -        }
   1.173 -      }
   1.174 -
   1.175 -      if(newsgroups.size() > 0)
   1.176 -      {
   1.177 -        newsgroups.addAll(oldgroups);
   1.178 -        StringBuilder groups = new StringBuilder();
   1.179 -        for(int n = 0; n < newsgroups.size(); n++)
   1.180 -        {
   1.181 -          groups.append(newsgroups.get(n));
   1.182 -          if (n + 1 != newsgroups.size())
   1.183 -          {
   1.184 -            groups.append(',');
   1.185 -          }
   1.186 -        }
   1.187 -        Log.get().info("Posting to group " + groups.toString());
   1.188 -
   1.189 -        article.setGroup(groups.toString());
   1.190 -        //article.removeHeader(Headers.REPLY_TO);
   1.191 -        //article.removeHeader(Headers.TO);
   1.192 -
   1.193 -        // Write article to database
   1.194 -        if(updateReq)
   1.195 -        {
   1.196 -          Log.get().info("Updating " + article.getMessageID()
   1.197 -            + " with additional groups");
   1.198 -          StorageManager.current().delete(article.getMessageID());
   1.199 -          StorageManager.current().addArticle(article);
   1.200 -        }
   1.201 -        else
   1.202 -        {
   1.203 -          Log.get().info("Gatewaying " + article.getMessageID() + " to "
   1.204 -            + article.getHeader(Headers.NEWSGROUPS)[0]);
   1.205 -          StorageManager.current().addArticle(article);
   1.206 -          Stats.getInstance().mailGatewayed(
   1.207 -            article.getHeader(Headers.NEWSGROUPS)[0]);
   1.208 -        }
   1.209 -        posted = true;
   1.210 -      }
   1.211 -      else
   1.212 -      {
   1.213 -        StringBuilder buf = new StringBuilder();
   1.214 -        for (Address toa : msg.getAllRecipients())
   1.215 -        {
   1.216 -          buf.append(' ');
   1.217 -          buf.append(toa.toString());
   1.218 -        }
   1.219 -        buf.append(" " + article.getHeader(Headers.LIST_POST)[0]);
   1.220 -        Log.get().warning("No group for" + buf.toString());
   1.221 -      }
   1.222 -      return posted;
   1.223 -    }
   1.224 -    catch(Exception ex)
   1.225 -    {
   1.226 -      ex.printStackTrace();
   1.227 -      return false;
   1.228 -    }
   1.229 -  }
   1.230 -  
   1.231 -  /**
   1.232 -   * Mails a message received through NNTP to the appropriate mailing list.
   1.233 -   * This method MAY be called several times by PostCommand for the same
   1.234 -   * article.
   1.235 -   */
   1.236 -  public static void toList(Article article, String group)
   1.237 -    throws IOException, MessagingException, StorageBackendException
   1.238 -  {
   1.239 -    // Get mailing lists for the group of this article
   1.240 -    List<String> rcptAddresses = StorageManager.current().getListsForGroup(group);
   1.241 -
   1.242 -    if(rcptAddresses == null || rcptAddresses.size() == 0)
   1.243 -    {
   1.244 -      Log.get().warning("No ML-address for " + group + " found.");
   1.245 -      return;
   1.246 -    }
   1.247 -
   1.248 -    for(String rcptAddress : rcptAddresses)
   1.249 -    {
   1.250 -      // Compose message and send it via given SMTP-Host
   1.251 -      String smtpHost = Config.inst().get(Config.MLSEND_HOST, "localhost");
   1.252 -      int smtpPort = Config.inst().get(Config.MLSEND_PORT, 25);
   1.253 -      String smtpUser = Config.inst().get(Config.MLSEND_USER, "user");
   1.254 -      String smtpPw = Config.inst().get(Config.MLSEND_PASSWORD, "mysecret");
   1.255 -      String smtpFrom = Config.inst().get(
   1.256 -        Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]);
   1.257 -
   1.258 -      // TODO: Make Article cloneable()
   1.259 -      article.getMessageID(); // Make sure an ID is existing
   1.260 -      article.removeHeader(Headers.NEWSGROUPS);
   1.261 -      article.removeHeader(Headers.PATH);
   1.262 -      article.removeHeader(Headers.LINES);
   1.263 -      article.removeHeader(Headers.BYTES);
   1.264 -
   1.265 -      article.setHeader("To", rcptAddress);
   1.266 -      //article.setHeader("Reply-To", listAddress);
   1.267 -
   1.268 -      if (Config.inst().get(Config.MLSEND_RW_SENDER, false))
   1.269 -      {
   1.270 -        rewriteSenderAddress(article); // Set the SENDER address
   1.271 -      }
   1.272 -
   1.273 -      SMTPTransport smtpTransport = new SMTPTransport(smtpHost, smtpPort);
   1.274 -      smtpTransport.send(article, smtpFrom, rcptAddress);
   1.275 -      smtpTransport.close();
   1.276 -
   1.277 -      Stats.getInstance().mailGatewayed(group);
   1.278 -      Log.get().info("MLGateway: Mail " + article.getHeader("Subject")[0]
   1.279 -        + " was delivered to " + rcptAddress + ".");
   1.280 -    }
   1.281 -  }
   1.282 -  
   1.283 -  /**
   1.284 -   * Sets the SENDER header of the given MimeMessage. This might be necessary
   1.285 -   * for moderated groups that does not allow the "normal" FROM sender.
   1.286 -   * @param msg
   1.287 -   * @throws javax.mail.MessagingException
   1.288 -   */
   1.289 -  private static void rewriteSenderAddress(Article msg)
   1.290 -    throws MessagingException
   1.291 -  {
   1.292 -    String mlAddress = Config.inst().get(Config.MLSEND_ADDRESS, null);
   1.293 -
   1.294 -    if(mlAddress != null)
   1.295 -    {
   1.296 -      msg.setHeader(Headers.SENDER, mlAddress);
   1.297 -    }
   1.298 -    else
   1.299 -    {
   1.300 -      throw new MessagingException("Cannot rewrite SENDER header!");
   1.301 -    }
   1.302 -  }
   1.303 -  
   1.304 -}