r3312 - in trunk/libmnetutil: . include include/libmnetutil source

mikaelsv at minisip.org mikaelsv at minisip.org
Wed Jun 13 20:12:10 CEST 2007


Author: mikaelsv
Date: 2007-06-13 20:12:09 +0200 (Wed, 13 Jun 2007)
New Revision: 3312

Added:
   trunk/libmnetutil/include/libmnetutil/LdapUrl.h
   trunk/libmnetutil/source/LdapUrl.cxx
Modified:
   trunk/libmnetutil/Makefile.am
   trunk/libmnetutil/include/Makefile.am
Log:

 * Added class for parsing and creating LDAP URLs



Modified: trunk/libmnetutil/Makefile.am
===================================================================
--- trunk/libmnetutil/Makefile.am	2007-06-13 17:47:42 UTC (rev 3311)
+++ trunk/libmnetutil/Makefile.am	2007-06-13 18:12:09 UTC (rev 3312)
@@ -37,7 +37,8 @@
 ldap_src += \
 		    source/LdapConnection.cxx \
                     source/LdapEntry.cxx \
-                    source/LdapException.cxx
+                    source/LdapException.cxx \
+		    source/LdapUrl.cxx
 endif
 
 mnetutil_src = \

Modified: trunk/libmnetutil/include/Makefile.am
===================================================================
--- trunk/libmnetutil/include/Makefile.am	2007-06-13 17:47:42 UTC (rev 3311)
+++ trunk/libmnetutil/include/Makefile.am	2007-06-13 18:12:09 UTC (rev 3312)
@@ -5,7 +5,8 @@
 			libmnetutil/LdapCredentials.h \
 			libmnetutil/LdapDirectoryLocator.h \
 			libmnetutil/LdapEntry.h \
-			libmnetutil/LdapException.h
+			libmnetutil/LdapException.h \
+			libmnetutil/LdapUrl.h
 endif
 
 pkginclude_HEADERS =    \

Added: trunk/libmnetutil/include/libmnetutil/LdapUrl.h
===================================================================
--- trunk/libmnetutil/include/libmnetutil/LdapUrl.h	                        (rev 0)
+++ trunk/libmnetutil/include/libmnetutil/LdapUrl.h	2007-06-13 18:12:09 UTC (rev 3312)
@@ -0,0 +1,126 @@
+/*
+  Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _LDAPURL_H_
+#define _LDAPURL_H_
+
+#include<libmnetutil/libmnetutil_config.h>
+
+#include <string>
+#include <vector>
+
+class LdapUrlExtension {
+	public:
+		LdapUrlExtension(std::string type, std::string value, bool critical) : type(type), value(value), critical(critical) {}
+
+		bool critical;
+		std::string type;
+		std::string value;
+};
+/**
+ * Conforms to the LDAP URL specification (RFC 4516) with the following exceptions:
+ *  - Does not handle case-insensitive URL parts correctly (requires lower-cased reserved words)
+ *  - b
+ *  - c
+ *  - d
+ *
+ * For details about the specification one should read http://tools.ietf.org/html/rfc4516.
+ *
+ * Other fancy notes:
+ *  - There is not setExtension method
+ *
+ * @author	Mikael Svensson
+ */
+class LdapUrl {
+	public:
+		LdapUrl(std::string url);
+		LdapUrl();
+
+		/** Restore URL parts to their default values */
+		void clear();
+		bool isValid();
+
+		/** Parse URL */
+		void setUrl(const std::string url);
+
+		/** Get string representation of URL, e.g. the actual URL */
+		std::string getString() const;
+
+		/** Prints all information about the URL */
+		void printDebug();
+
+		/* Getters and setters */
+		std::string getHost() const;
+		void setHost(std::string host_);
+
+		int32_t getPort() const;
+		void setPort(int32_t);
+
+		std::vector<std::string> getAttributes() const;
+		void setAttributes(std::vector<std::string>);
+
+		std::vector<LdapUrlExtension> getExtensions() const;
+		bool hasCriticalExtension() const;
+
+		std::string getFilter() const;
+		void setFilter(std::string);
+
+		std::string getDn() const;
+		void setDn(std::string);
+
+		int32_t getScope() const;
+		void setScope(int32_t);
+	private:
+		std::string			host;
+		int32_t 			port;
+		std::vector<std::string> 	attributes;
+		std::vector<LdapUrlExtension> 	extensions;
+		std::string 			filter;
+		std::string 			dn;
+		int32_t				scope;
+
+		/**
+		 * Unreserved Characters according to RFC 3986 (section 2.3).
+		 *
+		 * Characters that are allowed in a URI but do not have a reserved
+		 * purpose are called unreserved.  These include uppercase and lowercase
+		 * letters, decimal digits, hyphen, period, underscore, and tilde.
+		 */
+		bool isUnreservedChar(char in) const;
+
+		/**
+		 * Reserved Charachters according to RFC 3986 (section 2.2).
+		 *
+		 * URIs include components and subcomponents that are delimited by
+		 * characters in the "reserved" set.  These characters are called
+		 * "reserved" because they may (or may not) be defined as delimiters by
+		 * the generic syntax, by each scheme-specific syntax, or by the
+		 * implementation-specific syntax of a URI's dereferencing algorithm.
+		 */
+		bool isReservedChar(char in) const;
+
+		std::string encodeChar(const char in) const;
+		char decodeChar(const std::string in) const;
+		int32_t charToNum(const char in) const;
+
+		std::string percentDecode(const std::string & in) const;
+		std::string percentEncode(const std::string & in, bool escapeComma, bool escapeQuestionmark = true) const;
+
+		bool validUrl;
+};
+#endif

Added: trunk/libmnetutil/source/LdapUrl.cxx
===================================================================
--- trunk/libmnetutil/source/LdapUrl.cxx	                        (rev 0)
+++ trunk/libmnetutil/source/LdapUrl.cxx	2007-06-13 18:12:09 UTC (rev 3312)
@@ -0,0 +1,248 @@
+#include <libmnetutil/LdapUrl.h>
+
+#include <iostream>
+#include <libmutil/stringutils.h>
+#include <ldap.h>
+
+LdapUrl::LdapUrl(std::string url) {
+	clear();
+	setUrl(url);
+}
+
+LdapUrl::LdapUrl() {
+	clear();
+}
+
+void LdapUrl::clear() {
+	host = "";
+	port = LDAP_PORT;
+	filter = "(objectClass=*)";
+	dn = "";
+	scope = LDAP_SCOPE_BASE;
+	validUrl = false;
+	attributes = std::vector<std::string>();
+	extensions = std::vector<LdapUrlExtension>();
+}
+std::string LdapUrl::getString() const {
+
+	std::string url("ldap://");
+	url += host;
+	if (port > 0) {
+		url += ':';
+		url += itoa(port);
+	}
+	url += '/';
+	url += percentEncode(dn, false, true);
+	url += '?';
+	if (attributes.size() > 0) {
+		for (int i=0; i<attributes.size(); i++) {
+			if (i>0)
+				url += ',';
+			url += percentEncode(attributes.at(i), false, true);
+		}
+	}
+	url += '?';
+	url += (scope == LDAP_SCOPE_BASE ? "base" : (scope == LDAP_SCOPE_SUBTREE ? "sub" : "one"));
+	url += '?';
+	if (filter.length() > 0) {
+		url += filter;
+	}
+	if (extensions.size() > 0) {
+		url += '?';
+		for (int i=0; i<extensions.size(); i++) {
+			if (i>0)
+				url += ',';
+
+			LdapUrlExtension ext = extensions.at(i);
+			if (ext.critical)
+				url += '!';
+			url += percentEncode(ext.type, false, true);
+			url += '=';
+			url += percentEncode(ext.value, true, true);
+		}
+	}
+
+	return url;
+}
+bool LdapUrl::isUnreservedChar(char in) const {
+	char* alphabetUnreserved = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
+	for (int i=0; i<66; i++) {
+		if (alphabetUnreserved[i] == in)
+			return true;
+	}
+	return false;
+}
+
+bool LdapUrl::isReservedChar(char in) const {
+	char* alphabetReserved = ":/?#[]@!$&'()*+,;=";
+	for (int i=0; i<18; i++) {
+		if (alphabetReserved[i] == in)
+			return true;
+	}
+	return false;
+}
+/*
+      ldapurl     = scheme COLON SLASH SLASH [host [COLON port]]
+                       [SLASH dn [QUESTION [attributes]
+                       [QUESTION [scope] [QUESTION [filter]
+                       [QUESTION extensions]]]]]
+*/
+void LdapUrl::setUrl(const std::string url) {
+	std::string::size_type lastPos = 0, pos = 0, posTemp = 0;
+
+	if (strCaseCmp(url.substr(0, 7).c_str(), "ldap://") == 0) {
+		lastPos = 7;
+
+		/**************************************************************
+		 * Search for host and port
+		 */
+
+		pos = url.find('/', lastPos);
+
+		// lastPos = <first char after schema specifier>, pos = <first "/" after schema specifier>
+
+		if (pos == std::string::npos) {
+			// No slash after schema specifier. This means that the URL at most specified a host and a port.
+			pos = url.length();
+			//lastPos = pos;
+		}
+		if (pos != lastPos) {
+			// Host or port found
+			posTemp = url.find(':', lastPos);
+			if (posTemp != std::string::npos && posTemp < pos) {
+				// Port found
+				host = url.substr(lastPos, posTemp - lastPos);
+				port = atoi(url.substr(posTemp+1).c_str());
+			} else {
+				host = url.substr(lastPos, pos - lastPos);
+			}
+		}
+		lastPos = pos+1;
+
+		if (lastPos < url.length()) {
+			std::string restOfUrl = url.substr(lastPos);
+			//std::cerr << restOfUrl;
+
+			std::vector<std::string> parts = split(restOfUrl, false, '?', true);
+
+			switch (parts.size()) {
+				case 5: {
+					std::vector<std::string> exts = split(parts.at(4), false, ',', true);
+					for (int i=0; i<exts.size(); i++) {
+						std::string ext = exts.at(i);
+						std::string::size_type colonPos = ext.find('=', 0);
+						bool critical = (ext[0] == '!');
+						int criticalOffset = (critical ? 1 : 0);
+						if (colonPos != std::string::npos) {
+							extensions.push_back(LdapUrlExtension(percentDecode(ext.substr(criticalOffset,colonPos-criticalOffset)),percentDecode(ext.substr(colonPos+1)), critical));
+						} else {
+							extensions.push_back(LdapUrlExtension(percentDecode(ext.substr(criticalOffset)),"", critical));
+						}
+					}
+				}
+				case 4:
+					filter = parts.at(3);
+				case 3:
+					if (0 == strCaseCmp(parts.at(2).c_str(), "one")) {
+						scope = LDAP_SCOPE_ONELEVEL;
+					} else if (0 == strCaseCmp(parts.at(2).c_str(), "base")) {
+						scope = LDAP_SCOPE_BASE;
+					} else if (0 == strCaseCmp(parts.at(2).c_str(), "sub")) {
+						scope = LDAP_SCOPE_SUBTREE;
+					} else {
+						validUrl = false;
+					}
+
+				case 2:
+					attributes = split(parts.at(1), false, ',', true);
+					for (int i=0; i<attributes.size(); i++) {
+						attributes.at(i) = percentDecode(attributes.at(i));
+					}
+				case 1:
+					dn = percentDecode(parts.at(0));
+			}
+		}
+		validUrl = true;
+	} else {
+		validUrl = false;
+	}
+}
+void LdapUrl::printDebug() {
+
+	std::cerr <<  "     VALID?      " << (validUrl ? "yes" : "NO") << std::endl;
+
+	std::cerr <<  "     Host:       [" << host << "]" << std::endl;
+
+	std::cerr <<  "     Port:       [" << port << "]" << std::endl;
+
+	std::cerr <<  "     Attributes: " << std::endl;
+	for (int i=0; i<attributes.size(); i++)
+		std::cerr <<  "                 [" << attributes.at(i) << "]" << std::endl;
+
+	std::cerr <<  "     Extensions: " << std::endl;
+	for (int i=0; i<extensions.size(); i++)
+		std::cerr <<  "                 [" << extensions.at(i).type << "=" << extensions.at(i).value << "]" << (extensions.at(i).critical ? " (critical!)" : "") << std::endl;
+
+	std::cerr <<  "     Filter:     [" << filter << "]" << std::endl;
+
+	std::cerr <<  "     DN:         [" << dn << "]" << std::endl;
+
+	std::cerr <<  "     Scope:      [" << (scope == LDAP_SCOPE_BASE ? "base" : (scope == LDAP_SCOPE_ONELEVEL ? "one" : "sub")) << "]" << std::endl;
+}
+
+bool LdapUrl::hasCriticalExtension() const {
+	for (int i=0; i<extensions.size(); i++)
+		if (extensions.at(i).critical)
+			return true;
+	return false;
+}
+
+std::string LdapUrl::encodeChar(const char in) const {
+	std::string res;
+	res += '%';
+	if (in < 10)
+		res +='0';
+	res += binToHex(reinterpret_cast<const unsigned char*>(&in), sizeof(in));
+	return res;
+}
+char LdapUrl::decodeChar(const std::string in) const {
+	if (in.length() == 3) {
+		return (charToNum(in[1]) << 4) + (charToNum(in[2]));
+	} else {
+		return '0';
+	}
+}
+
+int32_t LdapUrl::charToNum(const char in) const {
+	if (in >= '0' && in <= '9') {
+		return (in - '0');
+	} else if (in >= 'A' && in <= 'F') {
+		return (in - 'A' + 10);
+	} else if (in >= 'a' && in <= 'f') {
+		return (in - 'a' + 10);
+	} else {
+		return -1;
+	}
+}
+
+std::string LdapUrl::percentEncode(const std::string & in, bool escapeComma, bool escapeQuestionmark) const {
+	std::string res;
+	for (int i=0; i < in.length(); i++) {
+		if ((!isReservedChar(in[i]) && !isUnreservedChar(in[i])) || (escapeQuestionmark && in[i] == '?') || (escapeComma && in[i] == ','))
+			res += encodeChar(in[i]);
+		else
+			res += in[i];
+	}
+	return res;
+}
+std::string LdapUrl::percentDecode(const std::string & in) const {
+	std::string res;
+	for (int i=0; i < in.length(); i++) {
+		if ('%' == in[i]) {
+			res += decodeChar(in.substr(i, 3));
+			i+=2;
+		} else
+			res += in[i];
+	}
+	return res;
+}



More information about the Minisip-devel mailing list