[cisco-voip] custom directories in CM 6.1
Truelove_John
JTruelove at aetinc.com
Tue Nov 18 16:09:33 EST 2008
We have three locations. Location #3 needs a 91 for LD dialing. Cut and paste in new document.
*****************************************************************
<%@ Language=JavaScript %>
<%
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Title: MultiDirectory
// Author: kstearns
// Source File(s): multidirectory.asp
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Description:
//
// Sample Javascript/ASP page using the LDAPSearch COM server to query
// against multiple LDAP directories and consolidate the response.
// The primary use of this app would be for LDAP searches across multiple CallManager clusters
// or any installation where a single, consolidated LDAP directory does not exist.
//
// Each directory defined can also have a unique string of digits prepended to the number.
// This can reduce the amount of EditDial'ing that must be done by prepending digits such as
// 9, 1, or an area code for dialing remote locations.
//
// This app was designed to be used in place of the standard Directories URL such that this
// app is called whenever the user presses the Directories button. However, it can also be
// configured as a regular IP Phone Service and accessed from the Services button.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Requirements and Caveats:
//
// - Client: Cisco IP Phone XML browser
//
// - Required COM Servers: Cisco LDAPSearch, Microsoft XML (MSXML) 3.0 or later
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
function appendSoftKey(object, name, position, uri) {
var softKey = object.createElement("SoftKeyItem");
var nameObj = object.createElement("Name");
nameObj.text = name;
var posObj = object.createElement("Position");
posObj.text = position;
var uriObj = object.createElement("URL");
uriObj.text = uri;
softKey.appendChild(nameObj);
softKey.appendChild(posObj);
softKey.appendChild(uriObj);
dirRoot = object.selectSingleNode("//CiscoIPPhoneDirectory");
dirRoot.appendChild(softKey);
}
function Directory(name_in, server_in, searchbase_in, port_in, userId_in, password_in, prependDigits_in) {
this.name = name_in;
this.server = server_in;
this.searchbase = searchbase_in;
this.port = port_in;
this.userId = userId_in;
this.password = password_in;
this.prependDigits = prependDigits_in;
}
//////////////////////////////////////////////////////////
//
// Edit the following settings for your environment.
// This is for sample purposes only - placing passwords and other
// sensitive information in an open text file is typically NOT recommended !!!
//
//////////////////////////////////////////////////////////
var ALL_DIRECTORIES_PHRASE = "All Directory Search";
var ALLOW_ALL_USERS_SEARCH = false;
var MAX_LIST_SIZE = 32; // Max number of users per page
// Define directories below - you can use any number of directories,
// just make sure to start with index 0 and keep them consecutive.
// Syntax: new Directory(<DisplayName>, <LdapServer>, <LdapSearchBase>, <LdapPort>, <LdapUserId>, <LdapPassword>, <PrependDigits>);
var dirs = new Array();
dirs[0] = new Directory("Site #1", "IP or host name of LDAP Server", "LDAP search string example", "3268", "LDAP Read account", "password", "");
dirs[1] = new Directory("Site #2", "IP or host name of LDAP Server", "ou=Site1 Users,ou=Site 1,ou=DOMAIN,dc=DOMAIN,dc=net", "3268", "LDAP Read account", "password", "");
dirs[2] = new Directory("Site #3", "IP or host name of LDAP Server", "LDAP search string", "3268", "LDAP Read account", "password", "91");
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
Response.ContentType = "text/xml";
Response.Expires = -1;
var thisPage = "http://" + Request.ServerVariables("SERVER_NAME") + Request.ServerVariables("PATH_INFO");
var action = String(Request.QueryString("action").Item);
var dirId = Number(Request.QueryString("id").Item);
/////////////////////////////////////////////////////////
// Directory Main Menu
/////////////////////////////////////////////////////////
if (action == "undefined" || action == "directory") {
// Return the Directory Main Menu with the proper URL linking to Search Input
Response.Write("<CiscoIPPhoneMenu><Title>DIRECTORY</Title>");
Response.Write("<MenuItem><Name>" + ALL_DIRECTORIES_PHRASE + "</Name>");
Response.Write("<URL>" + thisPage + "?action=search&id=-1" + "</URL></MenuItem>");
for (var i=0; i < dirs.length; i++) {
Response.Write("<MenuItem><Name>" + dirs[i].name + "</Name>");
Response.Write("<URL>" + thisPage + "?action=search&id=" + i + "</URL></MenuItem>");
}
Response.Write("</CiscoIPPhoneMenu>");
Session("dirXml") = null; // New search initiated, so clear previous cached result
}
/////////////////////////////////////////////////////////
// Directory Search Input
/////////////////////////////////////////////////////////
if (action == "search") {
Session("dirXml") = null; // New search initiated, so clear previous cached result
// Return the Search Input object with the proper URL linking to a Directory Listing
Response.Write("<CiscoIPPhoneInput><Title>");
Response.Write( (dirId == -1) ? ALL_DIRECTORIES_PHRASE : dirs[dirId].name );
Response.Write("</Title><Prompt>Enter search criteria</Prompt>");
Response.Write("<URL>" + thisPage + "?action=list&id=" + dirId + "</URL>");
Response.Write("<InputItem><DisplayName>Last Name</DisplayName>");
Response.Write("<QueryStringParam>l</QueryStringParam><InputFlags>A</InputFlags>");
Response.Write("<DefaultValue></DefaultValue></InputItem>");
Response.Write("<InputItem><DisplayName>First Name</DisplayName>");
Response.Write("<QueryStringParam>f</QueryStringParam><InputFlags>A</InputFlags>");
Response.Write("<DefaultValue></DefaultValue></InputItem>");
Response.Write("<InputItem><DisplayName>Number</DisplayName>");
Response.Write("<QueryStringParam>n</QueryStringParam><InputFlags>T</InputFlags>");
Response.Write("<DefaultValue></DefaultValue></InputItem></CiscoIPPhoneInput>");
}
////////////////////////////////////////////////////////
// Directory Listing
///////////////////////////////////////////////////////
if (action == "list") {
var last = String(Request.QueryString("l"));
var first = String(Request.QueryString("f"));
var start = String(Request.QueryString("start"));
var telephoneNumber = String(Request.QueryString("n"));
if (start == "undefined"){start = 1;}else{start = Number(start);}
if (last == "undefined"){last = "";}
if (first == "undefined"){first = "";}
// If empty search criteria is not allowed, redirect back to search input
if (last == "" && first == "" && telephoneNumber == "undefined" && !ALLOW_ALL_USERS_SEARCH) {
Response.Redirect(thisPage + "?action=search&id=" + dirId);
}
var querystring = (telephoneNumber == "undefined") ?
"l=" + last + "&f=" + first :
"n=" + telephoneNumber;
var tempDoc = new ActiveXObject("Msxml2.DOMDocument");
if (!Session("dirXml")) {
// The search hasn't been performed yet, so do the search and cache the result
var s = new ActiveXObject("LDAPSearch.LDAPSearchList");
var dirArray = new Array();
// Search each Directory and cache the resulting XML string
for (var i=0; i < dirs.length; i++) {
dirArray[i] = null;
if (i == dirId || dirId == -1) {
var s = new ActiveXObject("LDAPSearch.LDAPSearchList");
s.server = dirs[i].server;
s.searchbase = dirs[i].searchbase;
s.port = dirs[i].port;
s.AuthName = dirs[i].userId;
s.AuthPasswd = dirs[i].password;
s.AddReturnAttr("givenName, sn", "Name", "%2, %1", 31);
s.AddReturnAttr("telephoneNumber", "Telephone", "%1", 31);
if (telephoneNumber == "undefined") {
s.AddSortingAttr("sn, givenName, telephoneNumber", 1);
s.SearchByName(last + "*", first + "*");
}
else {
s.AddSortingAttr("telephoneNumber, sn, givenName", 1);
s.SearchByPhoneNumber("*" + telephoneNumber + "*");
}
dirArray[i] = (s.SearchCount > 0) ? s.XMLListOutput(1, s.SearchCount) : null;
}
}
// Next, load the results into an XML document for sorting and caching
var entries, i, j;
var dirDoc = new ActiveXObject("Msxml2.DOMDocument");
// Begin with an empty Directory object
var emptyDir = "<CiscoIPPhoneDirectory><Title>";
emptyDir += (dirId == -1) ? ALL_DIRECTORIES_PHRASE : dirs[dirId].name;
emptyDir += "</Title><Prompt></Prompt></CiscoIPPhoneDirectory>"
dirDoc.loadXML(emptyDir);
// Append all matching DirectoryEntries onto the XML object
var dirRoot = dirDoc.selectSingleNode("//CiscoIPPhoneDirectory");
for (i = 0; i < dirArray.length; i++) {
if (dirArray[i] != null) {
tempDoc.loadXML(dirArray[i]);
entries = tempDoc.selectNodes("//DirectoryEntry");
for (j = 0; j < entries.length; j++) {
// Only add users with a valid telephone number
var number = entries.item(j).selectSingleNode("Telephone");
if (number.text != "") {
// Strip - in phone number, Global Replace
var newNum = number.text.replace(new RegExp( "-", "g" ),"");
number.text = newNum;
// Prepend digits
number.text = dirs[i].prependDigits + number.text;
dirRoot.appendChild(entries.item(j));
}
}
}
}
// Now sort the entries
entries = dirRoot.selectNodes("//DirectoryEntry");
if (entries != null && entries.length > 1) {
var thisNode, nextNode;
var sortComplete = false;
while (!sortComplete) {
sortComplete = true;
entries = dirRoot.selectNodes("//DirectoryEntry");
for (i=0; i < entries.length - 1; i++) {
thisNode = entries.item(i);
nextNode = entries.item(i+1);
var thisName = thisNode.selectSingleNode("Name").firstChild.nodeValue;
var nextName = nextNode.selectSingleNode("Name").firstChild.nodeValue;
if (thisName.toUpperCase() > nextName.toUpperCase()) {
dirRoot.insertBefore(nextNode, thisNode);
sortComplete = false;
}
}
}
}
// Cache the search result XML string
Session("dirXml") = dirDoc.xml;
}
// Load the cached XML Directory into a MSXML document so we can modify it
tempDoc.loadXML(Session("dirXml"));
var dirRoot = tempDoc.selectSingleNode("CiscoIPPhoneDirectory");
var entries = dirRoot.selectNodes("DirectoryEntry");
var listCount = (entries == null) ? 0 : entries.length;
if (listCount == 0) {
Session("dirXml") = null;
Response.Write("<CiscoIPPhoneText>");
Response.Write("<Text>\r\nNo matching entries\r\n\r\nPress 'Search' to refine search criteria</Text>");
Response.Write("<SoftKeyItem><Name>Exit</Name><Position>3</Position><URL>SoftKey:Exit</URL></SoftKeyItem>");
Response.Write("<SoftKeyItem><Name>Search</Name><Position>4</Position>");
Response.Write("<URL>"+thisPage+"?action=search&id=" + dirId + "</URL></SoftKeyItem>");
Response.Write("<Prompt></Prompt></CiscoIPPhoneText>");
Response.End;
}
// Define and initialize count variables
var end = 0;
var currentStart;
var nextUrl = "";
// Get listcount and set currentStart since start changes
currentStart = start;
// Update start if needed
if (listCount >= (start + MAX_LIST_SIZE)){start += MAX_LIST_SIZE;}
// Set end and add header and softkey if more records are available
if (currentStart + MAX_LIST_SIZE - 1 >= listCount ) {
end = listCount;
}
else {
end = start - 1;
nextUrl = thisPage + "?action=list&" + querystring + "&start=" + start;
appendSoftKey(tempDoc, "Next", "4", "SoftKey:Next");
}
// If there are more listings, set the Refresh URL
if (nextUrl != "") {
Response.AddHeader("Refresh", ";url=" + nextUrl);
}
// Remove any DirectoryEntries not on the current page
if (listCount > 0) {
for (var i=end; i < listCount; i++) {
dirRoot.removeChild(entries[i]);
}
for (var i=0; i < currentStart - 1; i++) {
dirRoot.removeChild(entries[i]);
}
}
// Set the Prompt
var prompt = dirRoot.selectSingleNode("Prompt");
if (listCount > 0) {
prompt.text = "Records " + currentStart + " to " + end + " of " + listCount;
}
else {
prompt.text = "No Records Match - refine Search";
}
// Add the SoftKeys
if (listCount > 0) {
// Only show dial commands when the Directory has entries
appendSoftKey(tempDoc, "Dial", "1", "SoftKey:Dial");
appendSoftKey(tempDoc, "EditDial", "2", "SoftKey:EditDial");
}
appendSoftKey(tempDoc, "Exit", "3", "SoftKey:Exit"); // Always show Exit
Response.Write(tempDoc.xml);
}
%>
<%
// THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND BY CISCO,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY
// FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE
// OF DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY REGARDING ITS USAGE IN AN
// APPLICATION., THE APPLICATION IS PROVIDED AS AN EXAMPLE ONLY, THEREFORE CISCO DOES NOT MAKE ANY
// REPRESENTATIONS REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES CISCO
// WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE TO OPERATE THE SOFTWARE WITHOUT
// PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE
// SOFTWARE IS USED WILL BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS
// NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY ARISING FROM THE USE OF THE
// APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR
// CONSEQUENTIAL DAMAGES, LOST PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS
// SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.
%>
***************************************************************
End
John
-----Original Message-----
From: Robert Kulagowski [mailto:rkulagow at gmail.com]
Sent: Tuesday, November 18, 2008 3:56 PM
To: Truelove_John
Cc: cisco-voip at puck.nether.net
Subject: Re: [cisco-voip] custom directories in CM 6.1
Truelove_John wrote:
> I can send you a copy of my changes.
>
> Could save you some time.
>
>
>
> Changed Last Name to top of search, removed - in phones before dialing
> (it caused problems).
>
> Let me know if you want a copy.
Sounds good, but posting it to the list would be better, since I'm sure
it will come up again and again.
More information about the cisco-voip
mailing list