diff --git a/common/src/main/java/stirling/software/common/util/EmlToPdf.java b/common/src/main/java/stirling/software/common/util/EmlToPdf.java index 2fec5e9f2..7c29b1f9a 100644 --- a/common/src/main/java/stirling/software/common/util/EmlToPdf.java +++ b/common/src/main/java/stirling/software/common/util/EmlToPdf.java @@ -43,12 +43,10 @@ import stirling.software.common.model.api.converters.EmlToPdfRequest; @Slf4j @UtilityClass public class EmlToPdf { - private static final class StyleConstants { // Font and layout constants static final int DEFAULT_FONT_SIZE = 12; - static final String DEFAULT_FONT_FAMILY = - "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"; + static final String DEFAULT_FONT_FAMILY = "Helvetica, sans-serif"; static final float DEFAULT_LINE_HEIGHT = 1.4f; static final String DEFAULT_ZOOM = "1.0"; @@ -69,20 +67,15 @@ public class EmlToPdf { static final int EML_CHECK_LENGTH = 8192; static final int MIN_HEADER_COUNT_FOR_VALID_EML = 2; - private StyleConstants() { - // Utility class - prevent instantiation - } + private StyleConstants() {} } private static final class MimeConstants { static final Pattern MIME_ENCODED_PATTERN = Pattern.compile("=\\?([^?]+)\\?([BbQq])\\?([^?]*)\\?="); - static final String PAPERCLIP_EMOJI = "\uD83D\uDCCE"; // 📎 - static final String ATTACHMENT_ICON_PLACEHOLDER = "icon"; + static final String ATTACHMENT_MARKER = "[@]"; - private MimeConstants() { - // Utility class - prevent instantiation - } + private MimeConstants() {} } private static final class FileSizeConstants { @@ -90,9 +83,7 @@ public class EmlToPdf { static final long BYTES_IN_MB = BYTES_IN_KB * 1024L; static final long BYTES_IN_GB = BYTES_IN_MB * 1024L; - private FileSizeConstants() { - // Utility class - prevent instantiation - } + private FileSizeConstants() {} } // Cached Jakarta Mail availability check @@ -169,7 +160,7 @@ public class EmlToPdf { } } - private static void validateEmlInput(byte[] emlBytes) throws IOException { + private static void validateEmlInput(byte[] emlBytes) { if (emlBytes == null || emlBytes.length == 0) { throw new IllegalArgumentException("EML file is empty or null"); } @@ -205,7 +196,6 @@ public class EmlToPdf { disableSanitize); } catch (IOException | InterruptedException e) { log.warn("Initial HTML to PDF conversion failed, trying with simplified HTML"); - // Try with simplified HTML String simplifiedHtml = simplifyHtmlContent(htmlContent); return FileToPdf.convertHtmlToPdf( weasyprintPath, @@ -256,7 +246,7 @@ public class EmlToPdf { html.append("\n"); html.append("").append(escapeHtml(subject)).append("\n"); html.append("\n"); html.append("\n"); @@ -313,7 +303,7 @@ public class EmlToPdf { // Show advanced features status if requested assert request != null; - if (request != null && request.getFileInput().isEmpty()) { + if (request.getFileInput().isEmpty()) { html.append("
\n"); html.append( "

Note: Some advanced features require Jakarta Mail dependencies.

\n"); @@ -485,7 +475,7 @@ public class EmlToPdf { attachmentInfo .append("
") .append("") - .append(MimeConstants.ATTACHMENT_ICON_PLACEHOLDER) + .append(MimeConstants.ATTACHMENT_MARKER) .append(" ") .append("") .append(escapeHtml(filename)) @@ -659,7 +649,7 @@ public class EmlToPdf { return processed; } - private static void appendEnhancedStyles(StringBuilder html, EmlToPdfRequest request) { + private static void appendEnhancedStyles(StringBuilder html) { int fontSize = StyleConstants.DEFAULT_FONT_SIZE; String textColor = StyleConstants.DEFAULT_TEXT_COLOR; String backgroundColor = StyleConstants.DEFAULT_BACKGROUND_COLOR; @@ -841,7 +831,7 @@ public class EmlToPdf { processMultipartAdvanced(messageContent, content, request); } } catch (Exception e) { - log.warn("Error processing multipart content: {}", e.getMessage()); + log.warn("Error processing content: {}", e.getMessage()); } } @@ -979,7 +969,7 @@ public class EmlToPdf { html.append("\n"); html.append("").append(escapeHtml(content.getSubject())).append("\n"); html.append("\n"); html.append("\n"); @@ -1036,7 +1026,7 @@ public class EmlToPdf { .append(uniqueId) .append("\">") .append("") - .append(MimeConstants.PAPERCLIP_EMOJI) + .append(MimeConstants.ATTACHMENT_MARKER) .append(" ") .append("") .append(escapeHtml(safeMimeDecode(attachment.getFilename()))) @@ -1202,24 +1192,24 @@ public class EmlToPdf { return; } - // 1. Find the screen position of all emoji anchors - EmojiPositionFinder finder = new EmojiPositionFinder(); + // 1. Find the screen position of all attachment markers + AttachmentMarkerPositionFinder finder = new AttachmentMarkerPositionFinder(); finder.setSortByPosition(true); // Process pages in order finder.getText(document); - List emojiPositions = finder.getPositions(); + List markerPositions = finder.getPositions(); - // 2. Warn if the number of anchors and attachments don't match - if (emojiPositions.size() != attachments.size()) { + // 2. Warn if the number of markers and attachments don't match + if (markerPositions.size() != attachments.size()) { log.warn( - "Found {} emoji anchors, but there are {} attachments. Annotation count may be incorrect.", - emojiPositions.size(), + "Found {} attachment markers, but there are {} attachments. Annotation count may be incorrect.", + markerPositions.size(), attachments.size()); } - // 3. Create an invisible annotation over each found emoji - int annotationsToAdd = Math.min(emojiPositions.size(), attachments.size()); + // 3. Create an invisible annotation over each found marker + int annotationsToAdd = Math.min(markerPositions.size(), attachments.size()); for (int i = 0; i < annotationsToAdd; i++) { - EmojiPosition position = emojiPositions.get(i); + MarkerPosition position = markerPositions.get(i); EmailAttachment attachment = attachments.get(i); if (attachment.getEmbeddedFilename() != null) { @@ -1354,7 +1344,6 @@ public class EmlToPdf { } // MIME header decoding functionality for RFC 2047 encoded headers - moved to constants - private static String decodeMimeHeader(String encodedText) { if (encodedText == null || encodedText.trim().isEmpty()) { return encodedText; @@ -1494,15 +1483,13 @@ public class EmlToPdf { } @Data - public static class EmojiPosition { + public static class MarkerPosition { private int pageIndex; private float x; private float y; private String character; - public EmojiPosition() {} - - public EmojiPosition(int pageIndex, float x, float y, String character) { + public MarkerPosition(int pageIndex, float x, float y, String character) { this.pageIndex = pageIndex; this.x = x; this.y = y; @@ -1510,14 +1497,15 @@ public class EmlToPdf { } } - public static class EmojiPositionFinder extends org.apache.pdfbox.text.PDFTextStripper { - @Getter private final List positions = new ArrayList<>(); + public static class AttachmentMarkerPositionFinder + extends org.apache.pdfbox.text.PDFTextStripper { + @Getter private final List positions = new ArrayList<>(); private int currentPageIndex; - private boolean sortByPosition; + protected boolean sortByPosition; private boolean isInAttachmentSection; private boolean attachmentSectionFound; - public EmojiPositionFinder() throws IOException { + public AttachmentMarkerPositionFinder() { super(); this.currentPageIndex = 0; this.sortByPosition = false; @@ -1560,24 +1548,18 @@ public class EmlToPdf { isInAttachmentSection = false; } - // Only look for emojis if we are in the attachment section + // Only look for markers if we are in the attachment section if (isInAttachmentSection) { - // Look for paperclip emoji characters (U+1F4CE) - String paperclipEmoji = "\uD83D\uDCCE"; // 📎 Unicode representation - - for (int i = 0; i < string.length(); i++) { - // Check if we have a complete paperclip emoji at this position - if (i < string.length() - 1 - && string.substring(i, i + 2).equals(paperclipEmoji) - && i < textPositions.size()) { - + String attachmentMarker = MimeConstants.ATTACHMENT_MARKER; + for (int i = 0; (i = string.indexOf(attachmentMarker, i)) != -1; i++) { + if (i < textPositions.size()) { org.apache.pdfbox.text.TextPosition textPosition = textPositions.get(i); - EmojiPosition position = - new EmojiPosition( + MarkerPosition position = + new MarkerPosition( currentPageIndex, textPosition.getXDirAdj(), textPosition.getYDirAdj(), - paperclipEmoji); + attachmentMarker); positions.add(position); } } @@ -1589,16 +1571,5 @@ public class EmlToPdf { public void setSortByPosition(boolean sortByPosition) { this.sortByPosition = sortByPosition; } - - public boolean isSortByPosition() { - return sortByPosition; - } - - public void reset() { - positions.clear(); - currentPageIndex = 0; - isInAttachmentSection = false; - attachmentSectionFound = false; - } } }