diff --git a/Core/EwsHttpWebRequest.cs b/Core/EwsHttpWebRequest.cs index 65a9c7b1..141e1fd5 100644 --- a/Core/EwsHttpWebRequest.cs +++ b/Core/EwsHttpWebRequest.cs @@ -89,8 +89,8 @@ public async Task GetResponse(CancellationToken token) { var message = new HttpRequestMessage(new HttpMethod(Method), RequestUri); message.Content = new StringContent(Content); - //if (!string.IsNullOrEmpty(ContentType)) - // message.Content.Headers.ContentType = new MediaTypeHeaderValue(ContentType); + if (!string.IsNullOrEmpty(ContentType)) + message.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(ContentType); if (!string.IsNullOrEmpty(UserAgent)) { diff --git a/Core/ExchangeService.cs b/Core/ExchangeService.cs index a1f3d4f6..1c75dde9 100644 --- a/Core/ExchangeService.cs +++ b/Core/ExchangeService.cs @@ -2900,6 +2900,25 @@ public Task GetUserAvailability( } #endregion + #region MailTips operations + /// + /// Gets MailTips for given users. Calling this method results in a call to EWS. + /// + /// E-mail address that a user is trying to send as. + /// Collection of recipients that would receive a copy of the message. + /// Mail tips requested from the service. + /// List of GetMailTips results. + public Task GetMailTips(string sendingAs, Mailbox[] recipients, MailTipsRequested requested, CancellationToken token = default(CancellationToken)) + { + GetMailTipsRequest request = new GetMailTipsRequest(this); + request.SendingAs = sendingAs; + request.Recipients = recipients; + request.MailTipsRequested = requested; + + return request.Execute(token); + } + #endregion + #region Conversation /// /// Retrieves a collection of all Conversations in the specified Folder. diff --git a/Core/Requests/GetMailTipsRequest.cs b/Core/Requests/GetMailTipsRequest.cs new file mode 100644 index 00000000..5cc2084e --- /dev/null +++ b/Core/Requests/GetMailTipsRequest.cs @@ -0,0 +1,146 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Exchange.WebServices.Data +{ + /// + /// Represents a GetMailTips request. + /// + internal sealed class GetMailTipsRequest : SimpleServiceRequestBase + { + //https://msdn.microsoft.com/en-us/library/office/dd877060(v=exchg.140).aspx [GetMailTips Operation][2010] + //https://msdn.microsoft.com/en-us/library/office/dd877060(v=exchg.150).aspx [GetMailTips Operation][2013] + private MailTipsRequested requestedMailTips; + + /// + /// Initializes a new instance of the class. + /// + /// The service. + internal GetMailTipsRequest(ExchangeService service) + : base(service) + { + } + + /// + /// Gets the name of the XML element. + /// + /// XML element name + internal override string GetXmlElementName() { return XmlElementNames.GetMailTips; } + + /// Writes XML elements. + /// The writer. + internal override void WriteElementsToXml(EwsServiceXmlWriter writer) + { + SendingAs.WriteToXml(writer, XmlNamespace.Messages, XmlElementNames.SendingAs); + + writer.WriteStartElement(XmlNamespace.Messages, XmlElementNames.Recipients); + foreach (var mbox in Recipients) + { + mbox.WriteToXml(writer, XmlNamespace.Types, XmlElementNames.Mailbox); + } + writer.WriteEndElement(); // + + writer.WriteElementValue(XmlNamespace.Messages, XmlElementNames.MailTipsRequested, requestedMailTips); + } + + /// Gets the name of the response XML element. + /// XML element name + internal override string GetResponseXmlElementName() { return XmlElementNames.GetMailTipsResponse; } + + /// Parses the response. + /// The reader. + /// Response object. + internal override object ParseResponse(EwsServiceXmlReader reader) + { + GetMailTipsResults serviceResponse = new GetMailTipsResults(); + serviceResponse.LoadFromXml(reader, XmlElementNames.GetMailTipsResponse); + //if (serviceResponse.ErrorCode != ServiceError.NoError) + return serviceResponse; + } + + /// Gets the request version. + /// Earliest Exchange version in which this request is supported. + internal override ExchangeVersion GetMinimumRequiredServerVersion() + { + return ExchangeVersion.Exchange2010; + } + + /// Executes this request. + /// Service response. + internal async Task Execute(CancellationToken token) + { + return (GetMailTipsResults)(await this.InternalExecuteAsync(token).ConfigureAwait(false)); + } + + /// Gets or sets the attendees. + public EmailAddress SendingAs { get; set; } + + /// Gets or sets the requested MailTips. + public MailTipsRequested MailTipsRequested + { + get { return this.requestedMailTips; } + set { this.requestedMailTips = value; } + } + + /// + /// Gets or sets who are the recipients/targets whose MailTips we are interested in. + /// + public Mailbox[] Recipients { get; set; } + } + + /// + /// Defines the types of requested mail tips. + /// + public enum MailTipsRequested + { + /// + /// Represents all available mail tips. + /// + All, + + /// + /// Represents the Out of Office (OOF) message. + /// + OutOfOfficeMessage, + + /// + /// Represents the status for a mailbox that is full. + /// + MailboxFullStatus, + + /// + /// Represents a custom mail tip. + /// + CustomMailTip, + + /// + /// Represents the count of external members. + /// + ExternalMemberCount, + + /// + /// Represents the count of all members. + /// + TotalMemberCount, + + /// + /// Represents the maximum message size a recipient can accept. + /// + MaxMessageSize, + + /// + /// Indicates whether delivery restrictions will prevent the sender's message from reaching the recipient. + /// + DeliveryRestriction, + + /// + /// Indicates whether the sender's message will be reviewed by a moderator. + /// + ModerationStatus, + + /// + /// Indicates whether the recipient is invalid. + /// + InvalidRecipient + } +} diff --git a/Core/Responses/GetMailTipsResults.cs b/Core/Responses/GetMailTipsResults.cs new file mode 100644 index 00000000..459e818e --- /dev/null +++ b/Core/Responses/GetMailTipsResults.cs @@ -0,0 +1,51 @@ + +namespace Microsoft.Exchange.WebServices.Data +{ + /// + /// Represents the results of a GetMailTips operation. + /// + public sealed class GetMailTipsResults : ServiceResponse + { + private ServiceResponseCollection responseCollection; + + /// + /// Initializes a new instance of the class. + /// + internal GetMailTipsResults():base() { } + + /// + /// Reads response elements from XML. + /// + /// The reader. + internal override void ReadElementsFromXml(EwsServiceXmlReader reader) + { + responseCollection = new ServiceResponseCollection(); + base.ReadElementsFromXml(reader); + reader.ReadStartElement(XmlNamespace.Messages, XmlElementNames.ResponseMessages); + + if (!reader.IsEmptyElement) + { + // Because we don't have count of returned objects + // test the element to determine if it is return object or EndElement + reader.Read(); + while (reader.IsStartElement(XmlNamespace.Messages, XmlElementNames.MailTipsResponseMessageType)) + { + MailTipsResponseMessage mrm = new MailTipsResponseMessage(); + mrm.LoadFromXml(reader, XmlElementNames.MailTipsResponseMessageType); + this.responseCollection.Add(mrm); + reader.Read(); + } + reader.EnsureCurrentNodeIsEndElement(XmlNamespace.Messages, XmlElementNames.ResponseMessages); + } + } + + /// + /// Gets a collection of MailTips responses for the requested recipients + /// + public ServiceResponseCollection MailTipsResponses + { + get { return responseCollection; } + internal set { responseCollection = value; } + } + } +} diff --git a/Core/Responses/MailTipsResponseMessage.cs b/Core/Responses/MailTipsResponseMessage.cs new file mode 100644 index 00000000..def6dd3f --- /dev/null +++ b/Core/Responses/MailTipsResponseMessage.cs @@ -0,0 +1,188 @@ +using System; + +namespace Microsoft.Exchange.WebServices.Data +{ + /// + /// Represents the MailTips of an individual recipient. + /// + public sealed class MailTipsResponseMessage : ServiceResponse + { + private Mailbox recipientAddress; + private bool? mailboxFull, isInvalid, isModerated, deliveryRestricted; + private string customMailTip, pendingMailTips; + private int? totalMemberCount, externalMemberCount, maxMessageSize; + + private OutOfOfficeMessage oof; + + /// + /// Initializes a new instance of the class. + /// + internal MailTipsResponseMessage() : base() { } + + /// + /// Reads response elements from XML. + /// + /// + /// The reader. + /// + internal override void ReadElementsFromXml(EwsServiceXmlReader reader) + { + base.ReadElementsFromXml(reader); + + reader.ReadStartElement(XmlNamespace.Messages, XmlElementNames.MailTips); + reader.ReadStartElement(XmlNamespace.Types, XmlElementNames.RecipientAddress); + reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.Name); + var email = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.EmailAddress); + var routing = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.RoutingType); + recipientAddress = new Mailbox(email, routing); + + reader.ReadEndElementIfNecessary(XmlNamespace.Types, XmlElementNames.RecipientAddress); + pendingMailTips = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.PendingMailTips); + reader.Read(); + + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.MailboxFull)) + { + var mfTextValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.MailboxFull); + mailboxFull = System.Convert.ToBoolean(mfTextValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.CustomMailTip)) + { + customMailTip = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.CustomMailTip); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.TotalMemberCount)) + { + var textValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.TotalMemberCount); + totalMemberCount = System.Convert.ToInt32(textValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.MaxMessageSize)) + { + var textValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.MaxMessageSize); + maxMessageSize = System.Convert.ToInt32(textValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.DeliveryRestricted)) + { + var restrictionTextValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.DeliveryRestricted); + deliveryRestricted = System.Convert.ToBoolean(restrictionTextValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.IsModerated)) + { + var moderationTextValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.IsModerated); + isModerated = System.Convert.ToBoolean(moderationTextValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.InvalidRecipient)) + { + var invalidRecipientTextValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.InvalidRecipient); + isInvalid = System.Convert.ToBoolean(invalidRecipientTextValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.ExternalMemberCount)) + { + var textValue = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.ExternalMemberCount); + externalMemberCount = System.Convert.ToInt32(textValue); + reader.Read(); + } + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.OutOfOffice)) + { + reader.Read(); + + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.ReplayBody)) + { + var msg = reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.Message); + DateTime? startTime = null; + DateTime? endTime = null; + reader.Read(); + reader.Read(); + if (reader.IsStartElement(XmlNamespace.Types, XmlElementNames.Duration)) + { + startTime = DateTime.Parse(reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.StartTime)); + endTime = DateTime.Parse(reader.ReadElementValue(XmlNamespace.Types, XmlElementNames.EndTime)); + reader.Read(); + reader.Read(); + } + oof = new OutOfOfficeMessage(msg, startTime, endTime); + reader.Read(); + } + } + reader.ReadEndElementIfNecessary(XmlNamespace.Messages, XmlElementNames.MailTips); + } + + // MailTips node: https://msdn.microsoft.com/en-us/library/dd899507(v=exchg.140).aspx + + /// + /// Represents the mailbox of the recipient. + /// + public Mailbox RecipientAddress { get { return recipientAddress; } } + + /// + /// Indicates that the mail tips in this element could not be evaluated before the server's processing timeout expired. + /// + public string PendingMailTips { get { return pendingMailTips; } } + + /// + /// Represents the response message and a duration time for sending the response message. + /// + public OutOfOfficeMessage OutOfOffice { get { return oof; } } + + /// + /// Indicates whether the mailbox for the recipient is full. + /// + public bool? MailboxFull { get { return mailboxFull; } } + + /// + /// Represents a customized mail tip message. + /// + public string CustomMailTip { get { return customMailTip; } } + + /// + /// Represents the count of all members in a group. + /// + public int? TotalMemberCount { get { return totalMemberCount; } } + + /// + /// Represents the count of external members in a group. + /// + public int? ExternalMemberCount { get { return externalMemberCount; } } + + /// + /// Represents the maximum message size the recipient can accept. + /// + public int? MaxMessageSize { get { return maxMessageSize; } } + + /// + /// Indicates whether delivery restrictions will prevent the sender's message from reaching the recipient. + /// + public bool? DeliveryRestricted { get { return deliveryRestricted; } } + + /// + /// Indicates whether the recipient's mailbox is being moderated. + /// + public bool? IsModerated { get { return isModerated; } } + + /// + /// Indicates whether the recipient is invalid. + /// + public bool? InvalidRecipient { get { return isInvalid; } } + } + + public class OutOfOfficeMessage + { + public OutOfOfficeMessage(string message, DateTime? startTime, DateTime? endTime) + { + Message = message; + StartTime = startTime; + EndTime = endTime; + } + + public string Message { get; } + + public DateTime? StartTime { get; } + + public DateTime? EndTime { get; } + } +} \ No newline at end of file diff --git a/Core/Responses/ServiceResponse.cs b/Core/Responses/ServiceResponse.cs index 8698ef1e..a84d1f60 100644 --- a/Core/Responses/ServiceResponse.cs +++ b/Core/Responses/ServiceResponse.cs @@ -96,13 +96,22 @@ internal void LoadFromXml(EwsServiceXmlReader reader, string xmlElementName) { this.errorMessage = reader.ReadElementValue(XmlNamespace.Messages, XmlElementNames.MessageText); } + else + { + reader.ReadElementValue(); + if (reader.IsStartElement(XmlNamespace.Messages, XmlElementNames.MessageText)) + { + this.errorMessage = reader.ReadElementValue(XmlNamespace.Messages, XmlElementNames.MessageText); + } + } this.errorCode = reader.ReadElementValue(XmlNamespace.Messages, XmlElementNames.ResponseCode); if (this.result == ServiceResult.Warning) { reader.ReadElementValue(XmlNamespace.Messages, XmlElementNames.DescriptiveLinkKey); - } + } + // If batch processing stopped, EWS returns an empty element. Skip over it. if (this.BatchProcessingStopped) diff --git a/Core/XmlElementNames.cs b/Core/XmlElementNames.cs index 2b1bf60c..79ff419a 100644 --- a/Core/XmlElementNames.cs +++ b/Core/XmlElementNames.cs @@ -1166,6 +1166,29 @@ internal static class XmlElementNames public const string IsLessThanOrEqualTo = "IsLessThanOrEqualTo"; #endregion + #region MailTips + public const string GetMailTips = "GetMailTips"; + public const string MailTipsRequested = "MailTipsRequested"; + public const string GetMailTipsResponse = "GetMailTipsResponse"; + public const string GetMailTipsResponseArray = "ResponseMessages"; + public const string MailTipsResponseMessageType = "MailTipsResponseMessageType"; + public const string MailTips = "MailTips"; + public const string PendingMailTips = "PendingMailTips"; + public const string CustomMailTip = "CustomMailTip"; + public const string SendingAs = "SendingAs"; + public const string Recipients = "Recipients"; + public const string RecipientAddress = "RecipientAddress"; + public const string OutOfOffice = "OutOfOffice"; + public const string ReplayBody = "ReplyBody"; + public const string IsModerated = "IsModerated"; + public const string MailboxFull = "MailboxFull"; + public const string InvalidRecipient = "InvalidRecipient"; + public const string DeliveryRestricted = "DeliveryRestricted"; + public const string ExternalMemberCount = "ExternalMemberCount"; + public const string TotalMemberCount = "TotalMemberCount"; + public const string MaxMessageSize = "MaxMessageSize"; + #endregion + #region Directory only contact properties public const string PhoneticFullName = "PhoneticFullName"; public const string PhoneticFirstName = "PhoneticFirstName";