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 }