[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&amp;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&amp;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&amp;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&amp;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