org/sonews/mlgw/Dispatcher.java
author chris <chris@marvin>
Fri Jun 26 16:48:50 2009 +0200 (2009-06-26)
changeset 1 6fceb66e1ad7
child 3 2fdc9cc89502
permissions -rw-r--r--
Hooray... sonews/0.5.0 final

HG: Enter commit message. Lines beginning with 'HG:' are removed.
HG: Remove all lines to abort the collapse operation.
chris@1
     1
/*
chris@1
     2
 *   SONEWS News Server
chris@1
     3
 *   see AUTHORS for the list of contributors
chris@1
     4
 *
chris@1
     5
 *   This program is free software: you can redistribute it and/or modify
chris@1
     6
 *   it under the terms of the GNU General Public License as published by
chris@1
     7
 *   the Free Software Foundation, either version 3 of the License, or
chris@1
     8
 *   (at your option) any later version.
chris@1
     9
 *
chris@1
    10
 *   This program is distributed in the hope that it will be useful,
chris@1
    11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
chris@1
    12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
chris@1
    13
 *   GNU General Public License for more details.
chris@1
    14
 *
chris@1
    15
 *   You should have received a copy of the GNU General Public License
chris@1
    16
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
chris@1
    17
 */
chris@1
    18
chris@1
    19
package org.sonews.mlgw;
chris@1
    20
chris@1
    21
import java.io.IOException;
chris@1
    22
import org.sonews.daemon.Config;
chris@1
    23
import org.sonews.daemon.storage.Article;
chris@1
    24
import org.sonews.util.io.ArticleInputStream;
chris@1
    25
import org.sonews.daemon.storage.Database;
chris@1
    26
import java.sql.SQLException;
chris@1
    27
import java.util.ArrayList;
chris@1
    28
import java.util.List;
chris@1
    29
import java.util.Properties;
chris@1
    30
import javax.mail.Address;
chris@1
    31
import javax.mail.Authenticator;
chris@1
    32
import javax.mail.Message;
chris@1
    33
import javax.mail.MessagingException;
chris@1
    34
import javax.mail.PasswordAuthentication;
chris@1
    35
import javax.mail.Session;
chris@1
    36
import javax.mail.Transport;
chris@1
    37
import javax.mail.internet.InternetAddress;
chris@1
    38
import javax.mail.internet.MimeMessage;
chris@1
    39
import org.sonews.daemon.storage.Headers;
chris@1
    40
import org.sonews.util.Log;
chris@1
    41
import org.sonews.util.Stats;
chris@1
    42
chris@1
    43
/**
chris@1
    44
 * Dispatches messages from mailing list or newsserver or vice versa.
chris@1
    45
 * @author Christian Lins
chris@1
    46
 * @since sonews/0.5.0
chris@1
    47
 */
chris@1
    48
public class Dispatcher 
chris@1
    49
{
chris@1
    50
chris@1
    51
  static class PasswordAuthenticator extends Authenticator
chris@1
    52
  {
chris@1
    53
    
chris@1
    54
    @Override
chris@1
    55
    public PasswordAuthentication getPasswordAuthentication()
chris@1
    56
    {
chris@1
    57
      final String username = 
chris@1
    58
        Config.getInstance().get(Config.MLSEND_USER, "user");
chris@1
    59
      final String password = 
chris@1
    60
        Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
chris@1
    61
chris@1
    62
      return new PasswordAuthentication(username, password);
chris@1
    63
    }
chris@1
    64
    
chris@1
    65
  }
chris@1
    66
  
chris@1
    67
  /**
chris@1
    68
   * Posts a message that was received from a mailing list to the 
chris@1
    69
   * appropriate newsgroup.
chris@1
    70
   * @param msg
chris@1
    71
   */
chris@1
    72
  public static boolean toGroup(final Message msg)
chris@1
    73
  {
chris@1
    74
    try
chris@1
    75
    {
chris@1
    76
      Address[] to = msg.getAllRecipients(); // includes TO/CC/BCC
chris@1
    77
      if(to == null || to.length <= 0)
chris@1
    78
      {
chris@1
    79
        Log.msg("Skipping message because no receipient!", true);
chris@1
    80
        return false;
chris@1
    81
      }
chris@1
    82
      else
chris@1
    83
      {
chris@1
    84
        boolean posted = false;
chris@1
    85
        for(Address toa : to) // Address can have '<' '>' around
chris@1
    86
        {
chris@1
    87
          if(!(toa instanceof InternetAddress))
chris@1
    88
          {
chris@1
    89
            continue;
chris@1
    90
          }
chris@1
    91
          String group = Database.getInstance()
chris@1
    92
            .getGroupForList((InternetAddress)toa);
chris@1
    93
          if(group != null)
chris@1
    94
          {
chris@1
    95
            Log.msg("Posting to group " + group, true);
chris@1
    96
chris@1
    97
            // Create new Article object
chris@1
    98
            Article article = new Article(msg);
chris@1
    99
            article.setGroup(group);
chris@1
   100
            
chris@1
   101
            // Write article to database
chris@1
   102
            if(!Database.getInstance().isArticleExisting(article.getMessageID()))
chris@1
   103
            {
chris@1
   104
              Database.getInstance().addArticle(article);
chris@1
   105
              Stats.getInstance().mailGatewayed(
chris@1
   106
                article.getHeader(Headers.NEWSGROUPS)[0]);
chris@1
   107
            }
chris@1
   108
            else
chris@1
   109
            {
chris@1
   110
              Log.msg("Article " + article.getMessageID() + " already existing.", true);
chris@1
   111
              // TODO: It may be possible that a ML mail is posted to several
chris@1
   112
              // ML addresses...
chris@1
   113
            }
chris@1
   114
            posted = true;
chris@1
   115
          }
chris@1
   116
          else
chris@1
   117
          {
chris@1
   118
            Log.msg("No group for " + toa, true);
chris@1
   119
          }
chris@1
   120
        } // end for
chris@1
   121
        return posted;
chris@1
   122
      }
chris@1
   123
    }
chris@1
   124
    catch(Exception ex)
chris@1
   125
    {
chris@1
   126
      ex.printStackTrace();
chris@1
   127
      return false;
chris@1
   128
    }
chris@1
   129
  }
chris@1
   130
  
chris@1
   131
  /**
chris@1
   132
   * Mails a message received through NNTP to the appropriate mailing list.
chris@1
   133
   */
chris@1
   134
  public static void toList(Article article)
chris@1
   135
    throws IOException, MessagingException, SQLException
chris@1
   136
  {
chris@1
   137
    // Get mailing lists for the group of this article
chris@1
   138
    List<String> listAddresses = new ArrayList<String>();
chris@1
   139
    String[]     groupnames    = article.getHeader(Headers.NEWSGROUPS)[0].split(",");
chris@1
   140
    
chris@1
   141
    for(String groupname : groupnames)
chris@1
   142
    {
chris@1
   143
      String listAddress = Database.getInstance().getListForGroup(groupname);
chris@1
   144
      if(listAddress != null)
chris@1
   145
      {
chris@1
   146
        listAddresses.add(listAddress);
chris@1
   147
      }
chris@1
   148
    }
chris@1
   149
chris@1
   150
    for(String listAddress : listAddresses)
chris@1
   151
    {
chris@1
   152
      // Compose message and send it via given SMTP-Host
chris@1
   153
      String smtpHost = Config.getInstance().get(Config.MLSEND_HOST, "localhost");
chris@1
   154
      int    smtpPort = Config.getInstance().get(Config.MLSEND_PORT, 25);
chris@1
   155
      String smtpUser = Config.getInstance().get(Config.MLSEND_USER, "user");
chris@1
   156
      String smtpPw   = Config.getInstance().get(Config.MLSEND_PASSWORD, "mysecret");
chris@1
   157
chris@1
   158
      Properties props    = System.getProperties();
chris@1
   159
      props.put("mail.smtp.localhost", 
chris@1
   160
        Config.getInstance().get(Config.HOSTNAME, "localhost"));
chris@1
   161
      props.put("mail.smtp.from",  // Used for MAIL FROM command
chris@1
   162
        Config.getInstance().get(
chris@1
   163
          Config.MLSEND_ADDRESS, article.getHeader(Headers.FROM)[0]));
chris@1
   164
      props.put("mail.smtp.host", smtpHost);
chris@1
   165
      props.put("mail.smtp.port", smtpPort);
chris@1
   166
      props.put("mail.smtp.auth", "true");
chris@1
   167
chris@1
   168
      Address[] address = new Address[1];
chris@1
   169
      address[0] = new InternetAddress(listAddress);
chris@1
   170
chris@1
   171
      ArticleInputStream in = new ArticleInputStream(article);
chris@1
   172
      Session session = Session.getDefaultInstance(props, new PasswordAuthenticator());
chris@1
   173
      MimeMessage msg = new MimeMessage(session, in);
chris@1
   174
      msg.setRecipient(Message.RecipientType.TO, address[0]);
chris@1
   175
      msg.setReplyTo(address);
chris@1
   176
      msg.removeHeader(Headers.NEWSGROUPS);
chris@1
   177
      msg.removeHeader(Headers.PATH);
chris@1
   178
      msg.removeHeader(Headers.LINES);
chris@1
   179
      msg.removeHeader(Headers.BYTES);
chris@1
   180
      
chris@1
   181
      if(Config.getInstance().get(Config.MLSEND_RW_SENDER, false))
chris@1
   182
      {
chris@1
   183
        rewriteSenderAddress(msg); // Set the SENDER address
chris@1
   184
      }
chris@1
   185
      
chris@1
   186
      if(Config.getInstance().get(Config.MLSEND_RW_FROM, false))
chris@1
   187
      {
chris@1
   188
        rewriteFromAddress(msg);   // Set the FROM address
chris@1
   189
      }
chris@1
   190
      
chris@1
   191
      msg.saveChanges();
chris@1
   192
chris@1
   193
      // Send the mail
chris@1
   194
      Transport transport = session.getTransport("smtp");
chris@1
   195
      transport.connect(smtpHost, smtpPort, smtpUser, smtpPw);
chris@1
   196
      transport.sendMessage(msg, msg.getAllRecipients());
chris@1
   197
      transport.close();
chris@1
   198
chris@1
   199
      Stats.getInstance().mailGatewayed(article.getHeader(Headers.NEWSGROUPS)[0]);
chris@1
   200
      Log.msg("MLGateway: Mail " + article.getHeader("Subject")[0] 
chris@1
   201
        + " was delivered to " + listAddress + ".", true);
chris@1
   202
    }
chris@1
   203
  }
chris@1
   204
  
chris@1
   205
  /**
chris@1
   206
   * Sets the SENDER header of the given MimeMessage. This might be necessary
chris@1
   207
   * for moderated groups that does not allow the "normal" FROM sender.
chris@1
   208
   * @param msg
chris@1
   209
   * @throws javax.mail.MessagingException
chris@1
   210
   */
chris@1
   211
  private static void rewriteSenderAddress(MimeMessage msg)
chris@1
   212
    throws MessagingException
chris@1
   213
  {
chris@1
   214
    String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
chris@1
   215
chris@1
   216
    if(mlAddress != null)
chris@1
   217
    {
chris@1
   218
      msg.setSender(new InternetAddress(mlAddress));
chris@1
   219
    }
chris@1
   220
    else
chris@1
   221
    {
chris@1
   222
      throw new MessagingException("Cannot rewrite SENDER header!");
chris@1
   223
    }
chris@1
   224
  }
chris@1
   225
  
chris@1
   226
  /**
chris@1
   227
   * Sets the FROM header of the given MimeMessage. This might be necessary
chris@1
   228
   * for moderated groups that does not allow the "normal" FROM sender.
chris@1
   229
   * @param msg
chris@1
   230
   * @throws javax.mail.MessagingException
chris@1
   231
   */
chris@1
   232
  private static void rewriteFromAddress(MimeMessage msg)
chris@1
   233
    throws MessagingException
chris@1
   234
  {
chris@1
   235
    Address[] froms  = msg.getFrom();
chris@1
   236
    String mlAddress = Config.getInstance().get(Config.MLSEND_ADDRESS, null);
chris@1
   237
chris@1
   238
    if(froms.length > 0 && froms[0] instanceof InternetAddress 
chris@1
   239
      && mlAddress != null)
chris@1
   240
    {
chris@1
   241
      InternetAddress from = (InternetAddress)froms[0];
chris@1
   242
      from.setAddress(mlAddress);
chris@1
   243
      msg.setFrom(from);
chris@1
   244
    }
chris@1
   245
    else
chris@1
   246
    {
chris@1
   247
      throw new MessagingException("Cannot rewrite FROM header!");
chris@1
   248
    }    
chris@1
   249
  }
chris@1
   250
  
chris@1
   251
}