The Team Folders Wizard Administration Extension

[Previous] [Next]

To enhance the capabilities of the Team Folders Wizard, you can use the Team Folders Wizard Administration Extension provided on this book's companion CD. This extension provides a number of features that the Team Folders Wizard lacks. These features make it easier for administrators to control the creation of Team Folders applications and are listed here:

  • Approval and rejection of Team Folders applications
  • Creation of distribution lists (DLs) for Team Folders applications
  • Deletion of Team Folders applications, including DLs and folders associated with the application

The Administration Extension also incorporates some Exchange Server features that make the Team Project application easier to use. The extension provides a useful subscription/notification feature for any public folder application. The user can subscribe to a public folder, and an agent will notify her when a new item has been created there. In addition, the agent will send a link to the new item created in the folder.

Architecture of the Team Folders Wizard Administration Extension

Before diving into the code behind this extension, let's look at its architecture. The extension is comprised of a mailbox for the Event Scripting Agent. This agent processes Team Folders application requests, processes the approval/rejection of those requests, and dynamically creates the subscription/notification agents in the team folders themselves. The agent uses a distribution list, known as the Administrative Agent Distribution List (AADL), which names the administrators who can approve or reject the creation of Team Folders applications.

In addition to this agent, a client-side ActiveX control runs as part of the extension. This control checks to see whether the Team Folders application has been approved; if it hasn't, the control doesn't allow the Team Folders application to display any windows. To host this control, we modify the Team Folders HTML files to load the ActiveX control.

There are two aspects of the extension you should be aware of. First, I modified only the Team Project template to support the extension. After looking through the changes in the Team Project template, you should be able to easily modify the other templates of the Team Folders Wizard to support the extension. Second, I didn't sign the ActiveX control, and I have the CodeBase pointing to the standard Team Folders CodeBase location I specified when I set up the Team Folders Wizard. I didn't want to sign the control because you might want to give it your own signature, depending on how you use it. If you use the control as is from the companion CD, Outlook will ask whether you want to run an ActiveX control on a Web page.

Installing the Team Folders Wizard Administration Extension

Rather than detail the steps for installing this extension from the companion CD, I'll highlight the tools included with it that make installing the extension much easier. I'll also show you how to use a number of Exchange Server programming components, such as Active Directory Services Interface (ADSI) and the Event Scripting Configuration Library.

The companion CD contains three installation programs for the Team Folders Wizard Administration Extension. The first one is the agent installation program, which you must run on your Exchange server. The agent installation program creates the mailbox for the Team Folders Wizard Administration Extension agent and allows you to select membership for the AADL. This installation program also creates the agent and dynamically populates its script. Figure 9-13 depicts the user interface for the agent installation program. You can see the code for this installation program on the companion CD.

Figure 9-13. The agent installation program for the Team Folders Wizard Administration Extension.

The second installation program on the companion CD is the template installation program. You need to run this program on all client machines on which you want to use the Team Folders template. This program makes a backup of the original Team Folders templates and replaces the project template with the modified template. We'll look at the code for this later in the chapter.

The final program installs the ActiveX control. You can either modify the CodeBase property on the HTML pages to point at the .cab file included for the ActiveX control, or you can manually register the control from the .cab file.

Modifying the HTML for a Team Folders Wizard Template

Since the Team Folders templates are HTML files, you can easily modify them to fit your needs, including adding custom controls, HTML, or even script to the page. By looking at the modifications the extension makes to the HTML pages, you can determine what types of modifications you can make to your own applications.

The key modifications the extension makes to the Administration page of the Team Project template are the addition of a menu item, a Delete This Team button, and the ActiveX control. Since modifying the HTML for the Team Folders templates is pretty straightforward, I won't spend much time discussing how to modify the intrinsic HTML buttons and other elements of the user interface. However, the ActiveX control and some of the script in the HTML page contain the interesting code we'll examine next. Figure 9-14 shows the user interface of the modified Administration page.

click to view at full size.

Figure 9-14. The modified Administration page. Notice the new team deletion capabilities.

The code in this section shows some of the modifications the extension makes to the Administration page. The first code snippet uses the ActiveX control called Session, which checks to see whether the Team Folders application has been approved. If it hasn't, the code displays the nice message shown in Figure 9-15.

<SCRIPT LANGUAGE="vbscript"> <!— Function IsApproved() Dim CurrentState CurrentState = Session.TeamApproved(g_Fullpath, False,True) Select Case lcase(CurrentState) Case "requested" IsApproved = False Case "notadministrator" IsApproved = False Case "approved" IsApproved = True Case Else IsApproved = False End Select End Function If (not IsIEOK) or (Not IsOLOK) or (cInt(lErrCode) <> 0) Then 'there were no initialization errors ErrorBox.style.display = "inline" Else 'Added by the Team Folders Wizard Extension. 'Check to see whether this team has been approved. If IsApproved = False Then IsAdmin = False TheBodyUnapproved.style.display = "inline" Else 'Added TheBody.style.display = "inline" End If 'Added End If --> </SCRIPT>

click to view at full size.

Figure 9-15. This page is shown if the application is waiting for administrator approval.

Here is the code for the TeamApproved function in the ActiveX control:

Public Function TeamApproved(strFolderPath, _ TopTeamFolder As Boolean, AdminFolder As Boolean) On Error GoTo errHandler Dim Pos Dim strBody DoMAPILogon 'Get the Administration folder and InfoStore If GetFolderAndInfoStore(CStr(strFolderPath), oTeamFolder, _ oInfoStore) = False Then Exit Function If InDebug Then MsgBox "Got Folder & InfoStore for strFolderPath: " _ & strFolderPath Dim strAddressID strAddressID = GetAddressIDFromAlias(strTFWAAlias) If strAddressID = 0 Then MsgBox "Error getting address of the TFWA alias in TeamApproved." End If Set TFWAAddress = oSession.GetAddressEntry(strAddressID) If InDebug Then If Not (TFWAAddress Is Nothing) Then MsgBox "Got TFWAAddress" Else MsgBox "Didn't get TFWAAddress" End If End If EnsureTFWA_IsIn_ACL oTeamFolder 'Get the main team folder If TopTeamFolder = False Then 'We're currently looking at the Administration folder, 'and need to move up one folder level to access the main team folder Set oTeamFolder = oSession.GetFolder(oTeamFolder.FolderID, _ oInfoStore.ID) EnsureTFWA_IsIn_ACL oTeamFolder If InDebug Then MsgBox "Looking at : " & oTeamFolder.Name End If 'We also need to make sure the Administration folder is a member of 'all the subfolders 'If AdminFolder = True Then EnsureTFWA_IsIn_ACL_AllSubFolders oTeamFolder 'End If 'Determine the actual team path, and store it for notifying the 'AADL Pos = InStrRev(strFolderPath, oTeamFolder.Name) strTeamPath = Left(strFolderPath, Pos + Len(oTeamFolder.Name)) If InDebug Then MsgBox "strTeamPath: " & strTeamPath If TeamStatusMessageFound(oTeamFolder) = False Then If strErrNo = 0 Then If InDebug Then MsgBox "No Team Status Message found" 'We have not done any of the administration required 'to start the team approval process If AdminFolder = True Then If InDebug Then MsgBox "Admin Page" 'Hide the team folder from the team members If InDebug Then MsgBox "Attempting to Hide folder from team members" End If If SetFolderACL(oTeamFolder) = False Then TeamApproved = "An Error occurred 1. Ensure The " & _ "TFW Administrator has owner rights to this folder." Exit Function End If If InDebug Then MsgBox "Hidden folder from team members" 'Create the message body for the message strBody = CreateMsgBody("Requested") If CreateHiddenStatusMessage(oTeamFolder, strBody) = _ False Then TeamApproved = "An Error occurred 2. Ensure The " & _ "TFW Administrator has owner rights to this folder." Exit Function End If SendAgentMsg strBody, "TF: Create Team Folder request" End If TeamApproved = "Requested" Else Select Case strErrNo Case -2147024891 strErrDesc = "You do not have permission to read " & _ "entries in this folder." Case Else 'Do nothing End Select TeamApproved = "Error encountered: " & strErrDesc & _ " " & strErrNo Err.Clear End If Else TeamApproved = strCurrentTeamStatus End If Exit Function errHandler: MsgBox "Error in TeamApproved function. Err #" & Err.Number _ & " Description: " & Err.Description End Function

The TeamApproved function makes sure that the mailbox object of the Team Folders Wizard Administration Extension has Owner rights on all the folders for the application. When performing subscription and notification, this mailbox must be able to dynamically create agents in the application folders—and to do so, the mailbox must have Owner rights.

Next, TeamApproved checks to see whether a hidden message exists in the application's root folder. If no hidden message exists, it means that the application is a new one. If that's the case, the control creates a new hidden message and sends an approval notice to the extension agent. The control then sets the application status to Requested.

If the control does find a hidden status message in the root folder, it checks the message to see whether the team has been approved, has been rejected, or is still waiting for approval. The control returns this status to the HTML page so that the page can act accordingly.

The next function in the Administration page, RequestDeleteTeam, deletes the team. Since the Team Folders applications do not provide a good way for users to delete their applications, the extension offers this capability. This function requests that the agent delete all the applications' team folders, and forces the Outlook client to move to a folder other than the applications' team folder. This prevents Outlook from sitting on the folder while the agent deletes it in the background.

The Event Scripting Agent for the Administration Extension

I'd like to point out three aspects of the Event Scripting Agent for the Team Folders Wizard Administration Extension. (Chapter 13 will cover the Event Scripting Agent in much more detail.) First, the extension's Event Scripting Agent performs extensive logging, as shown in Figure 9-16. This logging allows you to watch the agent actions.

Second, the Event Scripting Agent uses subfolders to log the messages it receives, as shown in Figure 9-17. You can use these subfolders to troubleshoot any problems such as malfunctions in the agent or the functions it performs.

Figure 9-16. The log from the extension's Event Scripting Agent.

click to view at full size.

Figure 9-17. The subfolder structure of the extension mailbox.

Third, the Event Scripting Agent uses ADSI to dynamically create distribution lists and to add or remove members from these lists. You could take the code from this agent and build a generic agent that manages distribution lists. The code for managing the extension's DLs is shown here.

'************************************************************** '******* Customized Subroutines…. * '******* This subroutine creates a DL on the fly * '************************************************************** Public Sub CreateNewDL(DLAlias) On Error Resume Next If UserIsOwnerofDL = True Then strOwner = objRequestor.Fields(&H3A00001E).Value Else strOwner = "TFWA" End If LogIt "strOwner is " & strOwner strLDAPPath = "LDAP://" & LDAPServer & "/" & LDAPRecipientContainer _ & "," & LDAPSite & "," & LDAPOrg strLDAPOwnerPath = "LDAP://" & LDAPServer & "/cn=" & strOwner & ", _ " & LDAPRecipientContainer & "," & LDAPSite & "," & LDAPOrg LogIt "LDAP Path: " & strLDAPPath LogIt "LDAP UserName: " & LDAPUserName LogIt "LDAP Password: " & LDAPPassword Logit "New Alias: " & DLAlias Set objMyIADs = GetObject("LDAP:") Set objADSI = objMyIADs.OpenDSObject(strLDAPPath, LDAPUserName, _ LDAPPassword, 0) Set objNewDL = objADSI.Create("groupOfNames", "cn=" & CStr(DLAlias)) set objOwner = objMyIADS.OpenDSObject(strLDAPOwnerPath, _ LDAPUserName, LDAPPassword, 0) objNewDL.Put "cn", CStr(RequestorsName & " " & TeamFolderName) objNewDL.Put "uid", CStr(DLAlias) objNewDL.Put "distinguishedName", CStr("cn=" & CStr(DLAlias) & _ "," & LDAPRecipientContainer & "," & LDAPSite & "," & LDAPOrg) objNewDL.Put "owner", objOwner.distinguishedName objNewDL.Put "mail", CStr(DLAlias) & CStr(strSMTPAddr) objNewDL.Put "Report-To-Originator", True objNewDL.Put "Report-to-Owner", False objNewDL.Put "Replication-Sensitivity", CInt(20) objNewDL.Put "rfc822Mailbox", CStr(DLAlias) & CStr(strSMTPAddr) objNewDL.Put "textEncodedORaddress", CStr(strx400Addr) & _ CStr(DLAlias) & ";" objNewDL.SetInfo dim strPath dim strUID strUID = objNewDL.Get("uid") strPath = strLDAPPath & vblf & strUID LogIt "strPath: " & strPath 'Save DL alias to a hidden message in the team folder StoreDLAliasName strPath End Sub '**************************************************************** '******* This subroutine adds a new member to a DL * '**************************************************************** Public Sub AddMemberToDL(NameToReplace, DLAlias) On Error Resume Next strLDAPPath = "LDAP://" & LDAPServer & "/" & NameToReplace & "," _ & LDAPRecipientContainer & "," & LDAPSite & "," & LDAPOrg strLDAPRecip = "LDAP://" & LDAPServer & "/cn=" & DLAlias & "," _ & LDAPRecipientContainer & "," & LDAPSite & "," & LDAPOrg LogIt "strLDAPPath: " & strLDAPPath LogIt "strLDAPRecip: " & strLDAPRecip Set objIADs = GetObject("LDAP:") Set objLDAPRecip = objIADs.OpenDSObject(strLDAPRecip, _ LDAPUserName, LDAPPassword, 0) objLDAPRecip.Add (strLDAPPath) If Err.Number = -2147016691 Then 'They're already in the DL Else objLDAPRecip.SetInfo End If End Sub '*************************************************************** '******* This subroutine removes a member from a DL * '*************************************************************** Public Sub RemoveMemberFromDL(NameToReplace, DLAlias) On Error Resume Next strLDAPPath = "LDAP://" & LDAPServer & "/" & NameToReplace & "," _ & LDAPRecipientContainer & "," & LDAPSite & "," & LDAPOrg strLDAPRecip = "LDAP://" & LDAPServer & "/cn=" & DLAlias & "," _ & LDAPRecipientContainer & "," & LDAPSite & "," & LDAPOrg Set objIADs = GetObject("LDAP:") Set objLDAPRecip = objIADs.OpenDSObject(strLDAPRecip, _ LDAPUserName, LDAPPassword, 0) objLDAPRecip.Remove (strLDAPPath) objLDAPRecip.SetInfo End Sub

Subscription/Notification Functionality

The last functionality of the Administration Extension that we'll talk about is the subscription/notification functionality. For me, this is the most exciting part of the extension because it makes using any Public Folder application easier. The extension notifies users who subscribed to the Public Folder that a new item is available, meaning users don't have to check for new items in the Public Folder application. Users subscribe to the Public Folder by clicking a button in the home page of any folder in the Team Project application. The subscription/notification functionality is implemented on a folder-by-folder basis. Figure 9-18 shows the interface that allows the user to enable this functionality.

click to view at full size.

Figure 9-18. The user interface for enabling subscription/notification.

The extension tracks which users to notify about new items posted in the folder by storing in the folder a hidden message containing a list of users who've requested notification. The HTML pages in the extension use the CurrentlyNotified function from the ActiveX control to see whether the current user is on the folder's notification list. If the user is on the notification list, the text in the HTML offers the ability to unsubscribe to the notifications. Here is the code for the CurrentlyNotified function:

Public Function CurrentlyNotified(strFolderPath) If InDebug Then MsgBox "strFolderPath = " & strFolderPath If GetFolderAndInfoStore(CStr(strFolderPath), oTeamFolder, _ oInfoStore) = False Then MsgBox "Could not open folder: " & strFolderPath Exit Function End If Dim oHiddenMessages, oFilter Dim oMessage Dim strTeamDLPath, objIADs, objLDAPRecip, arrTeamPath, _ strDLAlias, strRecipContPath Dim arrMembers, strMember Set oHiddenMessages = oTeamFolder.HiddenMessages oHiddenMessages.Filter = Nothing Set oFilter = oHiddenMessages.Filter oFilter.Subject = "TFW Member Notification" If oHiddenMessages.Count >= 1 Then 'There should only ever be one. Set oMessage = oHiddenMessages.GetFirst arrMembers = Split(oMessage.Text, vbCrLf) CurrentlyNotified = False For Each strMember In arrMembers If strMember = oSession.CurrentUser.ID Then CurrentlyNotified = True Exit For End If Next Else 'No notification message exists; therefore, no one is 'currently notified CurrentlyNotified = False End If End Function

If the user asks to be added to the notification list, the application sends a message to the extension's mailbox agent. The extension checks to see whether a notification agent already exists in the requested folder. If it does, the user is added to the hidden notification message in the folder. If the agent doesn't exist, the extension agent creates a new agent in the folder and dynamically binds a script to this newly created notification agent to implement the notification functionality. Figure 919 shows a folder containing the dynamically created agent.

The notification agent uses the Windows Scripting Host to create a shortcut to the newly added item and attaches the shortcut to the notification e-mail. The user can then double-click on the shortcut, causing Outlook to open the original item.

The code for the notification agent follows. Be sure to look at the section that uses the Windows Scripting Host, since you can probably reuse this functionality in a number of your Outlook applications.

Figure 9-19. A Team Folders with the notification agent installed in it.

WARNING
There are two caveats to using this solution. First, the solution will work only online because you're specifying a path to an item that's online. Second, if two items have the same subject in the folder, it's undetermined which one Outlook will open.

'DESCRIPTION: This event is fired when a new message is added 'to the folder Public Sub Folder_OnMessageCreated() Const CdoFileData = 1 Dim oNewMsg, oHidden, aryText, iCount, blnFoundMsg, objAddrEntry Dim objSession, objFolder, aryHiddenMsgText, strRecip Dim WSHShell, MyShortcut, strUserProfile Dim objInMsg, MyAttachment Dim strPath On Error Resume Next Set objSession = EventDetails.Session Set objFolder = objSession.GetFolder(EventDetails.FolderID, Null) LogIt "Running" LogIt "Folder: " & objFolder.Name blnFoundMsg = False For iCount = objFolder.HiddenMessages.Count To 1 Step -1 Set oHidden = objFolder.HiddenMessages(iCount) If oHidden Is Nothing Then LogIt "oHidden is empty -"&_ "there should be at least 1 member to notify " Exit For End If If oHidden.Subject = "TFW Member Notification" Then aryHiddenMsgText = Split(oHidden.Text, vbCrLf) blnFoundMsg = True Exit For End If Next Set oHidden = Nothing If blnFoundMsg = False Then LogIt "Hidden is missing from folder " & objFolder.Name 'Do nothing but exit Set objSession = Nothing Set objFolder = Nothing Exit Sub End If LogIt "Got Hidden " Set oNewMsg = objSession.Outbox.Messages.Add For Each strRecip In aryHiddenMsgText If strRecip <> "" Then Set objAddrEntry = objSession.GetAddressEntry(strRecip) oNewMsg.Recipients.Add , , , objAddrEntry.ID Script.Response = Script.Response & vbCrLf & strRecip End If Next oNewMsg.Recipients.Resolve If oNewMsg.Recipients.Count = 0 Then LogIt "No Recipients to notify" Exit Sub End If Set objInMsg = objSession.GetMessage(EventDetails.MessageID, Null) 'This will create a shortcut and attach it to a message Set WSHShell = CreateObject("WScript.Shell") LogIt "Started" LogIt "Subject: " & objInMsg.Subject strUserProfile = WSHShell.ExpandEnvironmentStrings("%USERPROFILE%") Set MyShortcut = WSHShell.CreateShortcut(strUserProfile & _ "\msolink.url") LogIt strUserProfile Dim oParent strPath = "\" & objFolder.Name 'Get the path to the folder; assume it's in the Public Folder tree set oParent = objSession.GetFolder(objFolder.FolderID,Null) Do While oParent.Name <> "All Public Folders" strPath = "\" & oParent.Name & strPath set oParent = objSession.GetFolder(oParent.FolderID,Null) Loop strPath = "\\Public Folders\All Public Folders" & strPath Dim strPathwithoutFileName strPathwithoutFileName = strPath strPath = strPath & "\~" & objInMsg.Subject LogIt "strPath: " & strPath 'Set shortcut object properties and save them 'You can also try the format outlook:EntryID 'MyShortcut.TargetPath = "outlook:" & objInMsg.ID MyShortcut.TargetPath = "outlook:" & strPath LogIt "MyShortcut.TargetPath: " & strPath MyShortcut.Save LogIt "Saved" Set MyAttachment = oNewMsg.Attachments.Add("Shortcut to " & _ objInMsg.Subject) MyAttachment.Type = CdoFileData 'Attach the link, not a shortcut to it. MyAttachment.Source = strUserProfile & "\msolink.url" LogIt "New Message posted to folder " oNewMsg.Text = "A message has been posted to the folder <outlook:" _ & strPathwithoutFileName & "> " & vblf & _ "This message was posted by " & objInMsg.Sender.Name & "." & _ vblf & "The subject of the message is: " & objInMsg.Subject & _ "." & vblf & "Open the attachment in this mail to read the new item." oNewMsg.Subject = "Notification Message: New Message posted to folder" oNewMsg.Update True, True oNewMsg.Send False, False Set MyShortcut = Nothing Set oNewMsg = Nothing Set WSHShell = Nothing Set objSession = Nothing Set objFolder = Nothing Set objInMsg = Nothing End Sub 



Programming Microsoft Outlook and Microsoft Exchange
Programming Microsoft Outlook and Microsoft Exchange, Second Edition (DV-MPS Programming)
ISBN: 0735610193
EAN: 2147483647
Year: 2000
Pages: 184

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net