package com.wilutions.itol; import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.HashSet; public class IssueDescriptionParser { public static String stripOriginalMessageFromReply(String from, String to, String subject, String description) { String ret = description; OultookOriginalMessageDelimiter delim = new OultookOriginalMessageDelimiter(); delim.replyFrom = from; delim.replyTo = to; delim.replySubject = subject; int outlookDelimPos = findReplyDelim(description, delim); if (outlookDelimPos >= 0) { ret = description.substring(0, outlookDelimPos).trim(); } ret = ret.replace("\n\n", "\n"); return ret; } /** * Find beginning of original message. * * @param description * @return position or -1 */ private static int findReplyDelim(String description, OultookOriginalMessageDelimiter delim) { int org = 0; while (org < description.length()) { org = findFirstTextAfterNextEmptyLine(description, org); if (org < 0) break; // find ---- XXXX ---- // This delimiter is used in a reply message above the original message body if (isMaybeOriginalMessageLine(description, org, delim)) break; // find e.g.: On Wed, Nov 18, 2015 at 2:53 PM, WILUTIONS <wilutions@gmail.com <mailto:wilutions@gmail.com> > wrote: if (isMaybeSimpleHeaderLine(description, org, delim)) break; // find e.g.: // From: WILUTIONS [mailto:wilutions@googlemail.com] // Sent: Tuesday, November 24, 2015 4:02 PM // To: Ch Hough <cxxxx@axxx.com> // Subject: AW: license email int pos = org; pos = isMaybeOutlookHeaderLine(description, pos, delim); pos = isMaybeOutlookHeaderLine(description, pos, delim); pos = isMaybeOutlookHeaderLine(description, pos, delim); pos = isMaybeOutlookHeaderLine(description, pos, delim); // Break, if at least 2 lines found that could belong to delimiter // lines. if (delim.toValue() >= 2) break; } return org; } /** * Find first text after empty line starting from pos. * * @param description * @param pos * @return position of text after the empty line or -1 */ private static int findFirstTextAfterNextEmptyLine(String description, int pos) { int r = pos >= 0 ? description.indexOf('\n', pos) : -1; while (r >= 0) { r++; int q = description.indexOf('\n', r); if (q >= 0) { String s = description.substring(r, q).trim(); r = q; if (s.length() == 0) { // find first non-whitespace while (++r < description.length()) { char ch = description.charAt(r); if (!Character.isWhitespace(ch)) break; } if (r >= description.length()) r = -1; break; } } else { r = -1; } } return r; } private static class OultookOriginalMessageDelimiter { boolean fromFound; boolean sentFound; boolean toFound; boolean subjectFound; String replyTo; String replyFrom; String replySubject; int toValue() { int v = 0; if (fromFound) v++; if (toFound) v++; if (sentFound) v++; if (subjectFound) v++; return v; } } /** * Check whether line starting from pos could be a Outlook header line. A * header line starts with one word, maybe followed by blanks, then a colon, * then maybe blanks, and then some characters. If description beginning at * pos is a header line, the function returns the starting position of the * next line. If description beginning at pos is not a header line, the * function returns -1. * * @param description * @param pos * @param delim * @return next line start position or -1. */ private static int isMaybeOutlookHeaderLine(String description, int pos, OultookOriginalMessageDelimiter delim) { int n = pos >= 0 ? description.indexOf('\n', pos) : -1; if (n >= 0) { String s = description.substring(pos, n); int w = s.indexOf(':'); if (w > 0 && w + pos < n - 3) { s = s.substring(w + 1); boolean next = true; if (next && !delim.fromFound) { delim.fromFound = isMaybeMailAddress(s, delim.replyTo); next = !delim.fromFound; } if (next && !delim.toFound) { delim.toFound = isMaybeMailAddress(s, delim.replyFrom); next = !delim.toFound; } if (next && !delim.subjectFound) { delim.subjectFound = isMaybeSubject(s, delim.replySubject); next = !delim.subjectFound; } if (next && !delim.sentFound) { delim.sentFound = isMaybeSentDate(s); next = !delim.sentFound; } n++; } else { n = -1; } } return n; } /** * Check whether the line starting from pos contains text like ----XXXXX----. * @param description * @param pos * @param delim * @return */ private static boolean isMaybeOriginalMessageLine(String description, int pos, OultookOriginalMessageDelimiter delim) { boolean ret = false; int n = pos >= 0 ? description.indexOf('\n', pos) : -1; if (n >= 0) { String s = description.substring(pos, n); if (s.startsWith("----") && s.endsWith("----")) { ret = true; } } return ret; } /** * Check whether the line starting from pos contains a mail address and a date. * @param description * @param pos * @param delim * @return true, if both expected values found. */ private static boolean isMaybeSimpleHeaderLine(String description, int pos, OultookOriginalMessageDelimiter delim) { int n = pos >= 0 ? description.indexOf('\n', pos) : -1; if (n >= 0) { String s = description.substring(pos, n); delim.fromFound = isMaybeMailAddress(s, delim.replyTo); delim.sentFound = isMaybeSentDate(s); n++; } return delim.fromFound && delim.sentFound; } private static boolean isMaybeMailAddress(String s, String replyAddr) { boolean ret = false; String s1 = trimMailAddress(s); String k1 = trimMailAddress(replyAddr); HashSet<String> sparts = new HashSet<String>(Arrays.asList(s1.split(" "))); HashSet<String> kparts = new HashSet<String>(Arrays.asList(k1.split(" "))); for (String k : kparts) { if (sparts.contains(k)) { ret = true; break; } } return ret; } /** * Eliminate mail server address and special chars from given string. Should * return only first name and family name. * * @param s * @return name parts */ private static String trimMailAddress(String s) { StringBuilder r = new StringBuilder(); boolean skippingServerAddress = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (skippingServerAddress) { skippingServerAddress = Character.isLetterOrDigit(c); } else { skippingServerAddress = c == '@'; } if (!skippingServerAddress) { if (Character.isLetterOrDigit(c)) { r.append(c); } else if (r.length() == 0 || r.charAt(r.length() - 1) != ' ') { r.append(' '); } } } return r.toString().trim().toLowerCase(); } private static boolean isMaybeSentDate(String s) { s = s.replace('-', ' '); s = s.replace('.', ' '); s = s.replace('/', ' '); String[] parts = s.split(" "); boolean yearFound = false; boolean hourFound = false; boolean minuteFound = false; for (int i = 0; i < parts.length && !(yearFound && hourFound && minuteFound); i++) { String part = parts[i].trim(); if (!yearFound && part.length() >= 4) { try { int year = Integer.parseInt(part); GregorianCalendar cal = new GregorianCalendar(); cal.setTimeInMillis(System.currentTimeMillis()); int thisYear = cal.get(Calendar.YEAR); if (year >= 1970 && year <= thisYear) { yearFound = true; } } catch (Exception ignored) { } } else if (!(yearFound && minuteFound) && part.length() >= 4) { String[] hm = part.split(":"); if (hm.length == 2) { try { int hour = Integer.parseInt(hm[0]); int minute = Integer.parseInt(hm[1]); hourFound = hour >= 0 && hour < 24; minuteFound = minute >= 0 && minute < 60; } catch (Exception ignored) { } } } } return yearFound && hourFound && minuteFound; } private static boolean isMaybeSubject(String s, String knownSubject) { boolean ret = false; s = s.trim(); if (s.length() > 5) { int n = Math.min(s.length(), knownSubject.length()); int nbOfMatchingChars = 0; for (; nbOfMatchingChars < n; nbOfMatchingChars++) { char cs = s.charAt(s.length() - nbOfMatchingChars - 1); char ck = knownSubject.charAt(knownSubject.length() - nbOfMatchingChars - 1); if (cs != ck) break; } int matchingPercent = (nbOfMatchingChars * 100) / knownSubject.length(); ret = matchingPercent > 50; } return ret; } // das kann ich sp�ter mal versuchen. // greetings sind bereits in res/greetings.properties zu finden @SuppressWarnings("unused") private static int findGreeting(String description, int pos) { int ret = -1; return ret; } /* * Outlook Antworten: Leerzeile, dann 4 aufeinanderfolgende Zeilen, die mit * einem Wort + Doppelpunkt beginnen Eine Zeile kann eine Mailadresse * enthalten: [*]@[*].[*] Eine Zeile kann ein Datum enthalten: Zahl zw 1970 * und heutiger Jahreszahl, Uhrzeit [1-2 stellige zahl]:[1-2 stellige zahl] * Eine Zeile enth�lt nach dem ersten Doppelpunkt den Betreff * */ // De : WILUTIONS [mailto:wilutions@googlemail.com] // // Envoy� : dimanche 29 novembre 2015 14:54 // // � : Malvina Camus // // Objet : AW: QUOTE REQUEST // // // Da: Wolfgang Imig [mailto:wilutions@googlemail.com] // // Inviato: gioved� 16 luglio 2015 11.43 // // A: Claudio Gamberini // // Oggetto: Re: Info about DDAddin // // // From: WILUTIONS [mailto:wilutions@googlemail.com] // // Sent: Tuesday, November 24, 2015 4:02 PM // // To: Chuck Houghton <choughton@alro.com> // // Subject: AW: license email // // // Von: Rupert Stuffer // // Gesendet: Dienstag, 22. September 2015 08:57 // // An: 'Wolfgang Imig' // // Betreff: AW: Anfrage bzgl. Ihres Outlook Add Ins // // // Van: WILUTIONS [mailto:wilutions@gmail.com] // // Verzonden: dinsdag 17 november 2015 23:09 // // Aan: Jaap van der Reijden <jaap@toplogistics.nl> // // Onderwerp: AW: Request Add Inn Offer // // // -----Original Message----- // // From: WILUTIONS Support [mailto:mailer@fastspring.com] // // Sent: Friday, October 09, 2015 3:26 PM // // To: George Evans // // Subject: COMMERCIAL: Your Drag and Drop to HTML5 Addin for Microsoft // Outlook, NAMED USER License Delivery Information // // // From: Or Fogel // // Sent: Thursday, September 03, 2015 6:10 PM // // To: 'WILUTIONS' // // Subject: RE: Drag Drop solution - Outlook to HTML5 }