Public API Mail WCF
Basics
The MailWCF is a WCF interface of the inPoint server, which allows to archive emails. Can be accessed by the following address:
http://%SERVERNAME%/Pam.Web/MailWCF.svc
It's strongly advised to use "net.pipe"
or "net.tcp"
to access it.
Required StorageDocument properties
When a document is archived in inPoint, the StorageDocument object should contain the following document properties:
-
CONTENTACCESSID (varchar(256), null) - identification of the document inside contentACCESS
-
MAILBOX_GUID (varchar(38), null) - identification of the mailbox inside contentACCESS
-
SUBJECT (nvarchar(2000), null)
-
MAIL_CC (nvarchar(max), null)
-
MAIL_TO (nvarchar(max), null)
-
MAIL_FROM (nvarchar(max), null)
-
MAIL_BCC (nvarchar(max), null)
-
EWS_ID (varchar(512), null) - internet message ID
-
SENTDATE (datetime, null)
-
RECEIVEDDATE (datetime, null)
-
MODIFIEDDATE (datetime, null)
-
ATTACHMENTCOUNT (int, null)
-
MESSAGECLASS (varchar(256), null) - The message class for an item is used to identify the form that should be used to display the item. For more information see: Microsoft Documentation Item Types and Message Classes
-
IMPORTANCE (int, null) - sets the priority for the message
-
ACTION_DATE (datetime, null) - date of the reply or forward. If the mail was not replied or forwarded, the value is the SQL MINDATE (1753-01-01 00:00:00.000).
-
ACTION (int, null) - corresponds to PidTagIconIndex property, which is a hint to the client to display the icon of the mail. The value 261 corresponds to Replied mail, value 262 corresponds to Forwarded mail. The ACTION metadata decides which message class will be used:
Action
lower or equals to 0 -- IPM.Note.CAAction
= 261 -- IPM.Note.CA.RAction
= 262 -- IPM.Note.CA.F
/// Possible values of the ACTION field in the DocProperties property of the StorageDocument object
/// </summary>
public enum MailAction
{
/// <summary>
/// Not set
/// </summary>
NotSet = 0,
/// <summary>
/// Reply
/// </summary>
MailReplied = 261,
/// <summary>
/// Forward
/// </summary>
MailForwarded = 262
}
- MESSAGEFLAGS (int, null)
- SENSITIVITY (int, null)
- MESSAGESIZE (bigint, null)
- LASTVERBEXECUTED (smallint, null) - corresponds to PidTagLastVerbExecuted property. This property contains the last VERB which was executed on the mail. Value 102 represents Reply, 103 represents ReplyAll and value 104 represents the verb Forward.
API
The emails can be archived/retrieved using the following MailWCF-API.
For performance reasons don't use http
but net.tcp
or net.pipe
!
Create Project in VS
To create a proxy, add a service reference to your project!
e.g. use net.pipe://localhost/MailWCF.svc
as address
Interface IInPointAccess
This is the main interface for mail archiving and retrieval.
ArchiveDocument
Method for archiving an email to inPoint.
/// <summary>
/// Archives an email to inPoint.
/// </summary>
/// <param name="document">Document to be archived. The DocProperties property of the StorageDocument class has to contain the CONTENTACCESSID document property.</param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns>Returns the MailContents with ItemUri and ConIds</returns>
[OperationContract]
MailContents ArchiveDocumentEx(StorageDocument document, CallOptions callOptions);
/// <summary>
/// Obsolete. Use the ArchiveDocumentEx WCF method instead.
/// </summary>
/// <param name="document"></param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns></returns>
[OperationContract]
string ArchiveDocument(StorageDocument document, CallOptions callOptions);
/// <summary>
/// Mail properties used for archiving/updating the mail to inPoint.
/// </summary>
[DataContract]
[DebuggerDisplay("itemUri={itemUri} Title={Title} MessageId={MessageId}")]
public class StorageDocument
{
/// <summary>
/// Item uri of the archived mail.
/// </summary>
[DataMember]
public string itemUri;
/// <summary>
/// Title.
/// </summary>
[DataMember]
public string Title;
/// <summary>
/// Document properties
/// </summary>
[DataMember]
public List<DocProperty> DocProperties;
/// <summary>
/// Message Id
/// </summary>
[DataMember]
public string MessageId;
/// <summary>
/// EwsId
/// </summary>
[DataMember]
public string EwsId;
/// <summary>
/// Path of the folder. Folders are separated with backslash.
/// </summary>
[DataMember]
public string Folder;
// Email address of the mailbox
// In the case of Public folders = \'Public folders\' - configurable localization, etc\...
[DataMember]
public string MailboxId;
// Mailbox display name. inPoint also needs to display something as the root folder\...
// In the case of Public folders = \'Public folders\' - configurable
localization, etc\...
[DataMember]
public string MailboxName;
/// <summary>
/// Retention time in months
/// </summary>
[DataMember(EmitDefaultValue = false)]
public int? ExplicitRetentionTimeMonths;
/// <summary>
/// Enables the caller to explicitly set a storage scheme for all contents while saving a document.
/// </summary>
[DataMember(EmitDefaultValue = false)]
public int ExplicitStorageScheme;
// The Contents are only filled for document retrieval
[DataMember]
public List<UploadContent> Content;
}
/// <summary>
/// Contains the content information after archiving/updating the mail.
/// </summary>
[DataContract]
[DebuggerDisplay("itemUri={itemUri}")]
public class MailContents
{
public MailContents()
{
Content = new List<UploadContent>();
}
/// <summary>
/// The item uri of the mail after the archiving.
/// </summary>
[DataMember]
public string itemUri;
/// <summary>
/// Content information after archiving/updating the mail.
/// </summary>
[DataMember]
public List<UploadContent> Content;
}
/// <summary>
/// Additional settings for a call.
/// </summary>
[DataContract]
[DebuggerDisplay("CallOptions: RawMode={RawMode}")]
public class CallOptions
{
/// <summary>
/// If true, the document will be read and written as it is. (No splitting/Joining of msg or eml-files is done)!
/// </summary>
[DataMember]
public bool RawMode {get;set;}
}
[DataContract]
[Serializable]
[DebuggerDisplay("Key={Key} Value={Value}")]
[KnownType(typeof(System.DBNull))]
public class DocProperty
{
[DataMember]
public string Key;
[DataMember]
public Object Value;
}
UpdateDocument
Method for updating an email in inPoint.
/// <summary>
/// Updates the email in the archive.
/// </summary>
/// <param name="sourceItemUri">
/// This is the location of the mail in the inPoint archive.
/// Contains the inPoint item URI in format: "pam-item://hierarchy=\...\@path=\...\@eid=\..."
/// The NEW location is specified in the Folder property of the <paramref name="document"/> parameter.
/// The location of the mail is not changed in the archive in the case when:
/// a. the original location defined in <paramref name="sourceItemUri"/> parameter equals to the location retrieved by the Folder property of the <paramref name="document"/> parameter.
/// b. the Folder property of the <paramref name="document"/> parameter is set to NULL (empty is RESERVED)
/// In both cases just the update of metadata or contents will be applied.
/// Mails moved to another folder within the same mailbox will change the MAILBOX\_DOCLINK link table entry only. The document metadata willremain. (DocumentMove).
/// Mails moved to another user should not duplicate the original msg in the HybridStore (HS). It will create a link to the same msg file in HS, but with different document metadata/itemuri (DocumentCopy).
/// </param>
/// <param name="document">Document to be updated or/and moved. Only those properties are set which has been changed, except the CONTENTACCESSID, which identifies the email.
///
/// The DocProperties property of the StorageDocument class has to contain the CONTENTACCESSID document property.
/// The DocProperties property of the StorageDocument class is not containing the MAILBOX\_GUID document property.
///
/// If any of the following properties of the <paramref name="document"/> parameter is NULL, then the document metadata will be not changed.
/// - document.Title
/// - document.EwsId
/// - document.MessageId
///
/// If the folderpath was not changed then the folderpath will be set to NULL
///
/// If the DocProperties property of the <paramref name="document"/> parameter is NOT NULL then:
/// a. if the Value property of the DocProperty is NULL => the value of the property will be set to NULL in the archive.
/// b. if the Value property of the DocProperty is NOT NULL => the value of the property will be set in the archive.
/// If the DocProperties property of the <paramref name="document"/> parameter is NULL, then the document metadata will be not changed.
///
/// If the Content property of the <paramref name="document"/> parameter is NOT NULL then:
/// a. if the ConId property and the UploadId property of the Content item is filled => the content specified by ConId will be replaced withthe uploaded content specified by UploadId.
/// b. if the ConId property is EMPTY and the UploadId property of the Content item is filled => the uploaded content specified by UploadId is added as new content to an existing document in the archive.
/// c. Delete the content specified by ConId if the Remove property of the UploadContent is set.
/// If the Content property of the <paramref name="document"/> parameter is NULL then the contents will be not changed.
/// </param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns>Returns the MailContents containing the:
/// - the inPoint item URI in format:"pam-item://hierarchy=\...\@path=\...\@eid=\...ItemUri and ConIds</returns>
[OperationContract]
MailContents UpdateDocument(String sourceItemUri, StorageDocument document, CallOptions callOptions);
Upload
Method for uploading an email to inPoint.
/// <summary>
/// Starts uploading a file to the inPoint server. Returns an id, which can be used to add chunks and for accessing it.
/// </summary>
/// <param name="data">Content of the file.</param>
/// <returns>Upload id to be used for accessing the file.</returns>
[OperationContract]
string StartUpload(byte[] data);
/// <summary>
/// Uploads another chunk of a file (Upload was started with <see cref="StartUpload"/>)
/// The whole content of the buffer will be added to the file.
/// </summary>
/// <param name="uploadId">id of the file.</param>
/// <param name="data">chunk to be uploaded</param>
/// <param name="position">continue writing of the file here</param>
[OperationContract]
void UploadChunk(string uploadId, byte[] data, Int64 position);
[DataContract]
[DebuggerDisplay("FileName={FileName} UploadId={UploadId}")]
public class UploadContent
{
/// <summary>
/// The id of this content.
/// </summary>
[DataMember]
public string ConId;
/// <summary>
/// Id of the file, used in upload and download.
/// </summary>
[DataMember]
public string UploadId;
/// <summary>
/// The name of the file.
/// </summary>
[DataMember]
public string FileName;
/// <summary>
/// The size of the file.
/// </summary>
[DataMember]
public Int64 FileSize;
/// <summary>
/// Index of the attachment within the mail.
/// </summary>
[DataMember]
public Int32 AttachmentIndex;
/// <summary>
/// Path of the attachment within the mail.
/// </summary>
[DataMember]
public string AttachmentPath;
/// <summary>
/// The checksum of the file (normaly a MD5 encoded as hex).
/// </summary>
[DataMember]
public string CheckSum;
/// <summary>
/// Content properties
/// </summary>
[DataMember]
public List<DocProperty> ConProperties;
/// <summary>
/// Not used yet.
/// </summary>
[DataMember]
public bool Remove;
}
Download
Method for downloading an email from inPoint.
/// <summary>
/// Download a chunk of the file.
/// </summary>
/// <param name="downloadId">id of the file</param>
/// <param name="position">offset for reading</param>
/// <param name="dataLength">how much data should be returned</param>
/// <returns>content of the file (can be less then length, if EOF is reached)</returns>
[OperationContract]
byte[] DownloadChunk(string downloadId, Int64 position, Int32 dataLength);
RetrieveDocument
Method for retrieving an email from inPoint.
/// <summary>
/// Retrieves a mail given by an itemUri, if the document cannot be found an exception will be thrown.
/// </summary>
/// <param name="itemUri">Uri of the email.</param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns>The document which was requested.</returns>
[OperationContract]
StorageDocument RetrieveDocument(string itemUri, CallOptions callOptions);
GetUriForEID (handling migrated mails)
Method for finding the Uri for the given eid.
/// <summary>
/// Gets the Uri for the eid.
/// </summary>
/// <param name="textEid">Eid of the email.</param>
/// <returns>The Uri for the eid. An exception will be thrown, if the Uri cannot be found for the given eid.</returns>
[OperationContract]
string GetUriForEID(string textEid);
GetItem
Method for getting an email from inPoint.
/// <summary>
/// Get the mail for the <paramref name="itemUri"/>.
/// </summary>
/// <param name="userId">This argument is ignored.</param>
/// <param name="folderId">This argument is ignored.</param>
/// <param name="itemUri">Item uri of the mail</param>
/// <param name="customPropertyNames">This argument is ignored. Should define the additional properties to return.</param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns>Returns the mail for the <paramref name="itemUri"/>.</returns>
[OperationContract]
StorageDocument GetItem(string userId, string folderId, string itemUri, List<string> customPropertyNames, CallOptions callOptions);
GetItems
Method for getting the mails belonging to the specific folder.
/// <summary>
/// Get the mails belonging to the folder specified by the given <paramref name="folderId"/> (item uri), after applying the paging option.
/// </summary>
/// <param name="userId">This argument is ignored.</param>
/// <param name="folderId">Item uri</param>
/// <param name="paging">Paging</param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns>Returns the list of mails in the folder for the given <paramref name="folderId"/> (item uri)</returns>
[OperationContract]
List<StorageDocument> GetItems(string userId, string folderId, RemotePagingOptions paging, CallOptions callOptions);
GetItemCount
Method for getting the number of mails belonging to the specific folder.
/// <summary>
/// Get the number of mails in the folder specified by the given <paramref name="folderId"/> (item uri), after applying filtering and pagig options.
/// </summary>
/// <param name="userId">This argument is ignored.</param>
/// <param name="folderId">Item uri</param>
/// <param name="paging">Paging</param>
/// <returns>Returns the number of mails in the folder for the given <paramref name="folderId"/> (item uri).</returns>
[OperationContract]
int GetItemCount(string userId, string folderId, RemotePagingOptions paging);
GetFolders
Method for getting the folders from inPoint.
/// <summary>
/// Get all folders for the given <paramref name="folderId"/> (item uri), to which the current authenticated (active) pam user user has access to.
/// </summary>
/// <param name="userId">This argument is ignored.</param>
/// <param name="folderId">Item uri</param>
/// <returns>List of folders for the given <paramrefname="folderId"/> (item uri).</returns>
[OperationContract]
List<RemoteFolder> GetFolders(string userId, string folderId);
/// <summary>
/// inPoint folder
/// </summary>
[DataContract]
[DebuggerDisplay("Name={Name} Path={Path} FolderId={FolderId}")]
public class RemoteFolder
{
/// <summary>
/// Item URI
/// </summary>
[DataMember]
public string FolderId;
/// <summary>
/// Name of the folder
/// </summary>
[DataMember]
public string Name;
/// <summary>
/// Path of the folder
/// </summary>
[DataMember]
public string Path;
}
DocumentPurge
Completely removes a mail from the inPoint archive. This cannot be undone!
/// <summary>
/// Completely removes a mail from the inPoint archive. This cannot be undone!
/// </summary>
/// <param name="itemUri">Uri of the email.</param>
[OperationContract]
void DocumentPurge(string itemUri);
Search
Search for mails with full-text matching the searchTerm and the other conditions specified in the argument.
/// <summary>
/// Search for mails with full-text matching the searchTerm and the other conditions specified in the argument.
/// </summary>
/// <param name="searchTerm">SearchTerm</param>
/// <param name="entitiesToSearch">List of item uris where the search should be performed.</param>
/// <param name="paging">Paging options</param>
/// <param name="recursiveSearch">If set, the search is evaluated in all subfolders specified in the <paramref name="entitiesToSearch"/>.</param>
/// <param name="callOptions">Additional options for the call.</param>
/// <returns>Returns a fulltext-result, which contains all mails found by the full-text search.</returns>
[OperationContract]
List<StorageDocument> Search(string searchTerm, List<string> entitiesToSearch, RemotePagingOptions paging, bool recursiveSearch, CallOptions callOptions);
/// <summary>
/// Remote paging options
/// </summary>
[DataContract]
public class RemotePagingOptions
{
/// <summary>
/// Paging starts from 1
/// </summary>
[DataMember]
public int start;
/// <summary>
/// Page size
/// </summary>
[DataMember]
public int count;
/// <summary>
/// Sorting.
/// </summary>
[DataMember]
public RemoteSortOptions sorting;
public override string ToString()
{
return String.Format("{0}: start=\'{1}\', count=\'{2}\', RemoteSortOptions=\'{3}\'",
"RemotePagingOptions",
start,
count,
sorting
);
}
}
/// <summary>
/// Remote sort options
/// </summary>
[DataContract]
public class RemoteSortOptions
{
/// <summary>
/// Column name
/// </summary>
[DataMember]
public string columnName;
/// <summary>
/// If set, sorting is ascending.
/// </summary>
[DataMember]
public bool ascending;
public override string ToString()
{
return String.Format("{0}: columnName=\'{1}\', ascending=\'{2}\'",
"RemoteSortOptions",
columnName,
ascending
);
}
}
GetAllEntities
Method for getting all mailboxes from inPoint.
/// <summary>
/// Gets all mailboxes (root entries).
/// </summary>
/// <returns>Complete list of distinct mailboxes.</returns>
[OperationContract]
List<Mailbox> GetAllEntities();
/// <summary>
/// Mailbox
/// </summary>
[DataContract]
[DebuggerDisplay("Name={Name} Path={Path} FolderId={FolderId}")]
public class Mailbox
{
/// <summary>
/// unique Id of the mailbox coming from contentACCESS which is not
changing
/// </summary>
[DataMember]
public string MailboxId;
/// <summary>
/// Mailbox display name. inPoint also needs to display something as the
root folder\...
/// </summary>
[DataMember]
public string MailboxName;
/// <summary>
/// FolderID (ItemURI in inPoint)
/// </summary>
[DataMember]
public string FolderId;
public override string ToString()
{
return String.Format("{0}: MailboxName=\'{1}\', MailboxId=\'{2}\', FolderId=\'{3}\'",
"Mailbox",
MailboxName ?? "<null>",
MailboxId ?? "<null>",
FolderId ?? "<null>");
}
}
GetAccessibleEntities
Method for getting all mailboxes ) to which the current authenticated (active) pam user user has access to.
/// <summary>
/// Get all mailboxes (root entries) to which the current authenticated (active) pam user user has access to.
/// </summary>
/// <param name="userId">This argument is ignored.</param>
/// <returns>Returns the list of mailboxes for the current user.</returns>
[OperationContract]
List<Mailbox> GetAccessibleEntities(string userId);
ListStorageSchemes
Method for getting all storageschemes from inPoint.
/// <summary>
/// Retrieves a list of possible storage schemes for the mail archive.
/// </summary>
/// <returns>A list of all possible storage schemes!</returns>
[OperationContract]
List<InPointAccess.StorageSchemeInfo> ListStorageSchemes();
[DataContract]
[Serializable]
[DebuggerDisplay("Id={Id} Name={Name}")]
public class StorageSchemeInfo
{
[DataMember]
public int Id;
[DataMember]
public String Name;
}
Reply and forward icons in mails
The standard contentACCESS shortcut is displaying a custom icon. This information is useful for the users because it distinguishes the archived item from a not archived one. However the user can't see whether the given item was replied or forwarded. This information is not visible on the archived item.
The goal of this feature is to present this forward or reply information to the user also on the archived items.
New metadata
The StorageDocument object has been extended by the following metadata:
- LASTVERBEXECUTED (smallint, null)
- ACTION (int, null)
- ACTIONDATE (datetime, null)
ACTIONDATE
- date of the reply or forward. If the mail was not replied
or forwarded, the value is the SQL MINDATE (1753-01-01 00:00:00.000).
ACTION
- corresponds to PidTagIconIndex property, which is a hint to
the client to display the icon of the mail. The value 261 corresponds to
Replied mail, value 262 corresponds to Forwarded mail.
LASTVERBEXECUTED
- corresponds to PidTagLastVerbExecuted property; this
property contains the last VERB which was executed on the mail. Value
102 represents Reply, 103 represents ReplyAll and value 104 represents
the verb Forward.
For the shortcut icon only the ACTION metadata is used - this decides which message class will be used:
Action
lower or equals to 0 -- IPM.Note.CAAction
= 261 -- IPM.Note.CA.RAction
= 262 -- IPM.Note.CA.F
The ACTIONDATE is important when rendering the mail in contentWEB. The LASTVERBEXECUTED and the ACTIONDATE are important during retrieve and restore.
On-the-fly update of the message
When the message is archived, the current snapshot of the mail is stored
- the current reply/forward status is saved. When the reply/forward status is changed later, the stored document is not changed (performance optimization and storage space considerations), only the database metadata are updated.
Since the stored document is the original snapshot, it is necessary to apply the last changes to it. During retrieve the document is retrieved from the store and the changes are applied on the mail (MSG file in temp folder). The modified mail is returned to the client.
The MD5 values of the files in the store are not modified.
Security
The mailbox permissions can be synchronized using the following MailWCF-API.
For performance reasons don't use http but net.tcp or net.pipe!
Synchronizing the Mailbox permissions
The interface method was defined as:
namespace InPointAccess
{
public partial interface IInPointAccess
{
/// <summary>
/// Creates queue entries in the provisioning table to request the mailbox synchronisation in inPoint.
/// Send the flattened (and scoped) ACL (Access Control List) of the mailbox to inPoint:
/// User SID - ALLOW/DENY; Inherited or not
/// Group SID - ALLOW/DENY; Inherited or not
///
/// Flattening of the group members is done on the inPoint side.
/// Transforming the SIDs to Users/Groups is done on the inPoint side.
///
/// IF THERE WAS NO CHANGE IN THE PERMISSIONS OF THE MAILBOX, DO NOT CALL THIS METHOD.
/// </summary>
/// <param name="mailboxGuid">Mailbox Guid which uniquely identifies the mailbox between the caller and inPoint server
/// (Both systems are using the same mailboxGuid).</param>
/// <param name="entries">Complete list of permission entries
(sorted by sequence) for the given mailbox</param>
[OperationContract]
void SetRights(string mailboxGuid, List<PermissionEntry> entries);
}
/// <summary>
/// Defines the permission entry for a given user or group on the mailbox
/// </summary>
[DataContract]
public class PermissionEntry
{
/// <summary>
/// Might contain the following values:
/// - "Default" - fix value. Default is what every domain user will have if they are not specified in the access list.
/// - "Anonymous" - fix value. Anonymous is a non-domain account.
/// - SID of the AD user or group
/// </summary>
[DataMember]
public string SID { get; set; }
/// <summary>
/// True if the PermissionEntry is for a group
/// </summary>
[DataMember]
public bool IsGroup { get; set; }
/// <summary>
/// True if permission is denied
/// </summary>
[DataMember]
public bool IsDeny { get; set; }
/// <summary>
/// Sequence number of the PermissionEntry in the Provisioning queue
/// </summary>
[DataMember]
public int Sequence { get; set; }
}
}
The inPoint Server is interpreting the permission entries the following way:
To find out whether the user X has access to a mailbox M, while X is member of G1, G2, Gn, the permission entries must be ordered by sequence number (DESC).
Find the SID of the involved groups G1, G2, ... Gn.
Start from the highest sequence number and evaluate:
- Allow = false
- If the SID == X.SID => allow = !IsDeny
- If the SID == G.SID => allow = !IsDeny
- Repeat for each entry in the list
- The last value of allow is the result.
Synchronizing the "Public folder" permissions
The interface method was defined as:
namespace InPointAccess
{
public partial interface IInPointAccess
{
/// <summary>
/// Sets the rights on a folder.
/// </summary>
/// <param name="mailboxGuid">Mailbox Guid which uniquely identifies the mailbox between the caller and inPoint server
/// (Both systems are using the same mailboxGuid).</param>
/// <param name="folderPath">Path of the folder (has the same format like it is in the archiving).</param>
/// <param name="entries">Access list of the folder</param>
[OperationContract]
void SetFolderRights(string mailboxGuid, string folderPath, List<FolderPermissionEntry> entries);
}
/// <summary>
/// Defines the permissions on a folder
/// </summary>
[DataContract]
public class FolderPermissionEntry
{
/// <summary>
/// Might contain the following values:
/// - "Default" - fix value. Default is what every domain user will have if they are not specified in the access list.
/// - "Anonymous" - fix value. Anonymous is a non-domain account.
/// - SID of the AD user or group
/// </summary>
[DataMember]
public string SID { get; set; }
/// <summary>
/// AccessRights for the SID. Possible values: 0 or 1.
/// </summary>
[DataMember]
public int AccessRights { get; set; }
/// <summary>
/// Will be used for explicit right. Default value is True.
/// </summary>
[DataMember]
public bool Automatic { get; set; }
}
}