From c2dab16c8c57202952b3824d7a32e5b55cebb4ff Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Fri, 25 Apr 2014 03:42:18 +0000
Subject: [PATCH]  * SusiMail:    - Add icons for attachments and spam     
 (from Silk icons, same license as others)    - Add checks for POST for XSS
 prevention

---
 apps/susimail/build.xml                       |   4 ++
 apps/susimail/src/icons/attach.png            | Bin 0 -> 391 bytes
 apps/susimail/src/icons/flag_red.png          | Bin 0 -> 665 bytes
 .../src/src/i2p/susi/webmail/Mail.java        |  14 +++++
 .../src/src/i2p/susi/webmail/WebMail.java     |  52 ++++++++++++------
 5 files changed, 52 insertions(+), 18 deletions(-)
 create mode 100644 apps/susimail/src/icons/attach.png
 create mode 100644 apps/susimail/src/icons/flag_red.png

diff --git a/apps/susimail/build.xml b/apps/susimail/build.xml
index 4c79fdfd2a..bb80ea2744 100644
--- a/apps/susimail/build.xml
+++ b/apps/susimail/build.xml
@@ -62,6 +62,10 @@
         <!-- set if unset -->
         <property name="workspace.changes.tr" value="" />
         <copy file="src/susimail.properties" todir="src/WEB-INF/classes" />
+        <mkdir dir="src/WEB-INF/classes/icons" />
+        <copy todir="src/WEB-INF/classes/icons" >
+            <fileset dir="src/icons" />
+        </copy>	
         <war destfile="susimail.war" webxml="src/WEB-INF/web.xml"
              basedir="src/" excludes="WEB-INF/web.xml LICENSE src/**/*">
             <manifest>
diff --git a/apps/susimail/src/icons/attach.png b/apps/susimail/src/icons/attach.png
new file mode 100644
index 0000000000000000000000000000000000000000..ea897cc9f18ca49aa0f30bad4e6b67e4afc7f498
GIT binary patch
literal 391
zcmV;20eJq2P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz8A(JzR4C75
z_|JeJVi8&@J?G_=Q{6UAhFBFWR-FBE()F%K4O{#E=ha~-SR_63{=|(P7wdxlGvrt#
ze?wC+Uu4F;{>`oHYyCmI1nr3DC<^9@PyNudrDc9~P$75b!T6T2tv<*K=EzTZ+r6P_
zRz+%oP}<Shj^HWYH{C?x3TCTLdeSw&VS0I79%ss}n699Oo{wB5;l7xuIPpQpjJobJ
z?;OtLo00Vai#%Sr%EQB9hI;?|*5$Q~#cQ&zCp?R2@L%BZ#)S_lpnBX}9#u<#IPslf
zF+MZhZ@UPggk+Om#mfRw5GPpGd$HS1XEC&(F6YkMnzAKEHOSiYvg<u387y&;%p2(y
laNgsoYo4P35s^ir0sur(`Xw3qNKXI&002ovPDHLkV1i2Hu=D@`

literal 0
HcmV?d00001

diff --git a/apps/susimail/src/icons/flag_red.png b/apps/susimail/src/icons/flag_red.png
new file mode 100644
index 0000000000000000000000000000000000000000..e8a602da7b17a323b2c9afe3d8aac62cb717a0b8
GIT binary patch
literal 665
zcmV;K0%rY*P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!D@jB_R5;6}
z(_ctaVHn48=?_s3f-WosEn!=hrIfCmq!*2X3c=87keLKw7)S&`QATB38G}LE6z5c?
zhRtDW{wcJWxH2s>W2MxECPn{*ELdZ1op0xyVpxzDdhz3h^YVPo^S(T97!Wp}{CC5s
zOO0&MCbYN{*S_u5sKy(U<JzwtO|o6lM<M2pnBB7ipQ6Ks>Fm7-Lr)M|odnZ1F`|tp
z;QLC~<t;KI1IE;?3%s#Qn!M`8(_ZBwyfI>;7ZS9V!0QqC_yL9nVW1CJTMZN4M(R$+
zOTZBsFr_4h`&3JNv0I_O8fwI~`z}0v3|$@I8UFpf@&;uE8s7DoF&~bRfJhmzX*a6<
zs}(O~Kx~<V8Blx?>cpZxH}pS*S{qZRPWYW?G`zW8AQcn3#1@S*BcNV6f!zi<S&(}G
zu3Z90Jv<j%@9Gr0s$itFWXfgQ&RA#R-@stPDuZA#f5T7+dD(C*2TTTNcEI=;^xTJg
z?F^Tf^UA)TzUw<Bz!L(#tXH&(e+bI0XYPWcbI^1P+%AGQtABn!l=Z`}PY<~Aa%7<S
ze2N4Vg#ce{c)wsRg@#%&c7%>r{5lPjYZSt>eR~E27PJ0+es0y~s0ch&nN;M*NkCc%
zXiQ#beHkC&om4IpK8qPut?)aNVjs<%39&#|d3=N1!OZi|I!ONj#Vr@M%?lVEC`+Fg
zAQwL{?FfzVoB-$9WC=Ju7r^r86-w*!nR~wgLM67#gs;7-00000NkvXXu0mjfgI^=`

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 0d3c231276..ab1acb6211 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/Mail.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/Mail.java
@@ -70,6 +70,7 @@ class Mail {
 	private MailPart part;
 	String[] to, cc;        // addresses only, enclosed by <>
 	private boolean isNew, isSpam;
+	public String contentType;
 
 	public String error;
 
@@ -154,6 +155,14 @@ class Mail {
 		this.isNew = isNew;
 	}
 
+	public boolean hasAttachment() {
+		// this isn't right but good enough to start
+		// if part != null query parts instead?
+		return contentType != null &&
+			!contentType.contains("text/plain") &&
+			!contentType.contains("multipart/alternative");
+	}
+
 	/**
 	 * 
 	 * @param address E-mail address to be validated
@@ -348,6 +357,11 @@ class Mail {
 						} else if(line.equals( "X-Spam-Flag: YES" )) {
 							// TODO trust.spam.headers config
 							isSpam = true;
+						} else if(line.toLowerCase(Locale.US).startsWith("content-type:" )) {
+							// this is duplicated in MailPart but
+							// we want to know if we have attachments, even if
+							// we haven't fetched the body
+							contentType = line.substring(13).trim();
 						}
 					}
 				}
diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
index babeffbcf5..af8a06b47a 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
@@ -399,7 +399,7 @@ public class WebMail extends HttpServlet
 			MailCache mc = mailCache;
 			Folder<String> f = folder;
 			if (mc != null && f != null) {
-				if (mc.getMail(true)) {
+				if (MailCache.FETCH_HEADER) {
 					String[] uidls = mc.getUIDLs();
 					f.setElements(uidls);
 				}
@@ -702,7 +702,7 @@ public class WebMail extends HttpServlet
 						if (!offline) {
 							// prime the cache, request all headers at once
 							// otherwise they are pulled one at a time by sortBy() below
-							mc.getMail(true);
+							mc.getMail(MailCache.FETCH_HEADER);
 						}
 						// get through cache so we have the disk-only ones too
 						String[] uidls = mc.getUIDLs();
@@ -767,25 +767,27 @@ public class WebMail extends HttpServlet
 	}
 	/**
 	 * Process all buttons, which possibly change internal state.
+	 * Also processes ?show=x for a GET
 	 * 
 	 * @param sessionObject
 	 * @param request
+	 * @param isPOST disallow button pushes if false
 	 */
-	private static void processStateChangeButtons(SessionObject sessionObject, RequestWrapper request )
+	private static void processStateChangeButtons(SessionObject sessionObject, RequestWrapper request, boolean isPOST )
 	{
 		/*
 		 * LOGIN/LOGOUT
 		 */
-		if( sessionObject.state == STATE_AUTH )
+		if( sessionObject.state == STATE_AUTH && isPOST )
 			processLogin( sessionObject, request );
 
-		if( sessionObject.state != STATE_AUTH )
+		if( sessionObject.state != STATE_AUTH && isPOST )
 			processLogout( sessionObject, request );
 
 		/*
 		 *  compose dialog
 		 */
-		if( sessionObject.state == STATE_NEW ) {
+		if( sessionObject.state == STATE_NEW && isPOST ) {
 			// We have to make sure to get the state right even if
 			// the user hit the back button previously
 			if( buttonPressed( request, SEND ) ) {
@@ -824,7 +826,7 @@ public class WebMail extends HttpServlet
 		/*
 		 * message dialog
 		 */
-		if( sessionObject.state == STATE_SHOW ) {
+		if( sessionObject.state == STATE_SHOW && isPOST ) {
 			if( buttonPressed( request, LIST ) ) { 
 				sessionObject.state = STATE_LIST;
 			} else if (buttonPressed( request, CANCEL ) ||
@@ -849,7 +851,7 @@ public class WebMail extends HttpServlet
 		 * buttons on both folder and message dialog
 		 */
 		if( sessionObject.state == STATE_SHOW || sessionObject.state == STATE_LIST ) {
-			if( buttonPressed( request, NEW ) ) {
+			if( isPOST && buttonPressed( request, NEW ) ) {
 				sessionObject.state = STATE_NEW;
 			}
 			
@@ -979,8 +981,10 @@ public class WebMail extends HttpServlet
 				}
 			}
 		}
+
 		/*
 		 * folder view
+		 * SHOW is the one parameter that's a link, not a button, so we allow it for GET
 		 */
 		if( sessionObject.state == STATE_LIST || sessionObject.state == STATE_SHOW) {
 			/*
@@ -1039,7 +1043,7 @@ public class WebMail extends HttpServlet
 		if( buttonPressed( request, REFRESH ) ) {
 			sessionObject.mailbox.refresh();
 			sessionObject.error += sessionObject.mailbox.lastError();
-			sessionObject.mailCache.getMail(true);
+			sessionObject.mailCache.getMail(MailCache.FETCH_HEADER);
 			// get through cache so we have the disk-only ones too
 			String[] uidls = sessionObject.mailCache.getUIDLs();
 			if (uidls != null)
@@ -1360,13 +1364,15 @@ public class WebMail extends HttpServlet
                                ua.startsWith("Vodafone"));
     }
 	/**
+	 * The entry point for all web page loads
 	 * 
 	 * @param httpRequest
 	 * @param response
+	 * @param isPOST disallow button pushes if false
 	 * @throws IOException
 	 * @throws ServletException
 	 */
-	private void processRequest( HttpServletRequest httpRequest, HttpServletResponse response )
+	private void processRequest( HttpServletRequest httpRequest, HttpServletResponse response, boolean isPOST )
 	throws IOException, ServletException
 	{
 		String theme = Config.getProperty(CONFIG_THEME, DEFAULT_THEME);
@@ -1418,7 +1424,7 @@ public class WebMail extends HttpServlet
 				processComposeButtons( sessionObject, request );
 		
 			int oldState = sessionObject.state;
-			processStateChangeButtons( sessionObject, request );
+			processStateChangeButtons( sessionObject, request, isPOST );
 			int newState = sessionObject.state;
 			if (oldState != newState)
 				Debug.debug(Debug.DEBUG, "STATE CHANGE from " + oldState + " to " + newState);
@@ -1430,11 +1436,14 @@ public class WebMail extends HttpServlet
 			//	Debug.debug(Debug.DEBUG, "Changed idle from " + oldIdle + " to " + newIdle);
 			//}
 			
-			if( sessionObject.state != STATE_AUTH )
-				processGenericButtons( sessionObject, request );
+			if( sessionObject.state != STATE_AUTH ) {
+				if (isPOST)
+				       processGenericButtons( sessionObject, request );
+			}
 			
 			if( sessionObject.state == STATE_LIST ) {
-				processFolderButtons( sessionObject, request );
+				if (isPOST)
+					processFolderButtons( sessionObject, request );
 				for( Iterator<String> it = sessionObject.folder.currentPageIterator(); it != null && it.hasNext(); ) {
 					String uidl = it.next();
 					Mail mail = sessionObject.mailCache.getMail( uidl, MailCache.FETCH_HEADER );
@@ -1446,7 +1455,8 @@ public class WebMail extends HttpServlet
 			}
 			
 			if( sessionObject.state == STATE_SHOW ) {
-				processMessageButtons( sessionObject, request );
+				if (isPOST)
+					processMessageButtons( sessionObject, request );
 				// If the last message has just been deleted then
 				// sessionObject.state = STATE_LIST and
 				// sessionObject.showUIDL = null
@@ -1734,6 +1744,7 @@ public class WebMail extends HttpServlet
 		}
 		return ok;
 	}
+
 	/**
 	 * 
 	 */
@@ -1741,8 +1752,9 @@ public class WebMail extends HttpServlet
 	public void doGet( HttpServletRequest request, HttpServletResponse response )
 	throws IOException, ServletException
 	{
-		processRequest( request, response );		
+		processRequest( request, response, false );		
 	}
+
 	/**
 	 * 
 	 */
@@ -1750,8 +1762,9 @@ public class WebMail extends HttpServlet
 	public void doPost( HttpServletRequest request, HttpServletResponse response )
 	throws IOException, ServletException
 	{
-		processRequest( request, response );
+		processRequest( request, response, true );
 	}
+
 	/**
 	 * 
 	 * @param out
@@ -1948,7 +1961,10 @@ public class WebMail extends HttpServlet
 			//		", clear=" + sessionObject.clear );
 			out.println( "<tr class=\"list" + bg + "\"><td><input type=\"checkbox\" class=\"optbox\" name=\"check" + i + "\" value=\"1\"" + 
 					( idChecked ? "checked" : "" ) + ">" + "</td><td>" +
-					link + mail.shortSender + "</a></td><td>&nbsp;</td><td>" + link + mail.shortSubject + "</a></td><td>&nbsp;</td><td>" +
+					link + mail.shortSender + "</a></td><td>" +
+					(mail.hasAttachment() ? "<img src=\"/susimail/icons/attach.png\" alt=\"\">" : "&nbsp;") + "</td><td>" +
+					link + mail.shortSubject + "</a></td><td>" +
+					(mail.isSpam() ? "<img src=\"/susimail/icons/flag_red.png\" alt=\"\">" : "&nbsp;") + "</td><td>" +
 					// don't let date get split across lines
 					mail.localFormattedDate.replace(" ", "&nbsp;") + "</td><td>&nbsp;</td><td align=\"right\">" +
 					((mail.getSize() > 0) ? (DataHelper.formatSize2(mail.getSize()) + 'B') : "???") + "</td></tr>" );
-- 
GitLab