View Javadoc

1   package org.paneris.messageboard.receivemail;
2   
3   import java.net.InetAddress;
4   import java.net.ServerSocket;
5   import java.util.Properties;
6   
7   import org.paneris.jal.model.DBConnectionManager;
8   import org.paneris.jal.model.Log;
9   import org.paneris.util.PropertiesUtils;
10  
11  /**
12   * An SMTP server to handle mail coming in to messageboards.
13   *
14   * It is intended to be invoked from init scripts approximately thus:
15   *
16   * <PRE>
17   *   java org.paneris.messageboard.receivemail.SMTPServer --port 1615 &
18   * </PRE>
19   *
20   * A single server can handle mail for messageboards in several
21   * separate databases; the name of the database to which it should
22   * connect is determined from the recipient address given when the
23   * mail arrives.  The program looks for a `properties' resource under
24   * the name <TT>smtpServer.properties</TT> which specifies the mappings
25   * from domain to database name, in the form
26   *
27   * <PRE>
28   *   org.paneris.messageboard.receivemail.database.DOMAIN=DATABASE
29   * </PRE>
30   *
31   * for example
32   *
33   * <PRE>
34   *   org.paneris.messageboard.receivemail.database.messageboards.x.com=x
35   * </PRE>
36   *
37   * (see also <TT>smtpServer.properties.example</TT>).
38   *
39   * Mail can be funelled into the server either by having it listen on
40   * port 25 in place of sendmail, or by configuring the locally running
41   * MTA to forward appropriately addressed email to the server on
42   * a different port.  
43   *
44   * <B>Snedmail configuration</B>
45   * Edit <TT>sendmail.cf</TT> to define a new mailer.  Where it says
46   *
47   * <PRE>
48   *   Msmtp,             P=[IPC], F=mDFMuX, S=11/31, R=21, E=\r\n, L=990,
49   *                      T=DNS/RFC822/SMTP,
50   *                      A=IPC $h
51   * </PRE>
52   *
53   * insert also
54   *
55   * <PRE>
56   *   Msmtp1615,         P=[IPC], F=mDFMuX, S=11/31, R=21, E=\r\n, L=990,
57   *                      T=DNS/RFC822/SMTP,
58   *                      A=IPC $h 1615
59   * </PRE>
60   *
61   * Then use the standard <TT>mailertable</TT> feature to direct, for
62   * example, all mail to <TT>messageboards.x.com</TT> on to
63   * <TT>smtp1615:x.com</TT>.  You can do this very easily with
64   * <TT>linuxconf</TT>'s <I>Special (domain) routing</I> menu: make an
65   * entry with <I>Destination</I> set to <TT>messageboards.x.com</TT>,
66   * <I>Forwarder</I> set to <TT>x.com</TT>, and <I>Mailer</I> set to
67   * <TT>smtp1615</TT>.  But make sure to hack
68   * <TT>/usr/lib/linuxconf/mailconf/smtpmailer.std.cf</TT> first, as
69   * described above, to get it to define the special mailer in the
70   * <TT>sendmail.cf</TT> it generates.  And of course for every mail
71   * domain which sendmail is configured to forward to the messageboards
72   * server, there should be an entry in <TT>smtpServer.properties</TT>
73   * telling the latter which database to use.
74   *
75   * <B>Qmail configuration</B>
76   * In <tt>...qmail/control/smtproutes</tt> add
77   * <pre>
78   * messageboards.paneris.org:127.0.0.1:1615
79   * </pre>
80   * 
81   * <B>Postfix configuration</B>
82   * See http://www.postfix.org/transport.5.html
83   * 
84   * In <tt>/etc/postfix/main.cf</tt> add
85   * <pre>
86   * transport_maps = hash:/etc/postfix/transport
87   * </pre>
88   * 
89   * In <tt>/etc/postfix/transport</tt> add
90   * <pre>
91   * messageboards.paneris.org :127.0.0.1:1615
92   * </pre>
93   * (I found localhost went to a pipex server)
94   * you could equally use
95   * <pre>
96   * messageboards.paneris.org smtp:127.0.0.1:1615
97   * </pre>
98   *
99   * then run 
100  * <pre>
101  * postmap /etc/postfix/transport
102  * postfix reload
103  * </pre>
104  *
105  * The program takes the following command line arguments:
106  *
107  * <TABLE>
108  *   <TR>
109  *     <TD><TT>--port <I>number</I></TT></TD>
110  *     <TD>the port on which to listen, if not 1615</TD>
111  *   </TR>
112  *   <TR>
113  *     <TD><TT>--properties <I>filename</I></TT></TD>
114  *     <TD>
115  *       the name of a file in <TT>CLASSPATH</TT> containing the
116  *       domain-to-database mappings, if not
117  *       <TT>smtpServer.properties</TT>
118  *     </TD>
119  *   </TR>
120  *   <TR>
121  *     <TD><TT>--log <I>filename</I></TT></TD>
122  *     <TD>
123  *       the name of the log file (defaults to
124  *       <TT>/usr/local/apache/log/messageboard-receivemail.log</TT>
125  *     </TD>
126  *   </TR>
127  * </TABLE>
128  */
129 
130 public class SMTPServer {
131 
132   private static final int portDefault = 1615;
133   private static final String propertiesNameDefault = "smtpServer.properties";
134   private static final String logPathDefault =
135       "/usr/local/apache/logs/messageboard-receivemail.log";
136 
137   private static final String usage =
138       "Usage: ... [--port <port>] [--properties <resource>] [--log <file>]\n" +
139       "       defaults --port " + portDefault + "\n" +
140       "                --properties " + propertiesNameDefault + "\n" +
141       "                --log " + logPathDefault;
142 
143   public static void main(String[] args) {
144 
145     System.out.println("Starting receive mail daemon");
146     Log log = new Log("ReceiveMail", "ReceiveMail Log");
147 
148     int port = portDefault;
149     String propertiesName = propertiesNameDefault;
150     String logPath = null;
151 
152     try {
153       for (int a = 0; a < args.length; ++a) {
154         if (args[a].equals("--port"))
155           port = Integer.parseInt(args[++a]);
156         else if (args[a].equals("--properties"))
157           propertiesName = args[++a];
158         else if (args[a].equals("--log")) {
159           logPath = args[++a];
160           try {
161             log.setTarget(logPath);
162           }
163           catch (Exception e) {
164             System.err.println(e);
165             System.exit(1);
166           }
167         } else throw new Exception();
168       }
169     }
170     catch (Exception e) {
171       log.error(usage);
172       System.err.println(usage);
173       System.exit(1);
174     }
175 
176     try {
177       if (logPath == null) {
178         // not set on command line
179         log.setTarget(logPathDefault);
180       }
181       System.out.println("log:"+logPath);
182 
183       Properties databaseNameOfDomain =
184         PropertiesUtils.fromResource((new SMTPServer()).getClass(),
185                                      propertiesName);
186 
187       DBConnectionManager connMgr = DBConnectionManager.getInstance();
188 
189       ServerSocket serverSocket = new ServerSocket(port);
190       for (;;) {
191         System.out.println("Starting new session");
192         (new SMTPSession("messageboards." +
193            InetAddress.getLocalHost().getHostName(),
194            serverSocket.accept(),
195            connMgr, databaseNameOfDomain,
196            65536, log)).start();
197       }
198     }
199     catch (Exception e) {
200       log.exception(e);
201       e.printStackTrace();
202       System.exit(1);
203     }
204   }
205 }