package tech.blueglacier.disposition; import tech.blueglacier.Common; import com.sun.mail.util.PropUtil; import org.apache.james.mime4j.MimeException; import org.apache.james.mime4j.util.CharsetUtil; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Map; import java.util.Set; public class ContentDispositionDecoder { private static boolean decodeParametersStrict = PropUtil.getBooleanSystemProperty("mail.mime.decodeparameters.strict", false); private static ContentDispositionHeaderValue decodeContentDisposition( String headerValue) throws MimeException { ContentDispositionHeaderValue contentDispositionHeaderValue = new ContentDispositionHeaderValue(); contentDispositionHeaderValue.setValue(headerValue); try { int i = headerValue.indexOf('\''); if (i <= 0) { if (decodeParametersStrict) { throw new MimeException( "Missing charset in encoded value: " + headerValue); } return contentDispositionHeaderValue; } String charset = headerValue.substring(0, i); charset = Common.getFallbackCharset(charset); if (CharsetUtil.lookup(charset) == null) { return contentDispositionHeaderValue; } int li = headerValue.indexOf('\'', i + 1); if (li < 0) { if (decodeParametersStrict) { throw new MimeException( "Missing language in encoded value: " + headerValue); } return contentDispositionHeaderValue; } headerValue = headerValue.substring(li + 1); contentDispositionHeaderValue.setCharset(charset); contentDispositionHeaderValue.setValue(decodeBytes(headerValue, charset)); } catch (NumberFormatException nex) { if (decodeParametersStrict) { throw new MimeException(nex); } } catch (StringIndexOutOfBoundsException ex) { if (decodeParametersStrict) { throw new MimeException(ex); } } return contentDispositionHeaderValue; } private static String decodeBytes(String value, String charset) throws MimeException { byte[] b = new byte[value.length()]; int i = 0; int temp = 0; for (int bi = 0; i < value.length(); ++i) { char c = value.charAt(i); if (c == '%') { String hex = value.substring(i + 1, i + 3); c = (char) Integer.parseInt(hex, 16); i += 2; } b[(bi++)] = (byte) c; temp = bi; } String str; try { str = new String(b, 0, temp, charset); } catch (UnsupportedEncodingException e) { throw new MimeException(e); } return str; } /** * Logical class for representing Content-Disposition header value */ private static class ContentDispositionHeaderValue { private String value; private String charset; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getCharset() { return charset; } public void setCharset(String charset) { this.charset = charset; } } public static String decodeDispositionFileName(Map<String, String> contentDispositionParameters) throws MimeException { // Refer RFC 2183 'The Content-Disposition Header Field' and // RFC 2184 'Parameter Value Character Set and Language Information' Set<String> contentDispositionKeySet = contentDispositionParameters.keySet(); String fileName = null; if (contentDispositionKeySet != null) { String[] sortedDispositionFileNameKeys = getSortedStringArray(contentDispositionKeySet.toArray()); StringBuilder valueStr = new StringBuilder(); for (int i = 0; i < sortedDispositionFileNameKeys.length; i++) { valueStr.append(contentDispositionParameters.get(sortedDispositionFileNameKeys[i])); } String encodedStr = valueStr.toString(); if (!encodedStr.isEmpty()) { fileName = decodeContentDisposition(encodedStr).getValue(); } } return fileName; } private static String[] getSortedStringArray(Object[] objArray) { String[] strArray = new String[objArray.length]; for (int i = 0; i < objArray.length; i++) { strArray[i] = (String) objArray[i]; } Arrays.sort(strArray); return strArray; } }