Simple email application for Android. Original source code: https://framagit.org/dystopia-project/simple-email
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.7 KiB

6 years ago
6 years ago
  1. package eu.faircode.email;
  2. /*
  3. This file is part of FairEmail.
  4. FairEmail is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. NetGuard is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with NetGuard. If not, see <http://www.gnu.org/licenses/>.
  14. Copyright 2018 by Marcel Bokhorst (M66B)
  15. */
  16. import android.content.Context;
  17. import android.content.SharedPreferences;
  18. import android.preference.PreferenceManager;
  19. import android.text.Html;
  20. import android.text.TextUtils;
  21. import org.jsoup.Jsoup;
  22. import org.jsoup.helper.StringUtil;
  23. import org.jsoup.nodes.Document;
  24. import org.jsoup.nodes.Element;
  25. import org.jsoup.nodes.Node;
  26. import org.jsoup.nodes.TextNode;
  27. import org.jsoup.safety.Whitelist;
  28. import org.jsoup.select.NodeTraversor;
  29. import org.jsoup.select.NodeVisitor;
  30. import java.util.ArrayList;
  31. import java.util.List;
  32. import java.util.regex.Matcher;
  33. import java.util.regex.Pattern;
  34. public class HtmlHelper implements NodeVisitor {
  35. private Context context;
  36. private String newline;
  37. private List<String> refs = new ArrayList<>();
  38. private StringBuilder sb = new StringBuilder();
  39. private static Pattern pattern = Pattern.compile("([http|https]+://[\\w\\S(\\.|:|/)]+)");
  40. private HtmlHelper(Context context, boolean reply) {
  41. this.context = context;
  42. this.newline = (reply ? "<br>> " : "<br>");
  43. }
  44. public void head(Node node, int depth) {
  45. String name = node.nodeName();
  46. if (node instanceof TextNode) {
  47. String text = ((TextNode) node).text();
  48. Matcher matcher = pattern.matcher(text);
  49. while (matcher.find()) {
  50. String ref = matcher.group();
  51. if (!refs.contains(ref))
  52. refs.add(ref);
  53. String alt = context.getString(R.string.title_link);
  54. text = text.replace(ref, String.format("<a href=\"%s\">%s [%d]</a>", ref, alt, refs.size()));
  55. }
  56. sb.append(text);
  57. } else if (name.equals("li"))
  58. sb.append(newline).append(" * ");
  59. else if (name.equals("dt"))
  60. sb.append(" ");
  61. else if (StringUtil.in(name, "p", "h1", "h2", "h3", "h4", "h5", "tr", "div"))
  62. sb.append(newline);
  63. }
  64. public void tail(Node node, int depth) {
  65. String name = node.nodeName();
  66. if (StringUtil.in(name, "br", "dd", "dt", "p", "h1", "h2", "h3", "h4", "h5", "div"))
  67. sb.append(newline);
  68. else if (name.equals("a")) {
  69. String ref = node.absUrl("href");
  70. if (!TextUtils.isEmpty(ref)) {
  71. if (!refs.contains(ref))
  72. refs.add(ref);
  73. String alt = node.attr("alt");
  74. if (TextUtils.isEmpty(alt))
  75. alt = context.getString(R.string.title_link);
  76. alt = Html.escapeHtml(alt);
  77. sb.append(" ").append(String.format("<a href=\"%s\">%s [%d]</a>", ref, alt, refs.size()));
  78. }
  79. } else if (name.equals("img")) {
  80. String ref = node.absUrl("src");
  81. if (!TextUtils.isEmpty(ref)) {
  82. if (!refs.contains(ref))
  83. refs.add(ref);
  84. String alt = node.attr("alt");
  85. if (TextUtils.isEmpty(alt))
  86. alt = context.getString(R.string.title_image);
  87. alt = Html.escapeHtml(alt);
  88. sb.append(" ").append(String.format("<a href=\"%s\">%s [%d]</a>", ref, alt, refs.size()));
  89. sb.append("<img src=\"" + ref + "\" alt=\"" + alt + "\">");
  90. }
  91. }
  92. }
  93. @Override
  94. public String toString() {
  95. if (refs.size() > 0)
  96. sb.append(newline).append(newline);
  97. for (int i = 0; i < refs.size(); i++)
  98. sb.append(String.format("[%d] %s ", i + 1, refs.get(i))).append(newline);
  99. return sb.toString();
  100. }
  101. public static String sanitize(Context context, String html, boolean reply) {
  102. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  103. if (prefs.getBoolean("sanitize", false)) {
  104. Document document = Jsoup.parse(html);
  105. HtmlHelper visitor = new HtmlHelper(context, reply);
  106. NodeTraversor.traverse(visitor, document.body());
  107. return visitor.toString();
  108. } else {
  109. Document document = Jsoup.parse(Jsoup.clean(html, Whitelist.relaxed()));
  110. for (Element tr : document.select("tr"))
  111. tr.after("<br>");
  112. NodeTraversor.traverse(new NodeVisitor() {
  113. @Override
  114. public void head(Node node, int depth) {
  115. if (node instanceof TextNode) {
  116. String text = ((TextNode) node).text();
  117. Matcher matcher = pattern.matcher(text);
  118. while (matcher.find()) {
  119. String ref = matcher.group();
  120. text = text.replace(ref, String.format("<a href=\"%s\">%s</a>", ref, ref));
  121. }
  122. node.before(text);
  123. ((TextNode) node).text("");
  124. }
  125. }
  126. @Override
  127. public void tail(Node node, int depth) {
  128. }
  129. }, document.body());
  130. return document.body().html();
  131. }
  132. }
  133. }