// This function updates a folder tree based on the
        // changes received from the server in the response.
        public void UpdateFolderTree(Folder rootFolder)
        {
            rootFolder.LastSyncTime = DateTime.Now.ToUniversalTime();

            try
            {
                // Get sync key
                XmlNode syncKeyNode = responseXml.SelectSingleNode(".//folderhierarchy:SyncKey", xmlNsMgr);
                rootFolder.SyncKey = syncKeyNode.InnerText;

                // Process adds (new folders) first
                XmlNodeList addNodes = responseXml.SelectNodes(".//folderhierarchy:Add", xmlNsMgr);
                foreach (XmlNode addNode in addNodes)
                {
                    XmlNode nameNode = addNode.SelectSingleNode(".//folderhierarchy:DisplayName", xmlNsMgr);
                    XmlNode serverIdNode = addNode.SelectSingleNode(".//folderhierarchy:ServerId", xmlNsMgr);
                    XmlNode parentIdNode = addNode.SelectSingleNode(".//folderhierarchy:ParentId", xmlNsMgr);
                    XmlNode typeNode = addNode.SelectSingleNode(".//folderhierarchy:Type", xmlNsMgr);

                    rootFolder.AddFolder(nameNode.InnerText, serverIdNode.InnerText, parentIdNode.InnerText,
                        (Folder.FolderType)XmlConvert.ToInt32(typeNode.InnerText));
                }

                // Then process deletes
                XmlNodeList deleteNodes = responseXml.SelectNodes(".//folderhierarchy:Delete", xmlNsMgr);
                foreach (XmlNode deleteNode in deleteNodes)
                {
                    XmlNode serverIdNode = deleteNode.SelectSingleNode(".//folderhierarchy:ServerId", xmlNsMgr);

                    Folder removeFolder = rootFolder.FindFolderById(serverIdNode.InnerText);
                    removeFolder.Remove();
                }

                // Finally process any updates to existing folders
                XmlNodeList updateNodes = responseXml.SelectNodes(".//folderhierarchy:Update", xmlNsMgr);
                foreach (XmlNode updateNode in updateNodes)
                {
                    XmlNode nameNode = updateNode.SelectSingleNode(".//folderhierarchy:DisplayName", xmlNsMgr);
                    XmlNode serverIdNode = updateNode.SelectSingleNode(".//folderhierarchy:ServerId", xmlNsMgr);
                    XmlNode parentIdNode = updateNode.SelectSingleNode(".//folderhierarchy:ParentId", xmlNsMgr);
                    XmlNode typeNode = updateNode.SelectSingleNode(".//folderhierarchy:Type", xmlNsMgr);

                    Folder updateFolder = rootFolder.FindFolderById(serverIdNode.InnerText);
                    Folder updateParent = rootFolder.FindFolderById(parentIdNode.InnerText);

                    updateFolder.Update(nameNode.InnerText, updateParent,
                        (Folder.FolderType)XmlConvert.ToInt32(typeNode.InnerText));
                }
            }
            catch (Exception e)
            {
                // Rather than attempting to recover, reset sync key
                // and empty folders. The next FolderSync should
                // re-sync folders.
                rootFolder.SyncKey = "0";
                rootFolder.RemoveAllSubFolders();
            }

            rootFolder.SaveFolderInfo();
        }
예제 #2
0
        static void Main(string[] args)
        {
            NetworkCredential userCredentials = new NetworkCredential(
                string.Format("{0}\\{1}", domainName, userName), password);

            #region OPTIONS Request
            Console.WriteLine("Sending OPTIONS request to server...");

            ASOptionsRequest optionsRequest = new ASOptionsRequest();
            optionsRequest.Server      = activeSyncServer;
            optionsRequest.UseSSL      = useSSL;
            optionsRequest.Credentials = userCredentials;

            // Send the OPTIONS request
            ASOptionsResponse optionsResponse = optionsRequest.GetOptions();
            if (optionsResponse == null)
            {
                ReportError("Unable to connect to server.");
                return;
            }

            Console.WriteLine("Supported ActiveSync versions: {0}", optionsResponse.SupportedVersions);
            Console.WriteLine("Supported ActiveSync commands: {0}\n", optionsResponse.SupportedCommands);

            // Make sure version 14.1 is supported
            if (optionsResponse.HighestSupportedVersion != "14.1")
            {
                ReportError("+++ The server does not support ActiveSync version 14.1. +++");
                return;
            }
            #endregion

            #region Provisioning
            // Initialize the policy key
            uint policyKey = 0;

            // Provide details about the device
            Device deviceToProvision = new Device();
            deviceToProvision.DeviceID                = "EX2010activesyncfoldercs";
            deviceToProvision.DeviceType              = "Sample Application";
            deviceToProvision.Model                   = "Sample Model";
            deviceToProvision.FriendlyName            = "FolderSync/Sync Example";
            deviceToProvision.OperatingSystem         = "Sample OS 1.0";
            deviceToProvision.OperatingSystemLanguage = "English";
            deviceToProvision.MobileOperator          = "Phone Company";
            deviceToProvision.UserAgent               = "EX2010_activesyncfolder_cs_1.0";
            deviceToProvision.PhoneNumber             = "425-555-1000";

            // Phase 1: Initial provision request
            // During this phase, the client requests the policy
            // and the server sends the policy details, along with a temporary
            // policy key.
            ASProvisionRequest initialProvisionRequest = new ASProvisionRequest();

            // Initialize the request with information
            // that applies to all requests.
            initialProvisionRequest.Credentials           = userCredentials;
            initialProvisionRequest.Server                = activeSyncServer;
            initialProvisionRequest.User                  = userName;
            initialProvisionRequest.DeviceID              = deviceToProvision.DeviceID;
            initialProvisionRequest.DeviceType            = deviceToProvision.DeviceType;
            initialProvisionRequest.ProtocolVersion       = "14.1";
            initialProvisionRequest.PolicyKey             = policyKey;
            initialProvisionRequest.UseEncodedRequestLine = useBase64RequestLine;

            // Initialize the Provision command-specific
            // information.
            initialProvisionRequest.ProvisionDevice = deviceToProvision;

            Console.WriteLine("Sending initial provision request...");
            // Send the request
            ASProvisionResponse initialProvisionResponse =
                (ASProvisionResponse)initialProvisionRequest.GetResponse();

            Console.WriteLine("Initial Provision Request:");
            Console.WriteLine(initialProvisionRequest.XmlString);
            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
            Console.ReadLine();

            Console.WriteLine("Initial Provision Response:");
            Console.WriteLine(initialProvisionResponse.XmlString);
            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
            Console.ReadLine();

            // Check the result of the initial request.
            // The server may have requested a remote wipe, or
            // may have returned an error.
            Console.WriteLine("Response Status: {0}", initialProvisionResponse.Status);

            if (initialProvisionResponse.Status == (Int32)ASProvisionResponse.ProvisionStatus.Success)
            {
                if (initialProvisionResponse.IsPolicyLoaded)
                {
                    if (initialProvisionResponse.Policy.Status ==
                        (Int32)ASProvisionResponse.ProvisionStatus.Success)
                    {
                        if (initialProvisionResponse.Policy.RemoteWipeRequested)
                        {
                            // The server requested a remote wipe.
                            // The client must acknowledge it.
                            Console.WriteLine("+++ The server has requested a remote wipe. +++\n");

                            ASProvisionRequest remoteWipeAcknowledgment =
                                new ASProvisionRequest();

                            // Initialize the request with information
                            // that applies to all requests.
                            remoteWipeAcknowledgment.Credentials           = userCredentials;
                            remoteWipeAcknowledgment.Server                = activeSyncServer;
                            remoteWipeAcknowledgment.User                  = userName;
                            remoteWipeAcknowledgment.DeviceID              = deviceToProvision.DeviceID;
                            remoteWipeAcknowledgment.DeviceType            = deviceToProvision.DeviceType;
                            remoteWipeAcknowledgment.ProtocolVersion       = "14.1";
                            remoteWipeAcknowledgment.PolicyKey             = policyKey;
                            remoteWipeAcknowledgment.UseEncodedRequestLine = useBase64RequestLine;

                            // Initialize the Provision command-specific
                            // information.
                            remoteWipeAcknowledgment.IsRemoteWipe = true;
                            // Indicate successful wipe
                            remoteWipeAcknowledgment.Status =
                                (int)ASProvisionResponse.ProvisionStatus.Success;

                            Console.WriteLine("Sending remote wipe acknowledgment...");
                            // Send the acknowledgment
                            ASProvisionResponse remoteWipeAckResponse =
                                (ASProvisionResponse)remoteWipeAcknowledgment.GetResponse();

                            Console.WriteLine("Remote Wipe Acknowledgment Request:");
                            Console.WriteLine(remoteWipeAcknowledgment.XmlString);
                            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
                            Console.ReadLine();

                            Console.WriteLine("Remote Wipe Acknowledgment Response:");
                            Console.WriteLine(remoteWipeAckResponse.XmlString);
                            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
                            Console.ReadLine();

                            Console.WriteLine("Remote wipe acknowledgment response status: {0}",
                                              remoteWipeAckResponse.Status);
                        }
                        else
                        {
                            // The server has provided a policy
                            // and a temporary policy key.
                            // The client must acknowledge this policy
                            // in order to get a permanent policy
                            // key.
                            Console.WriteLine("Policy retrieved from the server.");
                            Console.WriteLine("Temporary policy key: {0}\n",
                                              initialProvisionResponse.Policy.PolicyKey);

                            ASProvisionRequest policyAcknowledgment =
                                new ASProvisionRequest();

                            // Initialize the request with information
                            // that applies to all requests.
                            policyAcknowledgment.Credentials     = userCredentials;
                            policyAcknowledgment.Server          = activeSyncServer;
                            policyAcknowledgment.User            = userName;
                            policyAcknowledgment.DeviceID        = deviceToProvision.DeviceID;
                            policyAcknowledgment.DeviceType      = deviceToProvision.DeviceType;
                            policyAcknowledgment.ProtocolVersion = "14.1";
                            // Set the policy key to the temporary policy key from
                            // the previous response.
                            policyAcknowledgment.PolicyKey             = initialProvisionResponse.Policy.PolicyKey;
                            policyAcknowledgment.UseEncodedRequestLine = useBase64RequestLine;

                            // Initialize the Provision command-specific
                            // information.
                            policyAcknowledgment.IsAcknowledgement = true;
                            // Indicate successful application of the policy.
                            policyAcknowledgment.Status =
                                (int)ASProvisionRequest.PolicyAcknowledgement.Success;

                            Console.WriteLine("Sending policy acknowledgment...");
                            // Send the request
                            ASProvisionResponse policyAckResponse =
                                (ASProvisionResponse)policyAcknowledgment.GetResponse();

                            Console.WriteLine("Policy Acknowledgment Request:");
                            Console.WriteLine(policyAcknowledgment.XmlString);
                            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
                            Console.ReadLine();

                            Console.WriteLine("Policy Acknowledgment Response:");
                            Console.WriteLine(policyAckResponse.XmlString);
                            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
                            Console.ReadLine();

                            Console.WriteLine("Response status: {0}", policyAckResponse.Status);

                            if (policyAckResponse.Status == (int)ASProvisionResponse.ProvisionStatus.Success &&
                                policyAckResponse.IsPolicyLoaded)
                            {
                                Console.WriteLine("Policy acknowledgment successful.");
                                Console.WriteLine("Permanent Policy Key: {0}", policyAckResponse.Policy.PolicyKey);

                                // Save the permanent policy key for use
                                // in subsequent command requests.
                                policyKey = policyAckResponse.Policy.PolicyKey;
                            }
                            else
                            {
                                Console.WriteLine("Error returned from policy acknowledgment request: {0}",
                                                  policyAckResponse.Status);
                            }
                        }
                    }
                    else
                    {
                        Console.WriteLine("Policy Error returned from initial provision request: {0}",
                                          initialProvisionResponse.Policy.Status);
                    }
                }
            }
            else
            {
                Console.WriteLine("Error returned from initial provision request: {0}",
                                  initialProvisionResponse.Status);
            }

            // If we did not end up with a permanent policy
            // key, then exit.
            if (policyKey == 0)
            {
                Console.WriteLine("Provisioning failed, cannot continue.");
                Console.WriteLine("+++ HIT ENTER TO EXIT +++");
                Console.ReadLine();
                return;
            }
            #endregion

            #region Sync Folder Hierarchy
            // Initialize local storage of mailbox
            Folder rootFolder = new Folder(mailboxCacheLocation);

            ASFolderSyncRequest folderSyncRequest = new ASFolderSyncRequest();

            // Initialize the request with information
            // that applies to all requests.
            folderSyncRequest.Credentials           = userCredentials;
            folderSyncRequest.Server                = activeSyncServer;
            folderSyncRequest.User                  = userName;
            folderSyncRequest.DeviceID              = deviceToProvision.DeviceID;
            folderSyncRequest.DeviceType            = deviceToProvision.DeviceType;
            folderSyncRequest.ProtocolVersion       = "14.1";
            folderSyncRequest.PolicyKey             = policyKey;
            folderSyncRequest.UseEncodedRequestLine = useBase64RequestLine;

            // Initialize the FolderSync command-specific
            // information.
            folderSyncRequest.SyncKey = rootFolder.SyncKey;

            // Send the request
            Console.WriteLine("Sending FolderSync request...");

            ASFolderSyncResponse folderSyncResponse = (ASFolderSyncResponse)folderSyncRequest.GetResponse();

            if (folderSyncResponse == null)
            {
                ReportError("Unable to connect to server.");
                return;
            }

            Console.WriteLine("FolderSync Request:");
            Console.WriteLine(folderSyncRequest.XmlString);
            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
            Console.ReadLine();

            Console.WriteLine("FolderSync Response:");
            Console.WriteLine(folderSyncResponse.XmlString);
            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
            Console.ReadLine();

            Console.WriteLine("Response Status: {0}", folderSyncResponse.Status);

            if (folderSyncResponse.Status ==
                (int)ASFolderSyncResponse.FolderSyncStatus.Success)
            {
                // Populate the folder hierarchy from the
                // response
                folderSyncResponse.UpdateFolderTree(rootFolder);
            }
            else
            {
                Console.WriteLine("Error returned from FolderSync request: {0}", folderSyncResponse.Status);
            }

            // Check that we have subfolders and
            // that "Inbox" is one of them.
            Folder inboxFolder = null;

            foreach (Folder subFolder in rootFolder.SubFolders)
            {
                if (subFolder.Name == "Inbox")
                {
                    inboxFolder = subFolder;
                    break;
                }
            }

            if (inboxFolder == null)
            {
                // Folders didn't sync or somehow
                // Inbox wasn't one of them, exit.
                ReportError("+++ Inbox not found in hierarchy. +++");
                return;
            }

            Console.WriteLine("Inbox found, Id: {0}, Sync Key: {1}, Last sync: {2}\n",
                              inboxFolder.Id, inboxFolder.SyncKey, inboxFolder.LastSyncTime);
            #endregion

            #region Sync Inbox Contents
            // If this is the first time syncing Inbox
            // (Sync Key = 0), then you must
            // send an initial sync request to "prime"
            // the sync state.
            if (inboxFolder.SyncKey == "0")
            {
                ASSyncRequest initialSyncRequest = new ASSyncRequest();

                // Initialize the request with information
                // that applies to all requests.
                initialSyncRequest.Credentials           = userCredentials;
                initialSyncRequest.Server                = activeSyncServer;
                initialSyncRequest.User                  = userName;
                initialSyncRequest.DeviceID              = deviceToProvision.DeviceID;
                initialSyncRequest.DeviceType            = deviceToProvision.DeviceType;
                initialSyncRequest.ProtocolVersion       = "14.1";
                initialSyncRequest.PolicyKey             = policyKey;
                initialSyncRequest.UseEncodedRequestLine = useBase64RequestLine;

                // Initialize the Sync command-specific
                // information.
                // Add the Inbox to the folders to be synced
                initialSyncRequest.Folders.Add(inboxFolder);

                Console.WriteLine("Sending initial Sync request to prime the sync state for Inbox...");

                // Send the request
                ASSyncResponse initialSyncResponse = (ASSyncResponse)initialSyncRequest.GetResponse();
                if (initialSyncResponse == null)
                {
                    ReportError("Unable to connect to server.");
                    return;
                }

                Console.WriteLine("Response status: {0}", initialSyncResponse.Status);

                Console.WriteLine("Initial Sync Request:");
                Console.WriteLine(initialSyncRequest.XmlString);
                Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
                Console.ReadLine();

                Console.WriteLine("Initial Sync Response:");
                Console.WriteLine(initialSyncResponse.XmlString);
                Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
                Console.ReadLine();

                if (initialSyncResponse.Status ==
                    (int)ASSyncResponse.SyncStatus.Success)
                {
                    inboxFolder.SyncKey = initialSyncResponse.GetSyncKeyForFolder(inboxFolder.Id);
                }
                else
                {
                    string errorMessage = string.Format("Error returned from empty sync reqeust: {0}",
                                                        initialSyncResponse.Status);
                    ReportError(errorMessage);
                    return;
                }
            }

            ASSyncRequest inboxSyncRequest = new ASSyncRequest();

            // Initialize the request with information
            // that applies to all requests.
            inboxSyncRequest.Credentials           = userCredentials;
            inboxSyncRequest.Server                = activeSyncServer;
            inboxSyncRequest.User                  = userName;
            inboxSyncRequest.DeviceID              = deviceToProvision.DeviceID;
            inboxSyncRequest.DeviceType            = deviceToProvision.DeviceType;
            inboxSyncRequest.ProtocolVersion       = "14.1";
            inboxSyncRequest.PolicyKey             = policyKey;
            inboxSyncRequest.UseEncodedRequestLine = useBase64RequestLine;

            // Initialize the Sync command-specific
            // information.
            // Add the Inbox to the folders to be synced
            inboxSyncRequest.Folders.Add(inboxFolder);

            // You can specify a Wait or HeartBeatInterval
            // to direct the server to delay a response
            // until something changes.
            // NOTE: Per MS-ASCMD, don't include both
            // a Wait and a HeartBeatInterval.

            // The value of HeartBeatInterval is in seconds
            inboxSyncRequest.HeartBeatInterval = 60;

            // The value of Wait is in minutes
            //inboxSyncRequest.Wait = 5;

            // You can specify a maximum number of changes
            // that the server should send in the response.
            // Uncomment the line below to specify a maximum.
            //inboxSyncRequest.WindowSize = 50;

            // You can also specify sync options on a specific
            // folder. This is useful if you are syncing
            // multiple folders in a single Sync command request
            // and need to specify different options for each.
            inboxFolder.UseConversationMode = true;
            inboxFolder.AreDeletesPermanent = false;

            // Further options are available in the <Options>
            // element as a child of the <Colletion> element.
            // (See MS-ASCMD section 2.2.3.115.5)
            inboxFolder.Options = new FolderSyncOptions();
            inboxFolder.Options.BodyPreference    = new BodyPreferences[1];
            inboxFolder.Options.BodyPreference[0] = new BodyPreferences();

            inboxFolder.Options.BodyPreference[0].Type           = BodyType.HTML;
            inboxFolder.Options.BodyPreference[0].TruncationSize = 500;
            inboxFolder.Options.BodyPreference[0].AllOrNone      = false;
            inboxFolder.Options.BodyPreference[0].Preview        = 100;

            Console.WriteLine("Sending Inbox Sync request...");

            // Send the request
            ASSyncResponse inboxSyncResponse =
                (ASSyncResponse)inboxSyncRequest.GetResponse();
            if (inboxSyncResponse == null)
            {
                ReportError("Unable to connect to server.");
                return;
            }

            Console.WriteLine("Response status: {0}", inboxSyncResponse.Status);

            Console.WriteLine("Inbox Sync Request:");
            Console.WriteLine(inboxSyncRequest.XmlString);
            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
            Console.ReadLine();

            Console.WriteLine("Inbox Sync Response:");
            Console.WriteLine(inboxSyncResponse.XmlString);
            Console.WriteLine("+++ HIT ENTER TO CONTINUE +++");
            Console.ReadLine();

            if (inboxSyncResponse.Status ==
                (int)ASSyncResponse.SyncStatus.Success)
            {
                List <ServerSyncCommand> addCommands =
                    inboxSyncResponse.GetServerAddsForFolder(inboxFolder.Id);

                if (addCommands != null)
                {
                    Console.WriteLine("Adding {0} items...", addCommands.Count);

                    SaveItemsInLocalFolder(inboxFolder, addCommands);
                }

                inboxFolder.SyncKey      = inboxSyncResponse.GetSyncKeyForFolder(inboxFolder.Id);
                inboxFolder.LastSyncTime = DateTime.Now;

                // Call SaveFolderInfo to update the last sync time
                // and sync key of the inbox.
                rootFolder.SaveFolderInfo();
            }
            else if (inboxSyncResponse.HttpStatus == HttpStatusCode.OK)
            {
                // The server had no changes
                // to send. At this point you could
                // repeat the last sync request by sending
                // an empty sync request (MS-ASCMD section 2.2.2.19.1.1)
                // This sample does not implement repeating the request,
                // so just notify the user.
                Console.WriteLine("No changes available on server.");
                inboxFolder.LastSyncTime = DateTime.Now;

                // Call SaveFolderInfo to update the last sync time
                rootFolder.SaveFolderInfo();
            }
            else
            {
                Console.WriteLine("Error returned from Inbox sync request: {0}",
                                  inboxSyncResponse.Status);
            }
            #endregion

            Console.WriteLine("+++ HIT ENTER TO EXIT +++");
            Console.ReadLine();
        }
예제 #3
0
        // This function updates an existing folder by either
        // renaming it or moving it.
        public void Update(string folderName, Folder newParent, Folder.FolderType folderType)
        {
            // Set the new name
            name = folderName;

            // Check to see if we are moving the folder.
            if (newParent != parentFolder)
            {
                // Remove this folder from the current parent's
                // subfolders
                parentFolder.RemoveSubFolder(this);

                parentFolder = newParent;

                // Add this folder to the new parent's subfolders
                newParent.AddSubFolder(this);
            }

            // Call MoveLocalFolder to move the local data to a new
            // directory.
            MoveLocalFolder(newParent.SaveLocation + "\\" + name);
        }
예제 #4
0
 // This function removes a folder from the list of
 // subfolders.
 public bool RemoveSubFolder(Folder removeFolder)
 {
     return subFolders.Remove(removeFolder);
 }
예제 #5
0
 // This function adds a Folder object to the list of subfolders.
 public void AddSubFolder(Folder newFolder)
 {
     subFolders.Add(newFolder);
 }
예제 #6
0
 // This function creates a new Folder object and adds it to the list of subfolders.
 public Folder AddSubFolder(string folderName, string folderId, FolderType folderType)
 {
     Folder newFolder = new Folder(folderName, folderId, folderType, this);
     subFolders.Add(newFolder);
     return newFolder;
 }
예제 #7
0
        // Constructor that creates a Folder object based on the basic
        // properties of the folder. This form is used when building
        // the folder hierarchy under the root.
        public Folder(string folderName, string folderId, FolderType folderType, Folder parent)
        {
            name = folderName;
            id = folderId;
            parentFolder = parent;
            type = folderType;

            saveLocation = parent.SaveLocation + "\\" + folderName;
            Directory.CreateDirectory(saveLocation);

            subFolders = new List<Folder>();
        }