Skip to content

Commit 7fa4378

Browse files
committed
Complete test for DistList
1 parent 643a551 commit 7fa4378

File tree

2 files changed

+185
-132
lines changed

2 files changed

+185
-132
lines changed

src/main/java/com/pff/PSTDistList.java

Lines changed: 143 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -34,74 +34,136 @@
3434
package com.pff;
3535

3636
import java.io.IOException;
37-
import java.util.Date;
3837
import java.util.HashMap;
3938
import java.util.Arrays;
4039

4140
/**
42-
* PST DistList contains methods for extracting Addresses from Distribution lists.
41+
* PST DistList for extracting Addresses from Distribution lists.
4342
* @author Richard Johnson
4443
*/
4544
public class PSTDistList extends PSTMessage {
4645

47-
PSTDistList(PSTFile theFile, DescriptorIndexNode descriptorIndexNode)
48-
throws PSTException, IOException
49-
{
50-
super(theFile, descriptorIndexNode);
51-
}
52-
53-
PSTDistList(PSTFile theFile, DescriptorIndexNode folderIndexNode, PSTTableBC table, HashMap<Integer, PSTDescriptorItem> localDescriptorItems)
54-
{
55-
super(theFile, folderIndexNode, table, localDescriptorItems);
56-
}
57-
58-
private int findNextNullChar(byte[] data, int start) {
59-
for (; start < data.length; start += 2) {
60-
if (data[start] == 0 && data[start+1] == 0) {
61-
break;
62-
}
63-
}
64-
return start;
65-
}
46+
/**
47+
* constructor.
48+
* @param theFile pst file
49+
* @param descriptorIndexNode index of the list
50+
* @throws PSTException on parsing error
51+
* @throws IOException on data access error
52+
*/
53+
PSTDistList(PSTFile theFile, DescriptorIndexNode descriptorIndexNode)
54+
throws PSTException, IOException {
55+
super(theFile, descriptorIndexNode);
56+
}
57+
58+
/**
59+
* Internal constructor for performance.
60+
* @param theFile pst file
61+
* @param folderIndexNode index of the list
62+
* @param table the PSTTableBC this object is represented by
63+
* @param localDescriptorItems additional external items that represent
64+
* this object.
65+
*/
66+
PSTDistList(PSTFile theFile, DescriptorIndexNode folderIndexNode,
67+
PSTTableBC table,
68+
HashMap<Integer, PSTDescriptorItem> localDescriptorItems) {
69+
super(theFile, folderIndexNode, table, localDescriptorItems);
70+
}
6671

72+
/**
73+
* Find the next two null bytes in an array given start.
74+
* @param data the array to search
75+
* @param start the starting index
76+
* @return position of the next null char
77+
*/
78+
private int findNextNullChar(byte[] data, int start) {
79+
for (; start < data.length; start += 2) {
80+
if (data[start] == 0 && data[start + 1] == 0) {
81+
break;
82+
}
83+
}
84+
return start;
85+
}
86+
87+
/**
88+
* identifier for one-off entries.
89+
*/
6790
private byte[] oneOffEntryIdUid = {
6891
(byte)0x81, (byte)0x2b, (byte)0x1f, (byte)0xa4,
6992
(byte)0xbe, (byte)0xa3, (byte)0x10, (byte)0x19,
7093
(byte)0x9d, (byte)0x6e, (byte)0x00, (byte)0xdd,
7194
(byte)0x01, (byte)0x0f, (byte)0x54, (byte)0x02
7295
};
7396

74-
private byte[] wrappedEntryIdUid = {
97+
/**
98+
* identifier for wrapped entries.
99+
*/
100+
private byte[] wrappedEntryIdUid = {
75101
(byte)0xc0, (byte)0x91, (byte)0xad, (byte)0xd3,
76102
(byte)0x51, (byte)0x9d, (byte)0xcf, (byte)0x11,
77103
(byte)0xa4, (byte)0xa9, (byte)0x00, (byte)0xaa,
78104
(byte)0x00, (byte)0x47, (byte)0xfa, (byte)0xa4
79105
};
80106

107+
/**
108+
* Inner class to represent distribution list one-off entries.
109+
*/
81110
public class OneOffEntry {
82-
public String displayName = "";
83-
public String addressType = "";
84-
public String emailAddress = "";
85-
int pos = 0;
86-
public String toString() {
87-
return String.format(
88-
"Display Name: %s\n" +
89-
"Address Type: %s\n" +
90-
"Email Address: %s\n",
91-
this.displayName,
92-
this.addressType,
93-
this.emailAddress);
94-
}
111+
/** display name. */
112+
private String displayName = "";
113+
/**
114+
* @return display name
115+
* */
116+
public String getDisplayName() {
117+
return this.displayName;
118+
}
119+
/** address type (smtp). */
120+
private String addressType = "";
121+
/**
122+
* @return address type
123+
* */
124+
public String getAddressType() {
125+
return this.addressType;
126+
}
127+
/** email address. */
128+
private String emailAddress = "";
129+
/**
130+
* @return email address.
131+
* */
132+
public String getEmailAddress() {
133+
return this.emailAddress;
134+
}
135+
/** ending position of this object in the data array. */
136+
private int pos = 0;
137+
/**
138+
* @return formatted record
139+
*/
140+
public String toString() {
141+
return String.format(
142+
"Display Name: %s\n"
143+
+ "Address Type: %s\n"
144+
+ "Email Address: %s\n",
145+
this.displayName,
146+
this.addressType,
147+
this.emailAddress);
148+
}
95149
}
96150

151+
/**
152+
* Parse a one-off entry from this Distribution List.
153+
* @param data the item data
154+
* @param pos the current position in the data.
155+
* @throws IOException on string reading fail
156+
* @return the one-off entry
157+
*/
97158
private OneOffEntry parseOneOffEntry(byte[] data, int pos)
98-
throws IOException
99-
{
100-
int version = (int)PSTObject.convertLittleEndianBytesToLong(data, pos, pos+2);
159+
throws IOException {
160+
int version = (int)PSTObject.convertLittleEndianBytesToLong(
161+
data, pos, pos + 2);
101162
pos += 2;
102163

103164
// http://msdn.microsoft.com/en-us/library/ee202811(v=exchg.80).aspx
104-
int additionalFlags = (int)PSTObject.convertLittleEndianBytesToLong(data, pos, pos+2);
165+
int additionalFlags = (int)PSTObject.convertLittleEndianBytesToLong(
166+
data, pos, pos + 2);
105167
pos += 2;
106168

107169
int pad = additionalFlags & 0x8000;
@@ -116,19 +178,22 @@ private OneOffEntry parseOneOffEntry(byte[] data, int pos)
116178

117179
int stringEnd = findNextNullChar(data, pos);
118180
byte[] displayNameBytes = new byte[stringEnd - pos];
119-
System.arraycopy(data, pos, displayNameBytes, 0, displayNameBytes.length);
181+
System.arraycopy(data, pos, displayNameBytes,
182+
0, displayNameBytes.length);
120183
String displayName = new String(displayNameBytes, "UTF-16LE");
121184
pos = stringEnd + 2;
122185

123186
stringEnd = findNextNullChar(data, pos);
124187
byte[] addressTypeBytes = new byte[stringEnd - pos];
125-
System.arraycopy(data, pos, addressTypeBytes, 0, addressTypeBytes.length);
188+
System.arraycopy(data, pos, addressTypeBytes,
189+
0, addressTypeBytes.length);
126190
String addressType = new String(addressTypeBytes, "UTF-16LE");
127191
pos = stringEnd + 2;
128192

129193
stringEnd = findNextNullChar(data, pos);
130194
byte[] emailAddressBytes = new byte[stringEnd - pos];
131-
System.arraycopy(data, pos, emailAddressBytes, 0, emailAddressBytes.length);
195+
System.arraycopy(data, pos, emailAddressBytes,
196+
0, emailAddressBytes.length);
132197
String emailAddress = new String(emailAddressBytes, "UTF-16LE");
133198
pos = stringEnd + 2;
134199

@@ -140,22 +205,32 @@ private OneOffEntry parseOneOffEntry(byte[] data, int pos)
140205
return out;
141206
}
142207

143-
public Object[] getDistributionListMembers()
144-
throws PSTException, IOException
145-
{
146-
PSTTableBCItem item = this.items.get(pstFile.getNameToIdMapItem(0x8055, PSTFile.PSETID_Address));
147-
Object[] out = {};
208+
/**
209+
* Get an array of the members in this distribution list.
210+
* @throws PSTException on corrupted data
211+
* @throws IOException on bad string reading
212+
* @return array of entries that can either be PSTDistList.OneOffEntry
213+
* or a PSTObject, generally PSTContact.
214+
*/
215+
public Object[] getDistributionListMembers()
216+
throws PSTException, IOException {
217+
PSTTableBCItem item = this.items.get(
218+
pstFile.getNameToIdMapItem(0x8055, PSTFile.PSETID_Address));
219+
Object[] out = {};
148220
if (item != null) {
149221
int pos = 0;
150-
int count = (int)PSTObject.convertLittleEndianBytesToLong(item.data, pos, pos+4);
151-
out = new Object[count];
222+
int count = (int)PSTObject.convertLittleEndianBytesToLong(
223+
item.data, pos, pos + 4);
224+
out = new Object[count];
152225
pos += 4;
153-
pos = (int)PSTObject.convertLittleEndianBytesToLong(item.data, pos, pos+4);
226+
pos = (int)PSTObject.convertLittleEndianBytesToLong(
227+
item.data, pos, pos + 4);
154228

155-
for (int x = 0; x < count; x++) {
229+
for (int x = 0; x < count; x++) {
156230
// http://msdn.microsoft.com/en-us/library/ee218661(v=exchg.80).aspx
157231
// http://msdn.microsoft.com/en-us/library/ee200559(v=exchg.80).aspx
158-
int flags = (int)PSTObject.convertLittleEndianBytesToLong(item.data, pos, pos+4);
232+
int flags = (int)PSTObject.convertLittleEndianBytesToLong(
233+
item.data, pos, pos + 4);
159234
pos += 4;
160235

161236
byte[] guid = new byte[16];
@@ -168,28 +243,30 @@ public Object[] getDistributionListMembers()
168243
int entryAddressType = item.data[pos] & 0x70 >> 4;
169244
boolean isOneOffEntryId = (item.data[pos] & 0x80) > 0;
170245
pos++;
171-
int wrappedflags = (int)PSTObject.convertLittleEndianBytesToLong(item.data, pos, pos+4);
172-
pos += 4;
246+
int wrappedflags = (int)PSTObject.convertLittleEndianBytesToLong(
247+
item.data, pos, pos + 4);
248+
pos += 4;
173249

174-
byte[] guid2 = new byte[16];
175-
System.arraycopy(item.data, pos, guid, 0, guid.length);
176-
pos += 16;
250+
byte[] guid2 = new byte[16];
251+
System.arraycopy(item.data, pos, guid, 0, guid.length);
252+
pos += 16;
177253

178-
int descriptorIndex = (int)PSTObject.convertLittleEndianBytesToLong(item.data, pos, pos+3);
179-
pos += 3;
254+
int descriptorIndex = (int)PSTObject.convertLittleEndianBytesToLong(
255+
item.data, pos, pos + 3);
256+
pos += 3;
180257

181-
byte empty = item.data[pos];
182-
pos++;
258+
byte empty = item.data[pos];
259+
pos++;
183260

184-
out[x] = PSTObject.detectAndLoadPSTObject(this.pstFile, descriptorIndex);
261+
out[x] = PSTObject.detectAndLoadPSTObject(this.pstFile, descriptorIndex);
185262

186263
} else if (Arrays.equals(guid, oneOffEntryIdUid)) {
187264
OneOffEntry entry = parseOneOffEntry(item.data, pos);
188265
pos = entry.pos;
189-
out[x] = entry;
266+
out[x] = entry;
190267
}
191268
}
192-
}
193-
return out;
194-
}
269+
}
270+
return out;
271+
}
195272
}

0 commit comments

Comments
 (0)