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