Exchange 2000 and Security

[Previous] [Next]

The final topic that we'll cover in the book is instant messaging. Instant messaging provides two sets of services. The first service is the ability to send and receive instant messages. Instant messages are different from e-mail in that they pop up on the receiving user's screen immediately after the message is sent—there is no delay. They also differ from e-mail because a user can actually block another user from sending the message. The only way you can "block" people from sending you e-mail is by automatically deleting the message.

The second and perhaps the most interesting service is the ability to track and display "presence" information about specified contacts. For example, a user could track its team, that is, determine whether team members are online, away from their computers, and so on. With presence technology, however, a user can track the availability and status of virtual teams across the Internet. This is where the power of presence technology shines.

Another great feature of instant messaging is that it is included with Microsoft Exchange 2000. When a user installs Exchange, the user has the option of installing instant messaging and setting up an instant messaging infrastructure. The instant messaging instructure leverages Active Directory and allows the user to extend the services he can offer and develop on in the Exchange environment. Furthermore, the MSN Messenger Service client can be installed on workstations so that users in an organization can leverage instant messaging technology.

At this point, the main question you probably have is, "How does instant messaging relate to developers?" You can take advantage of these features in your collaborative Exchange applications by integrating instant messaging, presence technology, or both. A number of controls produced by Microsoft make the process of integrating instant messaging in your applications very easy. In this chapter, we will take a look at one of these controls, the IM Contact View control. This controls provides a user interface to display presence information and send instant messages as well as a programmatic interface and event model that you can use in your applications.

Before we look at the details of the control, I need to show you the main page of the Training application, which has been updated with instant messaging functionality. As you can see in Figure 19-18, students can now see which instructors are online, and they can filter the list to view only those instructors for their courses. Students can send instant messages to their instructors. The instructors can block students from seeing their availability.

click to view at full size.

Figure 19-18. The updated Training application main page with instant messaging technology added.

Programming the IM Contact View Control

The IM Contact View control is an ActiveX control that you can place on your Web pages to implement IM functionality. This control has a number of properties and methods that you can use to customize the control's interface. You can set properties for the control by using an HTML Object tag, or you can set properties programmatically. The IM View Control is put onto the main.asp page in the application by using an OBJECT tag, as shown here:

 <OBJECT codebase="msimcntl.cab#Version=1,0,0,001" classid=CLSID:B06EDBC7-287D-405C-A899-9C7F8358EF26 codeType=application/x-oleobject id=MSIMContactList name=MSIMContactList VIEWASTEXT height=500> <PARAM NAME="Service" VALUE=0> <!--<PARAM NAME="List" VALUE="$$Messenger\Contact">--> <PARAM NAME="HotTracking" VALUE=FALSE> <PARAM NAME="AllowCollapse" VALUE=TRUE> <PARAM NAME="ShowSelectAlways" VALUE=TRUE> <PARAM NAME="ShowLogonButton" VALUE="1"> <PARAM NAME="OfflineCollapsed" VALUE=TRUE> <PARAM NAME="OnlineCollapsed" VALUE=FALSE> <PARAM NAME="OnlineRootLabel" VALUE="Instructors Online"> <PARAM NAME="OfflineRootLabel" VALUE="Instructors Offline"> <PARAM NAME="FilterOffline" VALUE=FALSE> <PARAM NAME="Group" VALUE=True> </OBJECT> 

As you can see, the PARAM tags pass the name of a property and the value for that property. Table 19-15 describes the available properties on the IM Contact View control.

The control supports seven methods and one function, all of which are very straightforward. Table 19-16 describes them.

The final aspect of the IM Contact View control that you should be aware of is its event support. You can place the control on a Web page, so the control supports events that tell you when users of your application have instantiated the control, are adding new contacts, are requesting menus, or even when the control is shutting down. Using these events, you can customize many aspects of the control. In the Training application, the menu events are used to add a custom menu item to the control so that right from the IM list, users can get details about instructors such as their office locations, phone numbers, and areas of expertise. This enhancement is shown in Figure 19-19.

Table 19-15. The IM Contact View control properties.

Property NameDescription
AllowCollapse This Boolean property specifies whether the user is allowed to collapsed the root nodes in the contact list. If set to False, the user cannot collapse the root nodes.
ExtentHeight This read-only long value returns the optimal height the control needs to be to be displayed without a scrollbar. You can then use DHTML to readjust your Web page to properly fit the control.
ExtentWidth This read-only long value return the optimal width the control needs to be to be displayed without a scrollbar. You can use DHTML to readjust your Web page to properly fit the control.
FilterOffline This Boolean value specifies whether offline contacts should be displayed in the list. True means that you want to filter offline contacts.
Group This Boolean value specifies whether online and offline contacts should be grouped within their respective nodes in the tree. True means that you do want the contacts grouped. Note that you can change the text, as I did, for the tree nodes that the contacts are grouped under by using the OfflineRootLabel and OnlineRootLabel properties, which I'll discuss later.
HotTracking This Boolean specifies whether the IM list will track the cursor as it moves over the list. True means that as the mouse cursor moves over contacts in the list, a hyperlink hand icon and an underline appear.
LoggedOn A Boolean that indicates whether the user is logged on.
List This string is the identifier for the collection of contacts to be used in the control. In the sample code above, the usage of this property is shown as commented out , butyou could have the control automatically load the MSN Messenger contact list as its default. You can also create and identify your own lists in the code and load those up as well. If you don't specify the value for this property , the control generates a random value for the property.
OfflineCollapsed This Boolean value specifies whether the offline contact list will be expanded or collapsed upon loading. True means that the offline contacts should be collapsed.
OfflineRootLabel This string property allows you to customize the text that appears for the offline contact list. In the Training application, this property is set to Instructors Offline.
OnlineCollapsed This Boolean is the same as the OfflineCollapsed property, except that it is affects the online contact list.
OnlineRootLabel This string property allows you to customize the text that appears for the online contact list. In the Training application, this property is set to Instructors Online.
SelectedMenuOptions This read-only Long value specifies which menu options can be performed for a user. This property is not useful unless a contact is selected in the user interface when you query the property on the control.
Service This property returns the Service interface. Providing more details about this interface is beyond the scope of this book.
ShowIcons This Boolean property specifies whether the state icons should be shown. True means to show the state icons, such as the green person icon indicating available and the red person icon indicating offline.
ShowLogonButton This Boolean specifies whether to show a logon prompt if the local user is not logged onto the IM service. True means that you want the logon prompt to be displayed.
ShowSelectAlways This Boolean specifies whether to show the selection in the list even if the control does not have focus. True means that even if the user is typing into a form in a separate part of your application window, the current contact selection in the control will remain highlighted.

Table 19-16. IM Contact View Control methods and functions.

Method NameDescription
Add Adds a list of contacts by using each contact's list ID. For MSN Messenger contacts, this would be $$Messenger\Contact. You can specify your own custom list here as well. You can also add contacts using a contact's IM address such as username@imaddress.com. Finally, you can add a number of contacts by passing a Variant array of strings that represent the IM addresses of all the contacts you want to add.
AddMenuItem This function adds a menu item to the context menu that is displayed when contacts are right-clicked. (This method is covered in more detail in the programming samples at the end of this chapter.)
BlockSelected Adds the selected contacts in the UI to the blocked list. These contacts will no longer be able to send instant messages to the user.
EmailSelected Initiates an e-mail message to the selected contacts in the UI.
IMSelected Sends an IM message to the selected contacts in the UI.
InviteSelected Initiates an invitation to the selected contacts in the UI to join an application.
Remove Removes a list or contact from the IM list. You need to pass the address of the IM user or name of the list as a parameter.
UnblockSelected Removes the selected contacts in the UI from the blocked list.

click to view at full size.

Figure 19-19. Adding a custom menu option for your application to the IM Contact View control.

Table 19-17 highlights the events you can receive from the IM Contact View control.

Table 19-17. Events for the IM Contacts View control.

Event NameDescription
OnAddContactUI This event is called when a user attempts to add a new contact using the Messenger Add Contact User Interface. The user can add a new contact by right-clicking on a node and selecting Add Contact. You are passed a Boolean variable pfEnableDefault which, if you set it to False, cancels the user's action and prevents the user interface for adding a contact from appearing.
OnAddResult This event is called when a contact or list has been added or an attempt has been made to add it. You are passed a Long value named lResult, which is the result of the attempt, as well as a Variant named vUser. This Variant holds either the list or contact that were added.
OnEmailContact This event indicates that e-mail is being sent to the selected contacts. You are passed a Variant named vUser, which is the contact or contacts. You are also passed pfEnableDefault, which you can set to False to cancel the action.
OnExtentsChange This event is called when the size of the list has changed. You are passed two Long values, nWidth and nHeight, which indicate the new width and height.
OnLocalStateChange This event is called when the user changes the IM local state. This state can be online, offline, out to lunch, and so on. You are passed a variable vState, which is an Integer that identifies the new state.
OnLogOff This event is called when the user logs off an IM service. You are passed a variable lResult, which is the result of the logoff attempt, and also a string bstrService, which is the service the user is logging off of, whether it be MSN or Exchange Instant Messaging.
OnLogon This event is called when a user logs on to an IM service. You are passed a Long value, lResult, which is the result of the logon attempt, usually 0 for successful. You are also passed a string called bstrService, which is the service the user logged on to.
OnMenuRequest This event indicates that a context menu is about to be displayed. We'll cover this event in more detail when we drill down into the Training application.
OnMenuSelect This event indicates that a context menu item has been selected. We'll look at this event in more detail when we look at the Training application.
OnNewIMSession This event is called when the user receives a request for an IM session from another user. You are passed a Variant, vUser, which is the user attempting to initiate the new session, as well as a Boolean, pfEnableDefault, which you can set to False to prevent the session from being initiated.
OnReady This event is called when the IM control is initialized and ready.
OnRemoveResult This event is called when a contact or list is removed. You are passed lResult, which is the result of the removal, and vUser, which is the contact or list that was removed.
OnSelect This event fires when a contact on the IM list is selected. The variable vUser is passed to indicate who was selected.
OnShutdown This event fires when the control is shutting down.

One issue to note about the events is that a bunch of them are passed a vUser variable. This variable actually corresponds to an IMContact object. The IMContact object has some properties that are very useful, such as FriendlyName, EmailAddress, LogonName, and State. You can guess by their names what they mean: FriendlyName is the friendly name of the user in the control, EmailAddress is the e-mail address, LogonName is the logon name, and State returns a number that indicates the user's state. For State, the most common states and values are: online(2), busy(10), idle(18), and away(34).

Putting It All Together

Now that I've provided some information on the IM Contacts View control, we can look at the Training application implementation of the control. I'm going to highlight certain code sections of the implementation to kick-start your development efforts with the IM Contacts View control.

Getting Contacts into the List Programmatically

To figure out who the instructors are and get them into the list, the application uses ASP code on the server side to query the instructors folder and retrieve the entire list of instructors. The code then figures out which instructors are teaching classes that the current student is taking or has completed. Both sets of lists are stored in ASP session variables so that this query does not have to occur on every load of the page. The list is streamed out to the Web browser as two local VBScript arrays, one called arrInstructorsIM and the other called arrMyInstructorsIM. I stream them into an array is so that I can pass the array to the Add method of the control and add all the instructors at once.

The addition is performed only if the user is logged onto an IM service and after the IM control has initialized. We can check both requirements programmatically by first checking the LoggedOn property for a True value. To make sure that I am attempting to add contacts only after the control has successfully initialized, the code listens for the OnReady event. Once both of these conditions have been satisfied, the code programmatically adds either all instructors or only my instructors to the control, depending on what I check in the check box for the application. The code that performs these steps is shown here:

 <SCRIPT LANGUAGE="vbscript"> <% 'Check the session variables to see if the array of instructor contacts 'is available 'By using session variables, the IM contacts will refresh 'only after a new session starts. If you want to refresh 'every time the user hits the page, remove the session 'variables. 'There are two arrays, one for all instructors 'and one for just this user's instructors if IsEmpty(Session("arrInstructorsIM")) then dim arrInstructorsIM() i=0 'Query the store for the list of available instructors strQuery = "Select ""urn:schemas:contacts:email1"" FROM " & _ "scope('shallow traversal of " & chr(34) _ & strInstructorsFolderPath & chr(34) & "') WHERE " & _ """DAV:ishidden"" = false" _ & " AND ""DAV:iscollection"" = false" set oRS = Server.CreateObject("ADODB.Recordset") oRS.Open strQuery,Session("oConnection") Do Until oRS.EOF 'Fill in the array with this info Redim Preserve arrInstructorsIM(i) arrInstructorsIM(i) = _ oRS.Fields("urn:schemas:contacts:email1").Value i=i+1 oRS.MoveNext Loop oRS.Close set oRS = Nothing on error resume next err.clear 'Check UBound iThrowAway = UBound(arrInstructorsIM) if err.number = 0 then %> on error resume next dim arrInstructorsIM(<%=UBound(arrInstructorsIM)%>) <% for y=LBound(arrInstructorsIM) to UBound(arrInstructorsIM) response.write vblf & "arrInstructorsIM(" & y & ") = """ & _ arrInstructorsIM(y) & """" next else arrInstructorsIM="" %> arrInstructorsIM="" <% end if if err.number = 0 then 'Save the local array into the Session variable Session("arrInstructorsIM") = arrInstructorsIM else Session("arrInstructorsIM") = "" end if else 'Traverse the list of available instructors and store them 'in local VBScript vars arrInstructorsIM = Session("arrInstructorsIM") on error resume next err.clear 'Check UBound iThrowAway = UBound(arrInstructorsIM) if err.number = 0 then %> on error resume next dim arrInstructorsIM(<%=UBound(arrInstructorsIM)%>) <% for y=LBound(arrInstructorsIM) to UBound(arrInstructorsIM) response.write vblf & "arrInstructorsIM(" & y & ") = """ & _ arrInstructorsIM(y) & """" next else %> arrInstructorsIM = "" <% end if end if if IsEmpty(Session("arrMyInstructorsIM")) then dim arrMyInstructorsIM() 'Query the store for the list of my instructors. 'Do this by querying the store for the courses 'the user is registered for, and then pull off the instructor 'e-mail. This shows all courses, both past and present. 'You could also limit this to current courses only. strUserEmail = Session("UserEmail") strQuery = "Select """ & strSchema & "registrations""," & _ """DAV:href"" FROM scope('shallow traversal of " & chr(34) _ & strStudentsFolderPath & chr(34) & "') " & _ "WHERE ""DAV:ishidden"" = false" _ & " AND ""DAV:iscollection"" = false AND " _ & ""urn:schemas:contacts:email1""" _ & "='" & strUserEmail & "'" set oRS = Server.CreateObject("ADODB.Recordset") oRS.Open strQuery,Session("oConnection") if oRS.RecordCount <> 0 then 'Actually has a student record strRegistrations = oRS.Fields(strSchema & "registrations") 'on error resume next if Not(IsNull(strRegistrations)) then arrRegistrations = Split(strRegistrations,",") strSQL = "Select """ & strSchema & "instructoremail"", " & _ """urn:schemas:mailheader:subject""," _ & """DAV:href"",""urn:schemas:calendar:dtstart""," & _ """urn:schemas:calendar:dtend"" " & _ "FROM scope('shallow traversal of """ & _ strScheduleFolderPath & _ """') WHERE (""DAV:iscollection"" = false) AND " & _ (""DAV:ishidden"" = false)" set rst = Server.CreateObject("ADODB.Recordset") With rst 'Open recordset based on the SQL string .Open strSQL, Session("oConnection") End With y=-1 If Not(rst.BOF And rst.EOF) Then rst.MoveFirst Do Until rst.EOF for i = LBound(arrRegistrations) to UBound(arrRegistrations) 'Print out the course if UCASE(rst.fields("DAV:href").Value) = _ UCASE((strScheduleFolderPath & _ arrRegistrations(i))) then 'Found a course the user is registered for 'Add it to an array y=y+1 Redim Preserve arrMyInstructorsIM(y) arrMyInstructorsIM(y) = _ rst.Fields(strSchema & "instructoremail").Value end if next rst.MoveNext loop rst.Close set rst=Nothing end if end if on error resume next err.clear 'Check UBound iThrowAway = UBound(arrMyInstructorsIM) if err.number = 0 then %> on error resume next dim arrMyInstructorsIM(<%=UBound(arrMyInstructorsIM)%>) <% for y=LBound(arrMyInstructorsIM) to UBound(arrMyInstructorsIM) response.write vblf & "arrMyInstructorsIM(" & y & ") = " & _ """" & arrMyInstructorsIM(y) & """" next else %> <% end if if err.number = 0 then 'Save the local array into the Session variable Session("arrMyInstructorsIM") = arrMyInstructorsIM else Session("arrMyInstructorsIM") = "" end if end if else 'Traverse the list of my instructors and store them 'in local VBScript vars arrMyInstructorsIM = Session("arrMyInstructorsIM") on error resume next err.clear 'Check UBound iThrowAway = UBound(arrMyInstructorsIM) if err.number = 0 then %> dim arrMyInstructorsIM(<%=UBound(arrMyInstructorsIM)%>) <% for y=LBound(arrMyInstructorsIM) to UBound(arrMyInstructorsIM) response.write vblf & "arrMyInstructorsIM(" & y & ") = """ & _ arrMyInstructorsIM(y) & """" next else %> arrMyInstructorsIM = "" <% end if end if %> SUB MSIMContactList_OnReady() 'Only display if available if MSIMContactList.LoggedOn = True then document.all.IMSection.style.display = "" end if settimeout "AddIMContacts",1000,"vbscript" end sub SUB MSIMContactList_OnLogOn(BYVAL lResult, BYVAL bstrService) document.all.IMSection.style.display = "" settimeout "AddIMContacts",1000,"vbscript" End SUB SUB MSIMContactList_OnLogOff() document.all.IMSection.style.display = "none" End SUB SUB EvaluateCheckbox() if document.all.myinstructors.checked = True then AddMyIMContacts else AddIMContacts end if End Sub SUB AddIMContacts() 'Adds all instructors 'Check to see if the user is logged on if MSIMContactList.LoggedOn = True then err.clear 'Clear the list Randomize lRandomNumber = Int((30000 * Rnd)+1) MSIMContactList.List = CStr(lRandomNumber) if IsArray(arrInstructorsIM) then AddSelectedContact(arrInstructorsIM) end if end if end sub      SUB AddMyIMContacts() 'Adds only my instructors on error resume next err.clear if MSIMContactList.LoggedOn = True then 'Clear the list Randomize lRandomNumber = Int((30000 * Rnd)+1) MSIMContactList.List = CStr(lRandomNumber) if IsArray(arrMyInstructorsIM) then AddSelectedContact(arrMyInstructorsIM) end if end if end sub sub AddSelectedContact(vUserAddress) MSIMContactList.Add vUserAddress if err.number <> 0 then msgbox "Add Contact: An error occured: " + err.number + ": " + err.description err.clear end if end sub 

Adding Dynamic Menu Items

The other task the Training application performs is dynamically adding a menu item to the context menu of the control. This menu item, as we saw, allows users to display instructor details as a menu option. The way to implement this functionality is to leverage the OnMenuRequest and OnMenuSelect events.

The OnMenuRequest event is fired when a user requests a context menu from the control. This event passes you a variable vSelected, which is the currently selected user in the control for which the menu was requested. Using this variable, you can decide whether you want the menu to appear. The instatiation of the menu is controlled by the next variable pfDefaults, which you can set to False if you do not want the menu to appear.

Inside of your event handler for the OnMenuRequest event, you can use the AddMenuItem function to add custom menu items. The AddMenuItem function takes a string that specifies the name of the menu for the new item. If you send an empty string, the control creates a new divider. This function also takes a Long value, which is the index of the location in the menu where you want the new item to appear. If you do not specify this location, the new menu item appears at the bottom of the menu list. Finally, this function will return to you a Long value that is a unique identifier for your menu item. You should retain this value so that you can use it with the next event we're going to cover, OnMenuSelect.

The OnMenuSelect event fires when a user selects a menu item from a context menu. This event passes you a vSelected variable, which is the user object of the currently selected user. This method also passes you a Long value, lCmd, which identifies which menu item was selected. If you saved the value returned from AddMenuItem, you can compare the identifier passed by OnMenuSelect with the custom menu indentifier you saved. If they match, you should perform the custom action required by your application. In my case, I get the friendly name of the user. I could have retrieved the e-mail address of the user if I had used the EmailAddress property on the vSelected variable that is passed by the OnMenuSelect event. I then launch a new instance of IE to an ASP page I created and pass the friendly name of the selected contact to that ASP page. The ASP page finds and displays the details for the selected contact. All the code for this scenario is shown here:

 SUB MSIMContactList_OnMenuRequest(BYVAL vSelected, BYREF pfDefaults) throwaway = MSIMContactList.AddMenuItem("") DetailsCmd = MSIMContactList.AddMenuItem("View Instructor Details") End Sub Sub MSIMContactList_OnMenuSelect(BYVAL vSelected, BYVAL lCmd) If lcmd = DetailsCmd then on error resume next err.clear 'Try to grab the friendly name; if an error, then 'not a valid selection strFriendlyName = vSelected.FriendlyName 'Could also be strEmail = vSelected.EmailAddress if err.number = 0 then 'Open a new window to show instructor details window.open "iminstructordetail.asp?InstructorName=" & _ vSelected.FriendlyName,null, _ "location=false,menubar=false,toolbar=false" end if end if 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