diff --git a/apps/susimail/src/icons/drive_edit.png b/apps/susimail/src/icons/drive_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..7923fada4bed2af85dfce000bcc9b9ef6793897d Binary files /dev/null and b/apps/susimail/src/icons/drive_edit.png differ diff --git a/apps/susimail/src/src/i2p/susi/webmail/Mail.java b/apps/susimail/src/src/i2p/susi/webmail/Mail.java index 95e0829bfe80c349118d5fce2424ddfaaa41b884..8632ac9c419a5e4bb86d86cd6241599d4ce4461e 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/Mail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/Mail.java @@ -88,6 +88,10 @@ class Mail { error = ""; } + /** + * This may or may not contain the body also. + * @return may be null + */ public synchronized ReadBuffer getHeader() { return header; } @@ -103,6 +107,10 @@ class Mail { return header != null; } + /** + * This contains the header also. + * @return may be null + */ public synchronized ReadBuffer getBody() { return body; } diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java index c3dbd78c3a05690b4b289121e96542d7292c0756..ad665e0b6e3c04257563d028780b75052dd60ea0 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java @@ -116,6 +116,7 @@ public class WebMail extends HttpServlet private static final String LOGOUT = "logout"; private static final String RELOAD = "reload"; private static final String SAVE = "save"; + private static final String SAVE_AS = "saveas"; private static final String REFRESH = "refresh"; private static final String CONFIGURE = "configure"; private static final String NEW = "new"; @@ -1298,6 +1299,33 @@ public class WebMail extends HttpServlet return isRaw; } + + /** + * Process save-as link in message view + * + * @param sessionObject + * @param request + * @return If true, we sent the file or 404, do not send any other response + * @since 0.9.18 + */ + private static boolean processSaveAsLink(SessionObject sessionObject, RequestWrapper request, HttpServletResponse response) + { + String str = request.getParameter(SAVE_AS); + if( str == null ) + return false; + Mail mail = sessionObject.mailCache.getMail( sessionObject.showUIDL, MailCache.FetchMode.ALL ); + if( mail != null ) { + if (sendMailSaveAs(sessionObject, mail, response)) + return true; + } + // error if we get here + sessionObject.error += _("Message not found."); + try { + response.sendError(404, _("Message not found.")); + } catch (IOException ioe) {} + return true; + } + /** * @param hashCode * @return the part or null @@ -1631,6 +1659,10 @@ public class WebMail extends HttpServlet // download or raw view sent, or 404 return; } + if (processSaveAsLink(sessionObject, request, response)) { + // download or sent, or 404 + return; + } // If the last message has just been deleted then // sessionObject.state = STATE_LIST and // sessionObject.showUIDL = null @@ -1790,7 +1822,7 @@ public class WebMail extends HttpServlet name = part.name; else name = "part" + part.hashCode(); - String name2 = name.replace( "\\.", "_" ); + String name2 = sanitizeFilename(name); response.setContentType( "application/zip; name=\"" + name2 + ".zip\"" ); response.addHeader( "Content-Disposition:", "attachment; filename=\"" + name2 + ".zip\"" ); ZipEntry entry = new ZipEntry( name ); @@ -1809,6 +1841,54 @@ public class WebMail extends HttpServlet } return shown; } + + /** + * Send the mail to be saved by the browser + * + * @param sessionObject + * @param response + * @return success + * @since 0.9.18 + */ + private static boolean sendMailSaveAs(SessionObject sessionObject, Mail mail, + HttpServletResponse response) + { + ReadBuffer content = mail.getBody(); + + if(content == null) + return false; + String name = mail.subject != null ? sanitizeFilename(mail.subject) : "message"; + try { + response.setContentType("message/rfc822"); + response.setContentLength(content.length); + // cache-control? + response.addHeader( "Content-Disposition:", "attachment; filename=\"" + name + ".eml\"" ); + response.getOutputStream().write(content.content, content.offset, content.length); + return true; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Convert the UTF-8 to ISO-8859-1 suitable for inclusion in a header. + * This will result in a bunch of ??? for non-Western languages. + * + * @param sessionObject + * @param response + * @return success + * @since 0.9.18 + */ + private static String sanitizeFilename(String name) { + try { + name = new String(name.getBytes("ISO-8859-1"), "ISO-8859-1"); + } catch( UnsupportedEncodingException uee ) {} + // strip control chars? + name = name.replace('"', '_'); + return name; + } + /** * @param sessionObject * @param request @@ -2255,7 +2335,8 @@ public class WebMail extends HttpServlet out.println( button( NEW, _("New") ) + spacer + button( REPLY, _("Reply") ) + button( REPLYALL, _("Reply All") ) + - button( FORWARD, _("Forward") ) + spacer); + button( FORWARD, _("Forward") ) + spacer + + button( SAVE_AS, _("Save As") ) + spacer); if (sessionObject.reallyDelete) out.println(button2(DELETE, _("Delete"))); else diff --git a/installer/resources/themes/susimail/dark/susimail.css b/installer/resources/themes/susimail/dark/susimail.css index a46a0e586f83ea1093ea9bfc459f3853dbb34eb8..0d49e6540c7a42e31b1f9f8bfe4eee80935608a6 100644 --- a/installer/resources/themes/susimail/dark/susimail.css +++ b/installer/resources/themes/susimail/dark/susimail.css @@ -252,6 +252,11 @@ input.configure { min-height: 22px; } +input.saveas { + background: #000 url('/susimail/icons/drive_edit.png') no-repeat 2px center; + min-height: 22px; +} + input[type=file], input.new_upload { background: #000 url('/themes/console/images/add.png') no-repeat 2px center; min-height: 22px; diff --git a/installer/resources/themes/susimail/light/susimail.css b/installer/resources/themes/susimail/light/susimail.css index afb2d082ade774cbf20aae387e062ef8c5e7110d..df3d749fa281410a7243bdc9577ed3af7d0bf9a6 100644 --- a/installer/resources/themes/susimail/light/susimail.css +++ b/installer/resources/themes/susimail/light/susimail.css @@ -274,6 +274,12 @@ input.configure { min-height: 22px; } +input.saveas { + background: #ddf url('/susimail/icons/drive_edit.png') no-repeat 4px center; + padding: 2px 3px 2px 24px; + min-height: 22px; +} + input[type=file], input.new_upload { background: #ddf url('/themes/console/images/add.png') no-repeat 4px center; padding: 2px 3px 2px 24px;