Namespace UserControls
Public Class OutlookCalendarWidget
Inherits System.Web.UI.UserControl
Private Const _activeSyncServer As String = "https://webmail.yourdomain.com/"
Private _calendarItems As List(Of CalendarItem)
Protected Class CalendarItem
Public Class Attendee
Public Property Name As String
Public Property Email As String
End Class
Public Property IsAllDay As Boolean
Public Property StartTime As DateTime
Public Property EndTime As DateTime
Public Property Subject As String
Public Property Location As String
Public Property Attendees As New List(Of Attendee)
Private _groupName As String
Public ReadOnly Property GroupName As String
Get
If String.IsNullOrEmpty(_groupName) Then
'categorize this calendar entry into a group
Dim daysFromToday As TimeSpan = StartTime.Date.Subtract(Today.Date)
Select Case daysFromToday.Days
Case Is < 0
_groupName = "Past"
Case Is = 0
_groupName = "Today"
Case Is <= 7
_groupName = StartTime.ToString("dddd")
Case Is <= 14
_groupName = "Next Week"
Case Else
_groupName = "Rest of Year"
End Select
End If
Return _groupName
End Get
End Property
Public ReadOnly Property TimespanString As String
Get
Dim format As String = ""
Dim elapsed As TimeSpan = EndTime.Subtract(StartTime)
'any days?
If elapsed.Days > 0 Then format &= "d'days'"
'hours?
If elapsed.Hours > 0 Then format &= CStr(IIf(format <> "", "\ ", "")) & "h'hrs'"
'mins?
If elapsed.Minutes > 0 Then format &= CStr(IIf(format <> "", "\ ", "")) & "m'mins'"
Return elapsed.ToString(format)
End Get
End Property
Public ReadOnly Property AttendeesList As String
Get
Return String.Join(", ", From a In Attendees Select a.Name)
End Get
End Property
End Class
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
MessageLoop()
End If
End Sub
Private Function GetUsername() As String
If HttpContext.Current.User IsNot Nothing AndAlso HttpContext.Current.User.Identity IsNot Nothing AndAlso Not String.IsNullOrEmpty(HttpContext.Current.User.Identity.Name) Then
'domain logged in - get the username
Return HttpContext.Current.User.Identity.Name
Else
Return txtUsername.Text
End If
End Function
Private Function GetPassword() As String
Return txtExchangePass.Text
End Function
Private Sub SyncCalendar()
Try
Dim fullUsername As String = GetUsername()
Dim username As String = ""
Dim domain As String = ""
Dim pw As String = GetPassword()
'check for domain login
If fullUsername.Contains("\") Then
Dim parts() As String = fullUsername.Split("\"c)
domain = parts(0)
username = parts(1)
Else
username = fullUsername
End If
Dim asHelper As New Email.Exchange.AirSync.AirSyncHelper(_activeSyncServer, username, pw, domain)
If asHelper.IsVersionCompatible() Then
'make sure the policy key is populated (if applicable) - not required for this version
'asHelper.ObtainPolicyKey()
'do an initial folder sync for the user (resets the sync on the server)
Dim initFolderSyncResult As System.Xml.XmlDocument = GetFolderSyncResult(asHelper, "0")
'use a namespace manager for FolderSync
Dim initFolderSyncNsMgr As New System.Xml.XmlNamespaceManager(initFolderSyncResult.NameTable)
'since XPATH 1 doesnt support default namespaces, we will have to invent our own
initFolderSyncNsMgr.AddNamespace("dflt", Email.Exchange.AirSync.Codepages.FolderHierarchy_7.Instance.XmlNs)
Dim statusNode As System.Xml.XmlNode = initFolderSyncResult.SelectSingleNode("dflt:FolderSync/dflt:Status", initFolderSyncNsMgr)
If statusNode IsNot Nothing AndAlso statusNode.InnerText = "1" Then
Dim folderSyncSyncKeyNode As System.Xml.XmlNode = initFolderSyncResult.SelectSingleNode("dflt:FolderSync/dflt:SyncKey", initFolderSyncNsMgr)
If folderSyncSyncKeyNode IsNot Nothing Then
'use the sync key to start a sync session on the server to complete the foldersync cycle
GetFolderSyncResult(asHelper, folderSyncSyncKeyNode.InnerText)
'do a sync on the calendar folder by using the server Id of the calendar from the initial sync
Dim calendarFolderNode As System.Xml.XmlNode = initFolderSyncResult.SelectSingleNode("dflt:FolderSync/dflt:Changes/dflt:Add[dflt:DisplayName = ""Calendar""]", initFolderSyncNsMgr)
If calendarFolderNode IsNot Nothing Then
Dim calendarFolderServerId As String = calendarFolderNode("ServerId").InnerText
Dim initialCalendarSyncResult As System.Xml.XmlDocument = GetSyncResult(asHelper, calendarFolderServerId, "Calendar", "0")
'use a namespace manager for Sync
Dim initCalSyncNsMgr As New System.Xml.XmlNamespaceManager(initialCalendarSyncResult.NameTable)
'since XPATH 1 doesnt support default namespaces, we will have to invent our own
initCalSyncNsMgr.AddNamespace("dflt", Email.Exchange.AirSync.Codepages.AirSync_0.Instance.XmlNs)
Dim calendarSyncKeyNode As System.Xml.XmlNode = initialCalendarSyncResult.SelectSingleNode("dflt:Sync/dflt:Collections/dflt:Collection/dflt:SyncKey", initCalSyncNsMgr)
If calendarSyncKeyNode IsNot Nothing Then
'now we can do a second sync to get the juicy stuff
Dim calendarSyncKey As String = calendarSyncKeyNode.InnerText
Dim juicyCalendarSyncResult As System.Xml.XmlDocument = GetSyncResult(asHelper, calendarFolderServerId, "Calendar", calendarSyncKey)
_calendarItems = ParseCalender(juicyCalendarSyncResult)
If _calendarItems IsNot Nothing AndAlso _calendarItems.Count > 0 Then
'bind the groups in date order (dont include items from the past)
rptCalendarItemGroups.DataSource = (From ci In _calendarItems Order By ci.StartTime Ascending Where ci.StartTime.Date >= Today.Date And ci.StartTime.Date <= Today.Date.AddDays(14) Group ci By ci.GroupName Into g = Group Select g.First().GroupName)
rptCalendarItemGroups.DataBind()
If rptCalendarItemGroups.Items.Count = 0 Then lblActiveSyncErrorMessage.Text = "You have no calendar items to display"
Else
'couldnt do it - after all that!!
lblActiveSyncErrorMessage.Text = "Could not do sync the calendar folder. "
'see if there was a status from AS
'use a namespace manager for FolderSync
Dim statusNsMgr As New System.Xml.XmlNamespaceManager(juicyCalendarSyncResult.NameTable)
'since XPATH 1 doesnt support default namespaces, we will have to invent our own
statusNsMgr.AddNamespace("dflt", Email.Exchange.AirSync.Codepages.AirSync_0.Instance.XmlNs)
Dim juicyStatusNode As System.Xml.XmlNode = juicyCalendarSyncResult.SelectSingleNode("dflt:Sync/dflt:Collections/dflt:Collection/dflt:Status", statusNsMgr)
If juicyStatusNode IsNot Nothing Then lblActiveSyncErrorMessage.Text &= " ActiveSync status: " & juicyStatusNode.InnerText
End If
Else
lblActiveSyncErrorMessage.Text = "Could not do initial sync on the calendar folder."
End If
Else
lblActiveSyncErrorMessage.Text = "There is no calendar folder found in the initial folder sync."
End If
Else
lblActiveSyncErrorMessage.Text = "Could not find SyncKey in FolderSync response."
End If
Else
lblActiveSyncErrorMessage.Text = "Initial FolderSync did not complete."
If statusNode IsNot Nothing Then lblActiveSyncErrorMessage.Text &= " ActiveSync status: " & statusNode.InnerText
End If
Else
Throw New Exception("Server does not support the correct verion of AirSync. Required version: " & Email.Exchange.AirSync.AirSyncHelper.AirSyncSupportedVersion)
End If
Catch wEx As Net.WebException
If wEx.Message.Contains("401") Then
pnlNotAuth.Visible = True
Else
Throw wEx
End If
Catch ex As Exception
lblActiveSyncErrorMessage.Text = "Could not connect to ActiveSync. " & ex.Message
End Try
End Sub
Private Function GetFolderSyncResult(ByVal asHelper As Email.Exchange.AirSync.AirSyncHelper, ByVal syncKey As String) As System.Xml.XmlDocument
Dim xmlRequestData As String = <?xml version="1.0" encoding="utf-8"?>
<FolderSync xmlns="FolderHierarchy:">
<SyncKey>{SyncKey}</SyncKey>
</FolderSync>.ToString().Replace("{SyncKey}", syncKey)
Return asHelper.ExecuteAirSyncCommand("FolderSync", xmlRequestData)
End Function
Private Function GetSyncResult(ByVal asHelper As Email.Exchange.AirSync.AirSyncHelper, ByVal collectionId As String, ByVal className As String, ByVal syncKey As String) As System.Xml.XmlDocument
Dim xmlRequestData As String
'initial sync has different body content
If syncKey = "0" Then
xmlRequestData = <?xml version="1.0" encoding="utf-8"?>
<Sync xmlns="AirSync:">
<Collections>
<Collection>
<Class>{ClassName}</Class>
<SyncKey>{SyncKey}</SyncKey>
<CollectionId>{CollectionId}</CollectionId>
</Collection>
</Collections>
</Sync>.ToString().Replace("{SyncKey}", syncKey).Replace("{CollectionId}", collectionId).Replace("{ClassName}", className)
Else
xmlRequestData = <?xml version="1.0" encoding="utf-8"?>
<Sync xmlns="AirSync:">
<Collections>
<Collection>
<Class>{ClassName}</Class>
<SyncKey>{SyncKey}</SyncKey>
<CollectionId>{CollectionId}</CollectionId>
<DeletesAsMoves/>
<GetChanges/>
</Collection>
</Collections>
</Sync>.ToString().Replace("{SyncKey}", syncKey).Replace("{CollectionId}", collectionId).Replace("{ClassName}", className)
End If
Return asHelper.ExecuteAirSyncCommand("Sync", xmlRequestData)
End Function
Private Sub rptCalendarItemGroups_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptCalendarItemGroups.ItemDataBound
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim rptCalendarEvents As Repeater = CType(e.Item.FindControl("rptCalendarEvents"), Repeater)
rptCalendarEvents.DataSource = From ci In _calendarItems Where ci.GroupName = CStr(e.Item.DataItem) Order By ci.StartTime Ascending Select ci
rptCalendarEvents.DataBind()
End If
End Sub
Protected Sub rptCalendarEvents_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs)
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
If DirectCast(e.Item.DataItem, CalendarItem).EndTime < Now Then
Dim pnlCalenderItem As Panel = CType(e.Item.FindControl("pnlCalenderItem"), Panel)
pnlCalenderItem.CssClass &= " strikeout"
End If
End If
End Sub
'Private isAlt As Boolean = False
'Protected Function GetCalendarRowIsAlt() As Boolean
' 'remember current row
' Dim thisOneIsAlt As Boolean = isAlt
' 'invert for next call
' isAlt = Not isAlt
' Return thisOneIsAlt
'End Function
Private Function ParseCalender(ByVal juicyCalendarSyncResult As System.Xml.XmlDocument) As List(Of CalendarItem)
Dim cItems As List(Of CalendarItem) = Nothing
'use a namespace manager for Calendar Sync
Dim juicyCalSyncNsMgr As New System.Xml.XmlNamespaceManager(juicyCalendarSyncResult.NameTable)
'since XPATH 1 doesnt support default namespaces, we will have to invent our own + register the calendar prefix
juicyCalSyncNsMgr.AddNamespace("dflt", Email.Exchange.AirSync.Codepages.AirSync_0.Instance.XmlNs)
juicyCalSyncNsMgr.AddNamespace(Email.Exchange.AirSync.Codepages.Calendar_4.Instance.XmlPrefix, Email.Exchange.AirSync.Codepages.Calendar_4.Instance.XmlNs)
Dim juicyStatusNode As System.Xml.XmlNode = juicyCalendarSyncResult.SelectSingleNode("dflt:Sync/dflt:Collections/dflt:Collection/dflt:Status", juicyCalSyncNsMgr)
If juicyStatusNode IsNot Nothing AndAlso juicyStatusNode.InnerText = "1" Then
'we can bindings to repeaterings
cItems = New List(Of CalendarItem)
For Each node As System.Xml.XmlNode In juicyCalendarSyncResult.SelectNodes("dflt:Sync/dflt:Collections/dflt:Collection/dflt:Commands/dflt:Add/dflt:ApplicationData", juicyCalSyncNsMgr)
Dim ci As New CalendarItem
ci.StartTime = DateTime.ParseExact(node("StartTime", "Calendar:").InnerText, "yyyyMMdd'T'HHmmss'Z'", Globalization.CultureInfo.CurrentCulture)
ci.EndTime = DateTime.ParseExact(node("EndTime", "Calendar:").InnerText, "yyyyMMdd'T'HHmmss'Z'", Globalization.CultureInfo.CurrentCulture)
ci.Subject = node("Subject", "Calendar:").InnerText
ci.IsAllDay = (node("AllDayEvent", "Calendar:") IsNot Nothing AndAlso node("AllDayEvent", "Calendar:").InnerText = "1")
If node("Location", "Calendar:") IsNot Nothing Then
ci.Location = node("Location", "Calendar:").InnerText
End If
'get all the accepted attendees
If node("Attendees", "Calendar:") IsNot Nothing Then
Dim attendees As System.Xml.XmlNodeList = node.SelectNodes("calendar:Attendees/calendar:Attendee", juicyCalSyncNsMgr)
For Each attendee As System.Xml.XmlNode In attendees
'accepted? (or not specified)
If attendee("AttendeeStatus", "Calendar:") Is Nothing OrElse attendee("AttendeeStatus", "Calendar:").InnerText <> "4" Then
ci.Attendees.Add(New CalendarItem.Attendee() With {
.Name = attendee("Attendee_Name", "Calendar:").InnerText,
.Email = attendee("Attendee_Email", "Calendar:").InnerText})
End If
Next
'organizer is attending
If node("Organizer_Name", "Calendar:") IsNot Nothing Then
Dim organiserName As String = node("Organizer_Name", "Calendar:").InnerText
If Not ci.AttendeesList.Contains(organiserName) Then
ci.Attendees.Add(New CalendarItem.Attendee() With {
.Name = organiserName,
.Email = node("Organizer_Email", "Calendar:").InnerText})
End If
End If
End If
cItems.Add(ci)
Next
End If
Return cItems
End Function
Private Sub btnSetUserContext_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSetUserContext.Click
MessageLoop()
End Sub
Private Sub MessageLoop()
pnlEpicFail.Visible = False
pnlOutlookCalendar.Visible = False
pnlSetUserContext.Visible = False
pnlSubmitExchangePw.Visible = False
'check we have a username/password and then sync
If GetUsername() = "" Then
pnlSetUserContext.Visible = True
ElseIf GetPassword() = "" Then
pnlSubmitExchangePw.Visible = True
Else
pnlOutlookCalendar.Visible = True
SyncCalendar()
End If
End Sub
Private Sub btnSubmitExchangePass_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmitExchangePass.Click
MessageLoop()
End Sub
Private Sub btnResetPassword_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnResetPassword.Click
'show the password entry screen
pnlNotAuth.Visible = False
pnlOutlookCalendar.Visible = False
pnlSubmitExchangePw.Visible = True
End Sub
End Class
End Namespace
Recent Comments