From a16d17c422f5c3fe4e33a1ac545487c8468dc800 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Mon, 24 Nov 2014 18:36:16 +0000 Subject: [PATCH] SusiMail: Add save-as button Fix encoding for filename in Content-Disposition header New icon from Silk, same license as the others --- apps/susimail/src/icons/drive_edit.png | Bin 0 -> 714 bytes .../src/src/i2p/susi/webmail/Mail.java | 8 ++ .../src/src/i2p/susi/webmail/WebMail.java | 85 +++++++++++++++++- .../themes/susimail/dark/susimail.css | 5 ++ .../themes/susimail/light/susimail.css | 6 ++ 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 apps/susimail/src/icons/drive_edit.png 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 GIT binary patch literal 714 zcmV;*0yX`KP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!TuDShR5;6} zQ_pJ?Q4s##Zg#hAezs|oCSr9<#gtNtiuE8>NDEf2-s&}Y^ic31co00R|9}S-FA@q~ z1q;#;e^rr&XrtIjwGF1}(zLNg!zP<;)}57vSQHN(80NjleBU?o-Wz5Z26kf{c4@Zy zBArgpZf|dgO^2@Qs8*{D*EFr+l}d$TEE0)~5{^*|CitW%it(<lE-PuLHMc1U0^;#F zGMUWi)YMeWs=!pd?(uk_C<-J=YJi%7w9aO;aJgKNWtl{;na44fN~J7yuh)xWvG_;1 z)CvI^W8irnZPf+v%TK^N22t90inXoUO_oe1X9Iyim=Xz8S8a~u+>aPq3QK719D!Rt zgstUQNX^{WYy>KmO33H))&)^=tyTkFCPmsiYYBvUG&l|%N8$5Fh)jdi)eU#&9vcya zNr{LEWVU3L%yGY8*w?y(qr)xm^p2ylHVv_jA@g<-Rh>ihotZ|e)GIj=)SdPn!V<=Y z1$g?-qMW+}CVYe7aDrEJsO+D>X32n!2<jjzITQ+65rsE6(l5c?cOK={+u#HpT2Y4b zY#xjD)9|<Ytv_NB&<hYj{le7TbGZB}d;{m8DR;q(2Fl;}Vf{q{#evK4OYH~-gI1L+ z8jU_S`ya3WGHfIfKGqGL`QYt%iFTi8g7@NUJb?$Fg4k5KM#ZMs4BI(O4{wbblb7xx zJ$(hal{rW~L(tdrxpt91HF)*)`~MD8dP&i>504-Zjlga{h}HSj&$6nW`5U+~3(a=n wM2C8~*KZr{mthE%IdwgMapK0pmw!#;FKVxMw^?5FRsaA107*qoM6N<$f)5QvuK)l5 literal 0 HcmV?d00001 diff --git a/apps/susimail/src/src/i2p/susi/webmail/Mail.java b/apps/susimail/src/src/i2p/susi/webmail/Mail.java index 95e0829bfe..8632ac9c41 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 c3dbd78c3a..ad665e0b6e 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 a46a0e586f..0d49e6540c 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 afb2d082ad..df3d749fa2 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; -- GitLab