/// <summary>
        /// Load free busy information from the public folder
        /// </summary>
        /// <param name="exchangeServerUrl">The exchange server to use</param>
        /// <param name="users">The set of users to get free busy info for</param>
        /// <param name="window">The DateTime range to get free busy info for</param>
        /// <returns>A set of FreeBusy information for each user</returns>
        public Dictionary <ExchangeUser, FreeBusy> LoadFreeBusy(
            string exchangeServerUrl,
            ExchangeUserDict users,
            DateTimeRange window)
        {
            DateTimeRange roundedWindow = DateUtil.RoundRangeToInterval(window, kFreeBusyInterval);

            string url = FreeBusyUrl.GenerateFreeBusyLookupUrl(exchangeServerUrl,
                                                               users,
                                                               roundedWindow,
                                                               kFreeBusyInterval);
            Stream response = IssueRequest(url, Method.GET, string.Empty);
            Dictionary <ExchangeUser, FreeBusy> result = null;

            try
            {
                result = ParseRasterFreeBusyResponse(users,
                                                     roundedWindow.Start,
                                                     response);
            }
            finally
            {
                response.Close();
            }

            return(result);
        }
        /// <summary>
        /// Returns the free busy times for the specified exchange users
        /// </summary>
        /// <param name="users">The user which free/busy blocks will be looked up for</param>
        /// <param name="window">The time period to look up FB info for</param>
        /// <returns></returns>
        public Dictionary<ExchangeUser, FreeBusy> LookupFreeBusyTimes(
            ExchangeUserDict users,
            DateTimeRange window )
        {
            /* Create an array of mailboxes to retrieve from exchange */
            Dictionary<ExchangeUser, FreeBusy> result = new Dictionary<ExchangeUser, FreeBusy>();

            try
            {
                using (BlockTimer bt = new BlockTimer("LookupFreeBusyTimes"))
                {
                    /* Perform the retrieval of free busy times through WebDav */
                    result = webDavQuery.LoadFreeBusy(exchangeServerUrl, users, window);
                }
            }
            catch (Exception ex)
            {
                throw new GCalExchangeException(
                    GCalExchangeErrorCode.ExchangeUnreachable,
                   "Error occured while retrieving free busy ranges",
                   ex);
            }

            return result;
        }
        private static void ParseFreeBusyRaster(
            ExchangeUserDict users,
            DateTime baseTime,
            string emailAddress,
            string freeBusyRaster,
            Dictionary <ExchangeUser, FreeBusy> result)
        {
            ExchangeUser user = null;

            if (emailAddress == null || !users.TryGetValue(emailAddress, out user))
            {
                return;
            }

            FreeBusy freeBusy = new FreeBusy();

            freeBusy.User = user;

            FreeBusyConverter.ParseRasterFreeBusy(baseTime,
                                                  kFreeBusyInterval,
                                                  freeBusyRaster,
                                                  freeBusy);

            FreeBusyConverter.CondenseFreeBusyTimes(freeBusy.All);

            result[user] = freeBusy;
        }
Beispiel #4
0
        protected void ButtonQueryExchFB_Click(object sender, EventArgs e)
        {
            verifyAllowed();

            try
            {
                ExchangeUserDict users =
                    ExchangeTester.QueryFreeBusy(TextBoxQueryExchEmail.Text);

                if (users.Count > 0)
                {
                    LabelExchFBSummary.Text     = "Verified";
                    WebServiceFreeBusy.CssClass = "verified";
                    StringBuilder sb = new StringBuilder();

                    foreach (ExchangeUser user in users.Values)
                    {
                        sb.AppendFormat("<ul>");
                        sb.AppendFormat("<li>Common Name: {0}</li>", user.CommonName);
                        sb.AppendFormat("<li>Email: {0}</li>", user.Email);
                        sb.AppendFormat("<li>Account Name: {0}</li>", user.AccountName);
                        sb.AppendFormat("<li>Mail Nickname: {0}</li>", user.MailNickname);

                        sb.AppendFormat("<li>Busy Times:");
                        sb.AppendFormat("<ul>");

                        foreach (FreeBusyTimeBlock tb in user.BusyTimes.Values)
                        {
                            sb.AppendFormat("<li>{0} to {1}</li>", tb.StartDate.ToLocalTime(), tb.EndDate.ToLocalTime());
                        }
                        sb.AppendFormat("</ul></li></ul>");
                    }

                    LabelExchFBDetail.Text = sb.ToString();
                }
                else
                {
                    LabelExchFBSummary.Text =
                        string.Format("User not found - {0}", TextBoxQueryExchEmail.Text);
                    LabelExchFBDetail.Text      = "";
                    WebServiceFreeBusy.CssClass = "failed";
                }
            }
            catch (Exception ex)
            {
                LabelExchFBSummary.Text     = ex.Message;
                WebServiceFreeBusy.CssClass = "failed";
                LabelExchFBDetail.Text      = string.Format("<blockquote>{0}</blockquote>", ex.ToString());
            }
        }
        public void FreeBusyUrls()
        {
            Assert.AreEqual(FreeBusyTestUrl, FreeBusyUrl.GenerateUrl(ExchangeServer, Organization, OrgUnit));
            Assert.AreEqual(FreeBusyFromDNUrl, FreeBusyUrl.GenerateUrlFromDN(ExchangeServer, LegacyDN));
            Assert.AreEqual(AdminGroupUrl, FreeBusyUrl.GenerateAdminGroupUrl(ExchangeServer, AdminGroup));

            ExchangeUserDict users = new ExchangeUserDict();
            users.Add(User1Email, createFauxUser("User1", User1Email));

            DateTimeRange range = new DateTimeRange(start, end);
            Assert.AreEqual(SingleUserFreeBusyUrl, FreeBusyUrl.GenerateFreeBusyLookupUrl(ExchangeServer, users, range, 15));

            users.Add(User2Email, createFauxUser("User2", User2Email));
            Assert.AreEqual(MultiUserFreeBusyUrl, FreeBusyUrl.GenerateFreeBusyLookupUrl(ExchangeServer, users, range, 15));
        }
Beispiel #6
0
        protected void ButtonLdapQuery_Click(object sender, EventArgs e)
        {
            verifyAllowed();

            try
            {
                ExchangeUserDict users =
                    ExchangeTester.QueryActiveDirectory(TextBoxLdapQuery.Text);

                if (users.Count > 0)
                {
                    WebServiceLdap.CssClass = "verified";
                    LabelLdapSummary.Text   = string.Format("Verified - Located {0} users", users.Count);
                    StringBuilder sb    = new StringBuilder();
                    int           count = 0;

                    sb.Append("<ul>");

                    foreach (string userKey in users.Keys)
                    {
                        sb.AppendFormat("<li>User: {0}</li>", userKey);
                        count++;

                        if (count > 20)
                        {
                            sb.AppendFormat("<li>&lt;Truncated&gt;</li>");
                            break;
                        }
                    }

                    sb.Append("</ul>");

                    LabelLdapDetail.Text = sb.ToString();
                }
                else
                {
                    LabelLdapSummary.Text   = "No users returned";
                    WebServiceLdap.CssClass = "failed";
                    LabelLdapDetail.Text    = "";
                }
            }
            catch (Exception ex)
            {
                LabelLdapSummary.Text   = ex.Message;
                WebServiceLdap.CssClass = "failed";
                LabelLdapDetail.Text    = string.Format("<blockquote>{0}</blockquote>", ex.ToString());
            }
        }
        public AppointmentLookupFuture(
            ExchangeService exchange,
            ExchangeUserDict users,
            DateTimeRange window)
        {
            this.exchange = exchange;
            this.users = users;
            this.syncWindow = window;

            // Only do this if appointment
            // lookup is enabled
            if (ConfigCache.EnableAppointmentLookup)
            {
                this.start();
            }
        }
Beispiel #8
0
        public void TestFastFreeBusyLookup()
        {
            _requestor.ValidMethod  = Method.GET;
            _requestor.ResponseBody = getResponseXML("FreeBusyResponse.xml");

            // These dates correspond to when the response XML was captured
            DateTime      start = DateUtil.ParseDateToUtc("2007-12-25T01:46:50Z");
            DateTime      end   = DateUtil.ParseDateToUtc("2008-01-08T01:42:50Z");
            DateTimeRange range = new DateTimeRange(start, end);

            ExchangeUserDict users = new ExchangeUserDict();

            users.Add(_user.Email, _user);

            Dictionary <ExchangeUser, FreeBusy> result = _webdav.LoadFreeBusy(exchangeServer,
                                                                              users,
                                                                              range);

            Assert.AreEqual(1, result.Count);

            FreeBusy fb = result[_user];

            Assert.AreEqual(6, fb.All.Count);
            Assert.AreEqual(6, fb.Busy.Count);
            Assert.AreEqual(0, fb.OutOfOffice.Count);
            Assert.AreEqual(0, fb.Tentative.Count);

            //dumpFreeBusy(fb.Busy);

            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:00:00Z"), fb.Busy[0].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:30:00Z"), fb.Busy[0].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T20:30:00Z"), fb.Busy[1].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T21:00:00Z"), fb.Busy[1].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T17:30:00Z"), fb.Busy[2].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T18:00:00Z"), fb.Busy[2].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:00:00Z"), fb.Busy[3].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:30:00Z"), fb.Busy[3].End);

            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:00:00Z"), fb.All[0].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:30:00Z"), fb.All[0].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T20:30:00Z"), fb.All[1].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T21:00:00Z"), fb.All[1].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T17:30:00Z"), fb.All[2].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T18:00:00Z"), fb.All[2].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:00:00Z"), fb.All[3].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:30:00Z"), fb.All[3].End);
        }
        public void FreeBusyUrls()
        {
            Assert.AreEqual(FreeBusyTestUrl, FreeBusyUrl.GenerateUrl(ExchangeServer, Organization, OrgUnit));
            Assert.AreEqual(FreeBusyFromDNUrl, FreeBusyUrl.GenerateUrlFromDN(ExchangeServer, LegacyDN));
            Assert.AreEqual(AdminGroupUrl, FreeBusyUrl.GenerateAdminGroupUrl(ExchangeServer, AdminGroup));

            ExchangeUserDict users = new ExchangeUserDict();

            users.Add(User1Email, createFauxUser("User1", User1Email));

            DateTimeRange range = new DateTimeRange(start, end);

            Assert.AreEqual(SingleUserFreeBusyUrl, FreeBusyUrl.GenerateFreeBusyLookupUrl(ExchangeServer, users, range, 15));

            users.Add(User2Email, createFauxUser("User2", User2Email));
            Assert.AreEqual(MultiUserFreeBusyUrl, FreeBusyUrl.GenerateFreeBusyLookupUrl(ExchangeServer, users, range, 15));
        }
        public static void WriteFreeBusyMessage(string commonName)
        {
            ExchangeService gw = new ExchangeService(
                ConfigCache.ExchangeFreeBusyServerUrl,
                ConfigCache.ExchangeUserLogin,
                ConfigCache.ExchangeUserPassword);

            SchedulePlusFreeBusyWriter writer =
                new SchedulePlusFreeBusyWriter();

            ExchangeUserDict users = QueryFreeBusy(commonName);

            if (users.Count < 1)
            {
                string msg = string.Format("User {0} not found", commonName);
                throw new Exception(msg);
            }

            if (users.Count > 1)
            {
                string msg = string.Format("More than one user matches {0}", commonName);
                throw new Exception(msg);
            }

            string userFreeBusyUrl = FreeBusyUrl.GenerateUrlFromDN(
                ConfigCache.ExchangeFreeBusyServerUrl,
                users[commonName].LegacyExchangeDN);

            List <string> emtpyList      = new List <string>();
            string        nowMinus30Days =
                FreeBusyConverter.ConvertToSysTime(DateUtil.NowUtc.AddDays(-30)).ToString();
            string nowPlus60Days =
                FreeBusyConverter.ConvertToSysTime(DateUtil.NowUtc.AddDays(60)).ToString();

            gw.FreeBusy.CreateFreeBusyMessage(userFreeBusyUrl,
                                              commonName,
                                              emtpyList,
                                              emtpyList,
                                              emtpyList,
                                              emtpyList,
                                              nowMinus30Days,
                                              nowPlus60Days);
        }
Beispiel #11
0
        /// <summary>
        /// Generate a URL for the new Free Busy Lookup format which is a replacement
        /// for public folders - documented here: http://support.microsoft.com/kb/813268
        /// </summary>
        /// <param name="exchangeServer">The exchange server to use</param>
        /// <param name="users">The set of users to lookup</param>
        /// <param name="range">The datetime range to lookup for</param>
        /// <param name="interval">The time interval to use</param>
        /// <returns>The URL to obtain FB info for the set of users</returns>
        public static string GenerateFreeBusyLookupUrl(
            string exchangeServer,
            ExchangeUserDict users,
            DateTimeRange range,
            int interval)
        {
            StringBuilder result = new StringBuilder(256);

            result.AppendFormat("{0}/public/?cmd=freebusy&start={1}&end={2}&interval={3}",
                                exchangeServer,
                                DateUtil.FormatDateForISO8601(range.Start),
                                DateUtil.FormatDateForISO8601(range.End),
                                interval);
            foreach (ExchangeUser user in users.Values)
            {
                result.AppendFormat("&u={0}", user.Email);
            }

            return(result.ToString());
        }
        public static void WriteAppointment(
            string email, DateTime appointmentStart)
        {
            DateTime appointmentEnd = appointmentStart.AddHours(1);

            ExchangeService gw = new ExchangeService(
                ConfigCache.ExchangeServerUrl,
                ConfigCache.ExchangeAdminLogin,
                ConfigCache.ExchangeAdminPassword);

            ExchangeUserDict users =
                gw.QueryActiveDirectory(string.Format("mail={0}", email));

            if (users.Count != 0)
            {
                foreach (ExchangeUser user in users.Values)
                {
                    Appointment appt = new Appointment();

                    appt.Subject       = "GCalExchangeSync test appt";
                    appt.Location      = "test";
                    appt.StartDate     = appointmentStart;
                    appt.EndDate       = appointmentEnd;
                    appt.MeetingStatus = MeetingStatus.Confirmed;
                    appt.Created       = DateUtil.NowUtc;
                    appt.InstanceType  = InstanceType.Single;

                    List <Appointment> list = new List <Appointment>();
                    list.Add(appt);

                    gw.Appointments.WriteAppointments(user, list);
                }
            }
            else
            {
                string msg = string.Format("User {0} not found", email);
                throw new Exception(msg);
            }
        }
        private ExchangeUserDict CreateExchangeUserCollection( SearchResultCollection searchResults )
        {
            ExchangeUserDict userCollection = new ExchangeUserDict();

            if ( searchResults != null )
            {
                /* For each result set in the result set */
                foreach ( System.DirectoryServices.SearchResult result in searchResults )
                {
                    /* Extract the property collection and create a new exchange user with it
                     * Add the new user to the result set and use the account name as the index for
                     * the dictionary collection */
                    ResultPropertyCollection property = result.Properties;
                    ExchangeUser user = new ExchangeUser( property );

                    if ( !user.IsValid )
                    {
                        log.WarnFormat( "User '{0}' is invalid and will not be synchronized.", user.CommonName );
                    }
                    else if ( userCollection.ContainsKey( user.Email.ToLower() ) )
                    {
                        log.WarnFormat( "User '{0}' was returned multiple times in the LDAP query. " +
                            "Only the first instance was added.", user.Email );
                    }
                    else
                    {
                        userCollection.Add( user.Email.ToLower(), user );
                        log.InfoFormat("Found and added '{0}' as an ExchangeUser.", user.Email);
                    }

                    log.DebugFormat("LDAP object debug info: {0}", user);
                }
            }

            return userCollection;
        }
        private static Dictionary<ExchangeUser, FreeBusy> ParseRasterFreeBusyResponse(
            ExchangeUserDict users,
            DateTime baseTime,
            Stream response)
        {
            Dictionary<ExchangeUser, FreeBusy> result = new Dictionary<ExchangeUser, FreeBusy>();
            string emailAddress = null;
            string freeBusyRaster = null;
            string elementName = null;
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.XmlResolver = null;
            settings.IgnoreComments = true;
            settings.IgnoreWhitespace = true;
            settings.ValidationType = ValidationType.None;
            settings.ValidationFlags = XmlSchemaValidationFlags.None;
            XmlReader reader = XmlReader.Create(response, settings);

            reader.MoveToContent();
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        elementName = reader.LocalName;
                        if (elementName == "item")
                        {
                            emailAddress = null;
                            freeBusyRaster = null;
                        }

                        break;

                    case XmlNodeType.Text:
                        if (elementName == "email")
                        {
                            emailAddress = reader.Value.ToLower();
                        }
                        else
                        {
                            if (elementName == "fbdata")
                            {
                                freeBusyRaster = reader.Value;
                            }
                        }

                        break;

                    case XmlNodeType.EndElement:
                        if (reader.LocalName == "item")
                        {
                            ParseFreeBusyRaster(users,
                                                baseTime,
                                                emailAddress,
                                                freeBusyRaster,
                                                result);

                            emailAddress = null;
                            freeBusyRaster = null;
                        }
                        elementName = string.Empty;

                        break;
                }
            }

            return result;
        }
        /// <summary>
        /// Load free busy information from the public folder
        /// </summary>
        /// <param name="exchangeServerUrl">The exchange server to use</param>
        /// <param name="users">The set of users to get free busy info for</param>
        /// <param name="window">The DateTime range to get free busy info for</param>
        /// <returns>A set of FreeBusy information for each user</returns>
        public Dictionary<ExchangeUser, FreeBusy> LoadFreeBusy(
            string exchangeServerUrl,
            ExchangeUserDict users,
            DateTimeRange window)
        {
            DateTimeRange roundedWindow = DateUtil.RoundRangeToInterval(window, kFreeBusyInterval);

            string url = FreeBusyUrl.GenerateFreeBusyLookupUrl(exchangeServerUrl,
                                                               users,
                                                               roundedWindow,
                                                               kFreeBusyInterval);
            Stream response = IssueRequest(url, Method.GET, string.Empty);
            Dictionary<ExchangeUser, FreeBusy> result = null;

            try
            {
                result = ParseRasterFreeBusyResponse(users,
                                                     roundedWindow.Start,
                                                     response);
            }
            finally
            {
                response.Close();
            }

            return result;
        }
        private static void ParseFreeBusyRaster(
            ExchangeUserDict users,
            DateTime baseTime,
            string emailAddress,
            string freeBusyRaster,
            Dictionary<ExchangeUser, FreeBusy> result)
        {
            ExchangeUser user = null;

            if (emailAddress == null || !users.TryGetValue(emailAddress, out user))
            {
                return;
            }

            FreeBusy freeBusy = new FreeBusy();
            freeBusy.User = user;

            FreeBusyConverter.ParseRasterFreeBusy(baseTime,
                                                  kFreeBusyInterval,
                                                  freeBusyRaster,
                                                  freeBusy);

            FreeBusyConverter.CondenseFreeBusyTimes(freeBusy.All);

            result[user] = freeBusy;
        }
        private void LogQueryResults(
            ExchangeUserDict userCollection, string[] searchTerms, string ldapAttribute )
        {
            if ( userCollection.Count != searchTerms.Length )
            {
                if ( ldapAttribute == "sAMAccountName" )
                {
                    foreach ( string term in searchTerms )
                    {
                        if ( !userCollection.ContainsKey( term.ToLower() ) )
                        {
                            log.InfoFormat( "Unable to find Active Directory user where '{0}'='{1}'.", ldapAttribute, term );
                        }
                    }
                }
                else if ( ldapAttribute == "mail" )
                {
                    foreach ( string email in searchTerms )
                    {
                        string login = email.Split( '@' )[ 0 ];

                        if ( !userCollection.ContainsKey( login.ToLower() ) )
                        {
                            log.InfoFormat( "Unable to find Active Directory user where '{0}'='{1}'.", ldapAttribute, email );
                        }
                    }
                }
                else
                {
                    log.InfoFormat(
                        "Unable to find all users in Active Directory.  [Users={0}]",
                        string.Join( ";", searchTerms ) );
                }
            }
        }
        /// <summary>
        /// Assigns free busy times to the exchange users that are passed into the method
        /// </summary>
        public virtual void GetCalendarInfoForUser(ExchangeUser user, DateTimeRange window)
        {
            ExchangeUserDict users = new ExchangeUserDict();
            users.AddExchangeUser(user.Email, user);

            GetCalendarInfoForUsers(users, window);
        }
        /// <summary>
        /// Assigns free busy times to the exchange users that are passed into the method
        /// </summary>
        public virtual void GetCalendarInfoForUsers(ExchangeUserDict users, DateTimeRange window)
        {
            // Perform  appointment lookup in parallel with FB lookup
            using (AppointmentLookupFuture future =
                new AppointmentLookupFuture(this, users, window))
            {
                Dictionary<ExchangeUser, FreeBusy> freeBusyBlocks =
                    freebusy.LookupFreeBusyTimes(users, window);

                foreach (ExchangeUser user in users.Values)
                {
                    // If the server gave us no data for a user, that's
                    // fine.  We just skip the user.
                    if (!freeBusyBlocks.ContainsKey(user))
                        continue;

                    /* Retrieve the free busy blocks */
                    FreeBusy freeBusy = freeBusyBlocks[user];

                    user.AccessLevel = GCalAccessLevel.ReadAccess;

                    List<Appointment> appointments = future.getResult(user);

                    MergeFreeBusyWithAppointments(
                        user,
                        freeBusy,
                        appointments,
                        window);
                }
            }
        }
        /// <summary>
        /// Returns the free busy times for the specified exchange users
        /// </summary>
        /// <param name="user">The user which free/busy blocks will be looked up for</param>
        /// <param name="window">The date range to do the lookup</param>
        /// <returns>FreeBusy data for user in the daterange</returns>
        public FreeBusy LookupFreeBusyTimes( ExchangeUser user, DateTimeRange window )
        {
            ExchangeUserDict users = new ExchangeUserDict();
            users.Add( user.Email, user );

            Dictionary<ExchangeUser, FreeBusy> result = LookupFreeBusyTimes ( users, window );

            return result[user];
        }
        private static Dictionary <ExchangeUser, FreeBusy> ParseRasterFreeBusyResponse(
            ExchangeUserDict users,
            DateTime baseTime,
            Stream response)
        {
            Dictionary <ExchangeUser, FreeBusy> result = new Dictionary <ExchangeUser, FreeBusy>();
            string            emailAddress             = null;
            string            freeBusyRaster           = null;
            string            elementName = null;
            XmlReaderSettings settings    = new XmlReaderSettings();

            settings.XmlResolver      = null;
            settings.IgnoreComments   = true;
            settings.IgnoreWhitespace = true;
            settings.ValidationType   = ValidationType.None;
            settings.ValidationFlags  = XmlSchemaValidationFlags.None;
            XmlReader reader = XmlReader.Create(response, settings);

            reader.MoveToContent();
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                case XmlNodeType.Element:
                    elementName = reader.LocalName;
                    if (elementName == "item")
                    {
                        emailAddress   = null;
                        freeBusyRaster = null;
                    }

                    break;

                case XmlNodeType.Text:
                    if (elementName == "email")
                    {
                        emailAddress = reader.Value.ToLower();
                    }
                    else
                    {
                        if (elementName == "fbdata")
                        {
                            freeBusyRaster = reader.Value;
                        }
                    }

                    break;

                case XmlNodeType.EndElement:
                    if (reader.LocalName == "item")
                    {
                        ParseFreeBusyRaster(users,
                                            baseTime,
                                            emailAddress,
                                            freeBusyRaster,
                                            result);

                        emailAddress   = null;
                        freeBusyRaster = null;
                    }
                    elementName = string.Empty;

                    break;
                }
            }

            return(result);
        }
        public void TestFastFreeBusyLookup()
        {
            _requestor.ValidMethod = Method.GET;
            _requestor.ResponseBody = getResponseXML("FreeBusyResponse.xml");

            // These dates correspond to when the response XML was captured
            DateTime start = DateUtil.ParseDateToUtc("2007-12-25T01:46:50Z");
            DateTime end = DateUtil.ParseDateToUtc("2008-01-08T01:42:50Z");
            DateTimeRange range = new DateTimeRange(start, end);

            ExchangeUserDict users = new ExchangeUserDict();
            users.Add(_user.Email, _user);

            Dictionary<ExchangeUser, FreeBusy> result = _webdav.LoadFreeBusy(exchangeServer,
                                                                             users,
                                                                             range);
            Assert.AreEqual(1, result.Count);

            FreeBusy fb = result[_user];

            Assert.AreEqual(6, fb.All.Count);
            Assert.AreEqual(6, fb.Busy.Count);
            Assert.AreEqual(0, fb.OutOfOffice.Count);
            Assert.AreEqual(0, fb.Tentative.Count);

            //dumpFreeBusy(fb.Busy);

            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:00:00Z"), fb.Busy[0].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:30:00Z"), fb.Busy[0].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T20:30:00Z"), fb.Busy[1].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T21:00:00Z"), fb.Busy[1].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T17:30:00Z"), fb.Busy[2].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T18:00:00Z"), fb.Busy[2].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:00:00Z"), fb.Busy[3].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:30:00Z"), fb.Busy[3].End);

            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:00:00Z"), fb.All[0].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T18:30:00Z"), fb.All[0].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T20:30:00Z"), fb.All[1].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-26T21:00:00Z"), fb.All[1].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T17:30:00Z"), fb.All[2].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T18:00:00Z"), fb.All[2].End);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:00:00Z"), fb.All[3].Start);
            Assert.AreEqual(DateUtil.ParseDateToUtc("2007-12-31T21:30:00Z"), fb.All[3].End);
        }
        /// <summary>
        /// Generate a URL for the new Free Busy Lookup format which is a replacement
        /// for public folders - documented here: http://support.microsoft.com/kb/813268
        /// </summary>
        /// <param name="exchangeServer">The exchange server to use</param>
        /// <param name="users">The set of users to lookup</param>
        /// <param name="range">The datetime range to lookup for</param>
        /// <param name="interval">The time interval to use</param>
        /// <returns>The URL to obtain FB info for the set of users</returns>
        public static string GenerateFreeBusyLookupUrl(
            string exchangeServer,
            ExchangeUserDict users,
            DateTimeRange range,
            int interval)
        {
            StringBuilder result = new StringBuilder(256);

            result.AppendFormat("{0}/public/?cmd=freebusy&start={1}&end={2}&interval={3}",
                                exchangeServer,
                                DateUtil.FormatDateForISO8601(range.Start),
                                DateUtil.FormatDateForISO8601(range.End),
                                interval);
            foreach (ExchangeUser user in users.Values)
            {
                result.AppendFormat("&u={0}", user.Email);
            }

            return result.ToString();
        }