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.

RecipientChunks.java 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hsmf.datatypes;
  16. import java.io.Serializable;
  17. import java.util.ArrayList;
  18. import java.util.Collections;
  19. import java.util.Comparator;
  20. import java.util.List;
  21. import java.util.Map;
  22. import org.apache.logging.log4j.LogManager;
  23. import org.apache.logging.log4j.Logger;
  24. /**
  25. * Collection of convenience chunks for the Recip(ient) part of an outlook file.
  26. *
  27. * If a message has multiple recipients, there will be several of these.
  28. */
  29. public final class RecipientChunks implements ChunkGroupWithProperties {
  30. private static final Logger LOG = LogManager.getLogger(RecipientChunks.class);
  31. public static final String PREFIX = "__recip_version1.0_#";
  32. public static final MAPIProperty RECIPIENT_NAME = MAPIProperty.DISPLAY_NAME;
  33. public static final MAPIProperty DELIVERY_TYPE = MAPIProperty.ADDRTYPE;
  34. public static final MAPIProperty RECIPIENT_EMAIL_ADDRESS = MAPIProperty.EMAIL_ADDRESS;
  35. public static final MAPIProperty RECIPIENT_SEARCH = MAPIProperty.SEARCH_KEY;
  36. public static final MAPIProperty RECIPIENT_SMTP_ADDRESS = MAPIProperty.SMTP_ADDRESS;
  37. public static final MAPIProperty RECIPIENT_DISPLAY_NAME = MAPIProperty.RECIPIENT_DISPLAY_NAME;
  38. /** Our 0 based position in the list of recipients */
  39. private int recipientNumber;
  40. /** TODO */
  41. private ByteChunk recipientSearchChunk;
  42. /**
  43. * The "name", which could be their name if an internal person, or their
  44. * email address if an external person
  45. */
  46. private StringChunk recipientNameChunk;
  47. /**
  48. * The email address of the recipient, which could be in SMTP or SEARCH
  49. * format, but isn't always present...
  50. */
  51. private StringChunk recipientEmailChunk;
  52. /**
  53. * The smtp destination email address of the recipient, but isn't always
  54. * present...
  55. */
  56. private StringChunk recipientSMTPChunk;
  57. /**
  58. * Normally EX or SMTP. Will generally affect where the email address ends
  59. * up.
  60. */
  61. private StringChunk deliveryTypeChunk;
  62. /**
  63. * The display name of the recipient. Normally seems to hold the same value
  64. * as in recipientNameChunk
  65. */
  66. private StringChunk recipientDisplayNameChunk;
  67. /**
  68. * Holds the fixed sized properties, and the pointers to the data of
  69. * variable sized ones
  70. */
  71. private PropertiesChunk recipientProperties;
  72. public RecipientChunks(String name) {
  73. recipientNumber = -1;
  74. int splitAt = name.lastIndexOf('#');
  75. if (splitAt > -1) {
  76. String number = name.substring(splitAt + 1);
  77. try {
  78. recipientNumber = Integer.parseInt(number, 16);
  79. } catch (NumberFormatException e) {
  80. LOG.atError().log("Invalid recipient number in name {}", name);
  81. }
  82. }
  83. }
  84. public int getRecipientNumber() {
  85. return recipientNumber;
  86. }
  87. public ByteChunk getRecipientSearchChunk() {
  88. return recipientSearchChunk;
  89. }
  90. public StringChunk getRecipientNameChunk() {
  91. return recipientNameChunk;
  92. }
  93. public StringChunk getRecipientEmailChunk() {
  94. return recipientEmailChunk;
  95. }
  96. public StringChunk getRecipientSMTPChunk() {
  97. return recipientSMTPChunk;
  98. }
  99. public StringChunk getDeliveryTypeChunk() {
  100. return deliveryTypeChunk;
  101. }
  102. public StringChunk getRecipientDisplayNameChunk() {
  103. return recipientDisplayNameChunk;
  104. }
  105. /**
  106. * Tries to find their name, in whichever chunk holds it.
  107. */
  108. public String getRecipientName() {
  109. if (recipientNameChunk != null) {
  110. return recipientNameChunk.getValue();
  111. }
  112. if (recipientDisplayNameChunk != null) {
  113. return recipientDisplayNameChunk.getValue();
  114. }
  115. // Can't find it
  116. return null;
  117. }
  118. /**
  119. * Tries to find their email address, in whichever chunk holds it given the
  120. * delivery type.
  121. */
  122. public String getRecipientEmailAddress() {
  123. // If we have this, it really has the email
  124. if (recipientSMTPChunk != null) {
  125. return recipientSMTPChunk.getValue();
  126. }
  127. // This might be a real email, or might be
  128. // in CN=... format
  129. if (recipientEmailChunk != null) {
  130. String email = recipientEmailChunk.getValue();
  131. int cne = email.indexOf("/CN=");
  132. if (cne < 0) {
  133. // Normal smtp address
  134. return email;
  135. } else {
  136. // /O=..../CN=em@ail
  137. return email.substring(cne + 4);
  138. }
  139. }
  140. // Might be in the name field, check there
  141. if (recipientNameChunk != null) {
  142. String name = recipientNameChunk.getValue();
  143. if (name.contains("@")) {
  144. // Strip leading and trailing quotes if needed
  145. if (name.startsWith("'") && name.endsWith("'")) {
  146. return name.substring(1, name.length() - 1);
  147. }
  148. return name;
  149. }
  150. }
  151. // Check the search chunk, see if it's
  152. // encoded as a SMTP destination in there.
  153. if (recipientSearchChunk != null) {
  154. String search = recipientSearchChunk.getAs7bitString();
  155. int idx = search.indexOf("SMTP:");
  156. if (idx >= 0) {
  157. return search.substring(idx + 5);
  158. }
  159. }
  160. // Can't find it
  161. return null;
  162. }
  163. /** Holds all the chunks that were found. */
  164. private final List<Chunk> allChunks = new ArrayList<>();
  165. @Override
  166. public Map<MAPIProperty, List<PropertyValue>> getProperties() {
  167. if (recipientProperties != null) {
  168. return recipientProperties.getProperties();
  169. } else {
  170. return Collections.emptyMap();
  171. }
  172. }
  173. public Chunk[] getAll() {
  174. return allChunks.toArray(new Chunk[0]);
  175. }
  176. @Override
  177. public Chunk[] getChunks() {
  178. return getAll();
  179. }
  180. /**
  181. * Called by the parser whenever a chunk is found.
  182. */
  183. @Override
  184. public void record(Chunk chunk) {
  185. try {
  186. if (chunk.getChunkId() == RECIPIENT_SEARCH.id) {
  187. // TODO - parse
  188. recipientSearchChunk = (ByteChunk) chunk;
  189. } else if (chunk.getChunkId() == RECIPIENT_NAME.id) {
  190. recipientDisplayNameChunk = (StringChunk) chunk;
  191. } else if (chunk.getChunkId() == RECIPIENT_DISPLAY_NAME.id) {
  192. recipientNameChunk = (StringChunk) chunk;
  193. } else if (chunk.getChunkId() == RECIPIENT_EMAIL_ADDRESS.id) {
  194. recipientEmailChunk = (StringChunk) chunk;
  195. } else if (chunk.getChunkId() == RECIPIENT_SMTP_ADDRESS.id) {
  196. recipientSMTPChunk = (StringChunk) chunk;
  197. } else if (chunk.getChunkId() == DELIVERY_TYPE.id) {
  198. deliveryTypeChunk = (StringChunk) chunk;
  199. } else if (chunk instanceof PropertiesChunk) {
  200. recipientProperties = (PropertiesChunk) chunk;
  201. }
  202. } catch (ClassCastException e) {
  203. throw new IllegalArgumentException("ChunkId and type of chunk did not match, had id " +
  204. chunk.getChunkId() + " and type of chunk: " + chunk.getClass(), e);
  205. }
  206. // And add to the main list
  207. allChunks.add(chunk);
  208. }
  209. @Override
  210. public void chunksComplete() {
  211. if (recipientProperties != null) {
  212. recipientProperties.matchVariableSizedPropertiesToChunks();
  213. } else {
  214. LOG.atWarn().log("Recipients Chunk didn't contain a list of properties!");
  215. }
  216. }
  217. /**
  218. * Orders by the recipient number.
  219. */
  220. public static class RecipientChunksSorter
  221. implements Comparator<RecipientChunks>, Serializable {
  222. @Override
  223. public int compare(RecipientChunks a, RecipientChunks b) {
  224. return Integer.compare(a.recipientNumber, b.recipientNumber);
  225. }
  226. }
  227. }