1 /***
2 *
3 */
4 package net.sf.mailservice.mailhttp;
5
6 import java.io.ByteArrayOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.OutputStream;
10 import java.io.PrintStream;
11 import java.net.HttpURLConnection;
12 import java.net.MalformedURLException;
13 import java.net.URL;
14 import java.net.URLConnection;
15 import java.net.URLDecoder;
16 import java.util.Enumeration;
17
18 import javax.mail.Address;
19 import javax.mail.Header;
20 import javax.mail.Message;
21 import javax.mail.MessagingException;
22 import javax.mail.Session;
23 import javax.mail.Transport;
24 import javax.mail.URLName;
25 import javax.mail.event.TransportEvent;
26 import javax.mail.internet.InternetAddress;
27 import javax.mail.internet.MimeMessage;
28 import javax.mail.internet.MimeUtility;
29
30 /***
31 * An HTTP protocol provider for the JavaMail API that provides access to an
32 * SMTP server via HTTP or HTTPS.
33 *
34 * <table>
35 * <tr>
36 * <td>mail.http.reportsuccess</td>
37 * <td>Throw a HttpTransportSuccessException on success.</td>
38 * </tr>
39 * <tr>
40 * <td>mail.http.url</td>
41 * <td>URL of the restful mail service.</td>
42 * </tr>
43 * </table>
44 *
45 * If a username and password is added to the URL, it will be added to the
46 * request using basic authentication.
47 *
48 * Both http and https URLs are supported.
49 *
50 * @author drewyrr
51 * @version $Id: $
52 */
53 public class HttpTransport extends Transport {
54
55 private PrintStream out;
56 private MimeMessage message;
57 private Address[] addresses;
58 private String name;
59 private boolean reportSuccess;
60 private URLConnection conn;
61
62 /***
63 * Create a new transport.
64 *
65 * @param session
66 * a {@link javax.mail.Session} object.
67 * @param urlname
68 * a {@link javax.mail.URLName} object.
69 */
70 public HttpTransport(Session session, URLName urlname) {
71 super(session, urlname);
72 String name;
73 if (urlname != null) {
74 name = urlname.getProtocol();
75 } else {
76 name = "http";
77 }
78 this.name = name;
79
80 out = session.getDebugOut();
81
82 String reportSuccessString = session.getProperty("mail." + name
83 + ".reportsuccess");
84 reportSuccess = reportSuccessString != null
85 && reportSuccessString.equalsIgnoreCase("true");
86
87 }
88
89 /***
90 * {@inheritDoc}
91 *
92 * Send the given message.
93 * @see javax.mail.Transport#sendMessage(javax.mail.Message,
94 * javax.mail.Address[])
95 */
96 @Override
97 public void sendMessage(Message message, Address[] addresses)
98 throws MessagingException {
99
100 String location;
101
102 if (!(message instanceof MimeMessage)) {
103 if (debug) {
104 out.println("DEBUG HTTP: Can only send RFC822 msgs");
105 }
106 throw new MessagingException("HTTP can only send RFC822 messages");
107 }
108 for (int i = 0; i < addresses.length; i++) {
109 if (!(addresses[i] instanceof InternetAddress)) {
110 throw new MessagingException(addresses[i]
111 + " is not an InternetAddress");
112 }
113 }
114
115 this.message = (MimeMessage) message;
116 this.addresses = addresses;
117 Address[] empty = new Address[0];
118
119 try {
120 Enumeration<?> enumeration = message.getAllHeaders();
121 while (enumeration.hasMoreElements()) {
122 Header header = (Header) enumeration.nextElement();
123 if (debug) {
124 out.println("DEBUG HTTP: Header " + header.getName() + ":"
125 + MimeUtility.unfold(header.getValue()));
126 }
127 conn.addRequestProperty(header.getName(), MimeUtility
128 .unfold(header.getValue()));
129 }
130
131
132
133
134 InputStream is = this.message.getInputStream();
135 OutputStream os = conn.getOutputStream();
136 int c;
137 while ((c = is.read()) != -1) {
138 os.write(c);
139 }
140
141 if (debug) {
142 out.print("DEBUG HTTP: Response: ");
143 }
144 is = conn.getInputStream();
145 while ((c = is.read()) != -1) {
146 if (debug) {
147 out.write(c);
148 }
149 }
150 is.close();
151 if (debug) {
152 out.println();
153 }
154
155 location = conn.getHeaderField("Location");
156 this.message.addHeader("Location", location);
157
158 notifyTransportListeners(TransportEvent.MESSAGE_DELIVERED,
159 this.addresses, empty, empty, this.message);
160 } catch (MessagingException mex) {
161 if (debug)
162 mex.printStackTrace(out);
163 notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED,
164 empty, this.addresses, empty, this.message);
165
166 throw mex;
167 } catch (IOException ioe) {
168 int response = 0;
169 if (debug)
170 ioe.printStackTrace(out);
171 try {
172 if (conn instanceof HttpURLConnection) {
173 response = ((HttpURLConnection) conn).getResponseCode();
174 InputStream es = ((HttpURLConnection) conn)
175 .getErrorStream();
176 int c;
177 while ((c = es.read()) != -1) {
178 if (debug) {
179 out.write(c);
180 }
181 }
182 es.close();
183 if (debug) {
184 out.println();
185 }
186 }
187 } catch (IOException e) {
188
189 }
190 notifyTransportListeners(TransportEvent.MESSAGE_NOT_DELIVERED,
191 empty, this.addresses, empty, this.message);
192
193 throw new MessagingException(
194 "IOException while sending message, with HTTP response code "
195 + response, ioe);
196 } finally {
197
198 this.addresses = null;
199 this.message = null;
200 }
201
202 if (reportSuccess) {
203 throw new HttpTransportSuccessException(location);
204 }
205
206 }
207
208 /***
209 * {@inheritDoc}
210 *
211 * Set up the connection to the mail service.
212 * @see javax.mail.Service#protocolConnect(java.lang.String, int,
213 * java.lang.String, java.lang.String)
214 */
215 @Override
216 protected boolean protocolConnect(String host, int port, String user,
217 String password) throws MessagingException {
218
219 URL url;
220 String p = session.getProperty("mail." + name + ".url");
221 try {
222 if (p != null) {
223 url = new URL(p);
224 } else {
225 url = new URL(name + "://localhost/");
226 }
227 } catch (MalformedURLException e) {
228 throw new MessagingException(e.getMessage());
229 }
230
231 try {
232 conn = url.openConnection();
233 conn.setDoOutput(true);
234 if (conn instanceof HttpURLConnection) {
235 HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;
236 httpUrlConnection.setInstanceFollowRedirects(false);
237 }
238
239
240
241
242
243 String authority = url.getAuthority();
244 int offset;
245 if (user != null && password != null) {
246 String userpassword = user.concat(":").concat(password);
247 ByteArrayOutputStream baos = new ByteArrayOutputStream();
248 OutputStream stream = MimeUtility.encode(baos, "base64");
249 stream.write(userpassword.getBytes());
250
251 conn.setRequestProperty("Authorization", "Basic "
252 + baos.toString("UTF-8"));
253 } else if ((offset = authority.indexOf('@')) != -1) {
254 String userpassword = URLDecoder.decode(authority.substring(0,
255 offset), "UTF-8");
256 ByteArrayOutputStream baos = new ByteArrayOutputStream();
257 OutputStream stream = MimeUtility.encode(baos, "base64");
258 stream.write(userpassword.getBytes());
259
260 conn.setRequestProperty("Authorization", "Basic "
261 + baos.toString("UTF-8"));
262 }
263
264 } catch (MalformedURLException e) {
265 throw new MessagingException(e.getLocalizedMessage());
266 } catch (IOException e) {
267 throw new MessagingException(e.getLocalizedMessage());
268 }
269
270 return true;
271 }
272
273 }