Skip to content

Commit 6ad9f65

Browse files
author
pborissow
committed
- Added content ID to attachments. Important for retrieving inline attachments in a message body.
- Updated the way email attachments are identified and sorted. Now using the PR_HASATTACH (0x0e1b000b) extended MAPI property instead of "HasAttachments". - Updated logic used to parse GetItems response in the EmailFolder to include generic "Items" such as sharing requests. - Refactored the orderBy parameter in the Folder.getItems() method to accept an array of FieldOrder objects instead of a string. This helps simplify logic used to sort by extended properties such as PR_HASATTACH. git-svn-id: svn://192.168.0.80/JavaXT/javaxt-exchange@427 2c7b0aa6-e0b2-3c4e-bb4a-8b65b6c465ff
1 parent 1ead74f commit 6ad9f65

File tree

7 files changed

+289
-46
lines changed

7 files changed

+289
-46
lines changed

src/javaxt/exchange/Attachment.java

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
public class Attachment {
1414

1515
private String id;
16+
private String cid;
1617
private String name;
1718
private String contentType;
1819
private String type; //FileAttachment or ItemAttachment
@@ -91,22 +92,61 @@ else if(nodeName.equalsIgnoreCase("Name")){
9192
else if(nodeName.equalsIgnoreCase("ContentType")){
9293
contentType = javaxt.xml.DOM.getNodeValue(childNode);
9394
}
95+
else if(nodeName.equalsIgnoreCase("ContentID")){
96+
cid = javaxt.xml.DOM.getNodeValue(childNode);
97+
}
9498
}
9599
}
96100
}
97-
101+
102+
103+
//**************************************************************************
104+
//** getID
105+
//**************************************************************************
106+
/** Returns the unique ID of the attachment.
107+
*/
98108
public String getID(){
99109
return id;
100110
}
101111

112+
113+
//**************************************************************************
114+
//** getName
115+
//**************************************************************************
116+
/** Returns the name of the attachment (e.g. "Resume.doc").
117+
*/
102118
public String getName(){
103119
return name;
104120
}
105121

122+
123+
//**************************************************************************
124+
//** getContentType
125+
//**************************************************************************
126+
/** Returns the mime type associated with the attachment (e.g. "image/jpeg").
127+
*/
106128
public String getContentType(){
107129
return contentType;
108130
}
109131

132+
133+
//**************************************************************************
134+
//** getContentID
135+
//**************************************************************************
136+
/** Returns the content id (cid) associated with this attachment. This is
137+
* useful for resolving inline attachments (e.g. images) found in email
138+
* messages, calendar invites, and other folder items.
139+
*/
140+
public String getContentID(){
141+
return cid;
142+
}
143+
144+
145+
//**************************************************************************
146+
//** toString
147+
//**************************************************************************
148+
/** Returns the name of the attachment (e.g. "Resume.doc").
149+
*/
110150
public String toString(){
111151
return name;
112152
}
@@ -252,14 +292,23 @@ private java.io.InputStream parseResponse(java.io.InputStream inputStream, boole
252292
if (nodeName.contains(" ")) nodeName = nodeName.substring(0, nodeName.indexOf(" "));
253293
if (nodeName.contains(":")) nodeName = nodeName.substring(nodeName.indexOf(":")+1);
254294

255-
295+
256296
if (nodeName.equalsIgnoreCase("Name")){
257297
name = getNodeValue(inputStream);
258298
}
259299
else if(nodeName.equalsIgnoreCase("ContentType")){
260300
contentType = getNodeValue(inputStream);
261301
}
262-
302+
else if(nodeName.equalsIgnoreCase("ContentId")){
303+
cid = getNodeValue(inputStream);
304+
}
305+
else if(nodeName.equalsIgnoreCase("FileAttachment")){
306+
type = "FileAttachment";
307+
}
308+
else if (nodeName.equalsIgnoreCase("ItemAttachment")){
309+
type = "ItemAttachment";
310+
}
311+
263312
if (nodeName.toLowerCase().endsWith("responsemessage")){
264313
if (node.toLowerCase().contains("error")){
265314
if (!node.endsWith("/>")) node = node.substring(0, node.length()-1) + "/>";
@@ -322,6 +371,7 @@ private String getNodeValue(java.io.InputStream inputStream) throws java.io.IOEx
322371
public static class ContentInputStream extends java.io.InputStream {
323372

324373
private java.io.InputStream inputStream;
374+
private boolean EOF = false;
325375

326376
protected ContentInputStream(java.io.InputStream inputStream){
327377
this.inputStream = inputStream;
@@ -344,21 +394,32 @@ public boolean markSupported(){
344394
public int read() throws IOException {
345395

346396
int x = inputStream.read();
347-
if (x==-1) return -1;
397+
if (x==-1){
398+
EOF = true;
399+
return -1;
400+
}
348401
else{
402+
if (EOF) return -1;
349403
char c = (char) x;
350404
if (c == '<'){
405+
EOF = true;
351406
return -1;
352407
}
353408
else if (c==' '){
354409
while ( (x = inputStream.read()) != -1) {
355410
c = (char) x;
356-
if (c == '<') return -1;
411+
if (c == '<'){
412+
EOF = true;
413+
return -1;
414+
}
357415
if (c != ' ') return x;
358416
}
417+
EOF = true;
359418
return -1;
360419
}
361-
else return x;
420+
else{
421+
return x;
422+
}
362423
}
363424
}
364425
}

src/javaxt/exchange/Email.java

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ else if(nodeName.equalsIgnoreCase("DateTimeReceived")){
203203
}
204204

205205
//Update the sent and received timestamps as needed
206-
if (isDraft) sent = received = null;
206+
//if (isDraft) sent = received = null;
207207

208208

209209
//Find the PR_LAST_VERB_EXECUTED (0x10810003) extended MAPI property
@@ -239,24 +239,39 @@ else if(nodeName.equalsIgnoreCase("DateTimeReceived")){
239239
ExtendedFieldURI property = it.next();
240240
if (property.getName().equalsIgnoreCase("0xC1F")){
241241
String email = extendedProperties.get(property).toString();
242-
if (from!=null){
243-
if (from.getEmailAddress()==null){
242+
243+
if (from==null){ //Example: Sharing Request
244+
EmailAddress _null = null;
245+
from = new Mailbox(null, _null);
246+
}
247+
248+
if (from.getEmailAddress()==null){
244249

245-
if (!email.contains("@")){
246-
from.setDomainAddress(email); //<--For performance reasons, don't resolve the domain address!
247-
}
248-
else{
249-
try{
250-
from.setEmailAddress(email);
251-
}
252-
catch(ExchangeException e){}
250+
if (!email.contains("@")){
251+
from.setDomainAddress(email); //<--For performance reasons, don't resolve the domain address!
252+
}
253+
else{
254+
try{
255+
from.setEmailAddress(email);
253256
}
257+
catch(ExchangeException e){}
254258
}
255259
}
256260
extendedProperties.remove(property);
257261
break;
258262
}
259263
}
264+
265+
//Find the PR_HASATTACH (0x0e1b000b) extended MAPI property
266+
it = extendedProperties.keySet().iterator();
267+
while(it.hasNext()){
268+
ExtendedFieldURI property = it.next();
269+
if (property.getName().equalsIgnoreCase("0xE1B")){
270+
hasAttachments = extendedProperties.get(property).toBoolean();
271+
extendedProperties.remove(property);
272+
break;
273+
}
274+
}
260275
}
261276

262277

@@ -576,6 +591,61 @@ public Mailbox[] getBccRecipients(){
576591
}
577592

578593

594+
//**************************************************************************
595+
//** isSharingRequest
596+
//**************************************************************************
597+
/** Returns true if the message is an invitation to share a calendar
598+
* or contact folder.
599+
*/
600+
public boolean isSharingRequest(){
601+
return itemClass.equalsIgnoreCase("IPM.Sharing");
602+
}
603+
604+
605+
//**************************************************************************
606+
//** acceptSharingRequest
607+
//**************************************************************************
608+
/** Used to accept a sharing invitation, allowing another user access to
609+
* view the calendar or contacts data.
610+
*/
611+
public void acceptSharingRequest(Connection conn) throws ExchangeException {
612+
if (!isSharingRequest()) return;
613+
614+
/*NOTE: This method fails on my 2010 server. It complains that that the
615+
request is invalid:
616+
617+
The request failed schema validation: The element 'Items' in namespace
618+
'http://schemas.microsoft.com/exchange/services/2006/messages' has
619+
invalid child element 'AcceptSharingInvitation' in namespace
620+
'http://schemas.microsoft.com/exchange/services/2006/types'.
621+
622+
This message doesn't make sense! The documentation clearly indicates
623+
that AcceptSharingInvitation is a child of Items:
624+
http://msdn.microsoft.com/en-us/library/aa565652%28v=exchg.140%29.aspx
625+
626+
Also, check out the example from Microsoft for how to accept a sharing
627+
request:
628+
http://msdn.microsoft.com/en-us/library/exchange/ee693280%28v=exchg.140%29.aspx
629+
*/
630+
631+
632+
StringBuffer msg = new StringBuffer();
633+
msg.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
634+
msg.append("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\">");
635+
msg.append("<soap:Body>");
636+
msg.append("<m:CreateItem MessageDisposition=\"" + "SendOnly" + "\">");
637+
msg.append("<m:Items>");
638+
msg.append("<t:AcceptSharingInvitation>");
639+
msg.append("<t:ReferenceItemId Id=\"" + this.getID() + "\" ChangeKey=\"" + this.getChangeKey(conn) + "\" />");
640+
msg.append("</t:AcceptSharingInvitation>");
641+
msg.append("</m:Items>");
642+
msg.append("</m:CreateItem>");
643+
msg.append("</soap:Body>");
644+
msg.append("</soap:Envelope>");
645+
conn.execute(msg.toString());
646+
}
647+
648+
579649
//**************************************************************************
580650
//** delete
581651
//**************************************************************************

src/javaxt/exchange/EmailFolder.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ public EmailFolder(String folderName, Connection conn) throws ExchangeException
3939

4040
//Add the PR_SENDER_EMAIL_ADDRESS (0x0c1f001e) extended MAPI property.
4141
props.add(new ExtendedFieldURI(null, "0x0C1F", "String"));
42+
43+
//Add the PR_HASATTACH (0x0e1b000b) extended MAPI property. This property
44+
//is used to indicate whether the message has an attachment. Note that
45+
//the item:HasAttachments doesn't reveal "hidden" attachments. Also,
46+
//you cannot perform compound (multidimensional) sorts on the
47+
//item:HasAttachments field.
48+
props.add(new ExtendedFieldURI(null, "0x0E1B", "Boolean"));
4249
}
4350

4451

@@ -75,26 +82,39 @@ public static Folder[] getMailFolders(Connection conn) throws ExchangeException
7582
* <a href="http://msdn.microsoft.com/en-us/library/aa563791%28v=exchg.140%29.aspx">
7683
* Restriction</a>. Null values imply no restriction.
7784
*
78-
* @param orderBy. SQL-style order by clause used to sort the response
79-
* (e.g. "item:DateTimeReceived DESC"). This parameter is optional. A null
80-
* value implies no sort preference.
8185
*/
82-
public Email[] getMessages(int offset, int limit, FieldURI[] additionalProperties, String where, String orderBy) throws ExchangeException {
86+
public Email[] getMessages(int offset, int limit, FieldURI[] additionalProperties, String where, FieldOrder[] sortOrder) throws ExchangeException {
8387

84-
//Merge additional properties
88+
//Merge additional properties with default properties
8589
java.util.HashSet<FieldURI> props = getDefaultProperties();
8690
if (additionalProperties!=null){
8791
for (FieldURI property : additionalProperties) props.add(property);
8892
}
8993

94+
//Execute GetItems request
9095
java.util.ArrayList<Email> messages = new java.util.ArrayList<Email>();
91-
org.w3c.dom.NodeList nodes = getItems(offset, limit, props, where, orderBy).getElementsByTagName("t:Message");
96+
org.w3c.dom.Document xml = getItems(offset, limit, props, where, sortOrder);
97+
98+
99+
//Parse email messages
100+
org.w3c.dom.NodeList nodes = xml.getElementsByTagName("t:Message");
101+
for (int i=0; i<nodes.getLength(); i++){
102+
org.w3c.dom.Node node = nodes.item(i);
103+
if (node.getNodeType()==1){
104+
messages.add(new Email(node));
105+
}
106+
}
107+
108+
109+
//Parse Item nodes (e.g. Sharing Request)
110+
nodes = xml.getElementsByTagName("t:Item");
92111
for (int i=0; i<nodes.getLength(); i++){
93112
org.w3c.dom.Node node = nodes.item(i);
94113
if (node.getNodeType()==1){
95114
messages.add(new Email(node));
96115
}
97116
}
117+
98118
return messages.toArray(new Email[messages.size()]);
99119
}
100120

src/javaxt/exchange/ExtendedFieldURI.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public class ExtendedFieldURI extends FieldURI {
2020
/** Creates a new instance of this class.
2121
* @param id A unique id in the form of a Microsoft GUID.
2222
* @param name Property name.
23-
* @param name Property type (e.g. "String", "Integer", "SystemTime", etc).
23+
* @param name Property type (e.g. "String", "Integer", "Boolean",
24+
* "SystemTime", etc).
2425
*/
2526
public ExtendedFieldURI(String id, String name, String type){
2627
this.id = id;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy