From 006ba8be2e0b8a22849f0f1130965b7387e8e7eb Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 28 Nov 2013 11:00:26 +0100 Subject: [PATCH] Progress commit: basic object structure is here --- configure.ac | 19 +++ coreapi/Makefile.am | 8 +- coreapi/contactprovider.c | 94 ++++++++++-- coreapi/contactprovider.h | 46 +++++- coreapi/ldap/ldapprovider.c | 290 ++++++++++++++++++++++++++++++++++++ coreapi/ldap/ldapprovider.h | 42 ++++++ coreapi/linphonecore.h | 6 +- 7 files changed, 483 insertions(+), 22 deletions(-) create mode 100644 coreapi/ldap/ldapprovider.c create mode 100644 coreapi/ldap/ldapprovider.h diff --git a/configure.ac b/configure.ac index b1a4df656..e7256e06b 100644 --- a/configure.ac +++ b/configure.ac @@ -161,6 +161,24 @@ AC_ARG_ENABLE(x11, [enable_x11=true] ) +dnl conditional build of LDAP support +AC_ARG_ENABLE(ldap, + [AS_HELP_STRING([--disable-ldap], [Disable LDAP support (default=no)])], + [case "${enableval}" in + yes) enable_ldap=true ;; + no) enable_ldap=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-ldap) ;; + esac], + [enable_ldap=true] +) + +AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse) +if test "$enable_ldap" = "true"; then + AC_CHECK_LIB(ldap,ldap_initialize, LDAP_LIBS="-lldap") + AC_SUBST(LDAP_LIBS) + AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled]) +fi + dnl conditionnal build of console interface. AC_ARG_ENABLE(console_ui, [AS_HELP_STRING([--enable-console_ui=[yes/no]], [Turn on or off compilation of console interface (default=yes)])], @@ -854,6 +872,7 @@ printf "* %-30s %s\n" "Tools" $build_tools printf "* %-30s %s\n" "Message storage" $enable_msg_storage printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp printf "* %-30s %s\n" "uPnP support" $build_upnp +printf "* %-30s %s\n" "LDAP support" $enable_ldap if test "$enable_tunnel" = "true" ; then printf "* %-30s %s\n" "Tunnel support" "true" diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index b6ed2ec32..928ffb084 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -48,11 +48,16 @@ liblinphone_la_SOURCES=\ message_storage.c \ info.c \ event.c event.h \ + contactprovider.c contactprovider.h \ $(GITVERSION_FILE) if BUILD_UPNP liblinphone_la_SOURCES+=upnp.c upnp.h endif + +if BUILD_LDAP +liblinphone_la_SOURCES+= ldap/ldapprovider.c ldap/ldapprovider.h +endif liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c bellesip_sal/sal_impl.h \ @@ -89,7 +94,8 @@ liblinphone_la_LIBADD= \ $(TUNNEL_LIBS) \ $(LIBSOUP_LIBS) \ $(SQLITE3_LIBS) \ - $(LIBXML2_LIBS) + $(LIBXML2_LIBS) \ + $(LDAP_LIBS) if ENABLE_TESTS diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index d8e7cb7ee..94ce56beb 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -15,23 +15,85 @@ */ #include "contactprovider.h" +#include -struct linphone_contact_provider { - belle_sip_object_t base; +/* LinphoneContactSearchRequest + */ + +void linphone_contact_search_init(LinphoneContactSearch* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + static unsigned int request_id_counter = 1; + obj->id = request_id_counter++; // unique id + obj->predicate = ms_strdup(predicate?predicate:""); + obj->cb = cb; + obj->data = cb_data; +} + +static void linphone_contact_search_destroy( LinphoneContactSearch* req) { + if( req->predicate ) ms_free(req->predicate); + ms_free(req); +} + +ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj) +{ + return obj->id; +} + +const char*linphone_contact_search_get_predicate(LinphoneContactSearch* obj) +{ + return obj->predicate; +} + +void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends) +{ + if( req->cb ) req->cb(req->id, friends, req->data); +} + +int linphone_contact_search_compare(const void* a, const void* b) { + LinphoneContactSearch *ra=((LinphoneContactSearch*)a); + LinphoneContactSearch *rb=((LinphoneContactSearch*)b); + return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactSearch); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneContactSearch,belle_sip_object_t, + (belle_sip_object_destroy_t)linphone_contact_search_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + +/* + * LinphoneContactProvider + */ + + +void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc){ + obj->lc = lc; +} + +static void contact_provider_destroy(LinphoneContactProvider* obj){ + (void)obj; +} + + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactProvider); +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneContactProvider)= +{ + { + BELLE_SIP_VPTR_INIT(LinphoneContactProvider,belle_sip_object_t,TRUE), + (belle_sip_object_destroy_t) contact_provider_destroy, + NULL,/*no clone*/ + NULL,/*no marshal*/ + }, + "", + // Pure virtual + NULL, /* begin_search -> pure virtual */ + NULL /* cancel_search -> pure virtual */ }; -linphone_contact_provider_t* linphone_contact_provider_create() -{ - linphone_contact_provider_t* obj = belle_sip_object_new(linphone_contact_provider_t); - return obj; -} - -static void linphone_contact_provider_destroy() -{ - -} - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(linphone_contact_provider_t); -BELLE_SIP_INSTANCIATE_VPTR(linphone_contact_provider_t, belle_sip_object_t, - linphone_contact_provider_destroy, NULL, NULL,FALSE); diff --git a/coreapi/contactprovider.h b/coreapi/contactprovider.h index b1a502b21..68c894fbf 100644 --- a/coreapi/contactprovider.h +++ b/coreapi/contactprovider.h @@ -17,10 +17,50 @@ #include #include "linphonecore.h" +/* LinphoneContactSearchRequest */ -typedef struct linphone_contact_provider linphone_contact_provider_t; -#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,linphone_contact_provider_t) +typedef unsigned int ContactSearchID; + +typedef void (*ContactSearchCallback)( ContactSearchID id, MSList* friends, void* data ); + +typedef struct { + ContactSearchID id; + char* predicate; + ContactSearchCallback cb; + void* data; +} LinphoneContactSearch; + +#define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch) +void linphone_contact_search_init(LinphoneContactSearch* obj, const char* predicate, ContactSearchCallback cb, void* cb_data); +ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj); +const char* linphone_contact_search_get_predicate(LinphoneContactSearch* obj); +void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends); -linphone_contact_provider_t* linphone_contact_provider_create(); + +/* LinphoneContactProvider */ + +struct _LinphoneContactProvider { + belle_sip_object_t base; + LinphoneCore* lc; +}; + +typedef struct _LinphoneContactProvider LinphoneContactProvider; +typedef LinphoneContactSearch* (*LinphoneContactProviderStartSearchMethod)( LinphoneContactProvider* thiz, const char* predicate, ContactSearchCallback cb, void* data ); +typedef unsigned int (*LinphoneContactProviderCancelSearchMethod)( LinphoneContactProvider* thiz, LinphoneContactSearch *request ); +#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneContactProvider) + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider,belle_sip_object_t) + const char* name; /*!< Name of the contact provider (LDAP, Google, ...) */ + + /* pure virtual methods: inheriting objects must implement these */ + LinphoneContactProviderStartSearchMethod begin_search; + LinphoneContactProviderCancelSearchMethod cancel_search; +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + + +void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc); +LinphoneCore* linphone_contact_provider_get_core(LinphoneContactProvider* obj); +const char* linphone_contact_provider_get_name(LinphoneContactProvider* obj); diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c new file mode 100644 index 000000000..843cea918 --- /dev/null +++ b/coreapi/ldap/ldapprovider.c @@ -0,0 +1,290 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ldapprovider.h" +#include "linphonecore_utils.h" +#include "lpconfig.h" +#include + +struct _LinphoneLDAPContactSearch +{ + LDAP *ld; + int msgid; + char* filter; +}; + +#define MAX_RUNNING_REQUESTS 10 +#define FILTER_MAX_SIZE 512 +typedef struct { + int msgid; + LinphoneLDAPContactSearch* request; +} LDAPRequestEntry; + +struct _LinphoneLDAPContactProvider +{ + LDAP* ld; + //LDAPRequestEntry requests[MAX_RUNNING_REQUESTS]; + MSList* requests; + int req_count; + + // config + int use_tls; + char* auth_method; + char* username; + char* password; + + char* base_object; + char** attributes; + char* filter; + int timeout; + int deref_aliases; + int max_results; +}; + +/* ************************* + * LinphoneLDAPContactSearch + * *************************/ + +LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) +{ + LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); + LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); + linphone_contact_search_init(base, predicate, cb, cb_data); + search->ld = cp->ld; + search->filter = ms_malloc(FILTER_MAX_SIZE); + snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); + search->filter[FILTER_MAX_SIZE-1] = 0; + struct timeval timeout = { cp->timeout, 0 }; + ldap_search_ext(search->ld, cp->base_object, LDAP_SCOPE_SUBTREE, search->filter, + cp->attributes, 0, NULL, NULL, &timeout, cp->max_results, &search->msgid ); + return search; +} + +static void linphone_ldap_contact_destroy( LinphoneLDAPContactSearch* obj ) +{ + (void)obj; +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch); +BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, + (belle_sip_object_destroy_t)linphone_ldap_contact_destroy, + NULL, + NULL, + TRUE +); + + +/* *************************** + * LinphoneLDAPContactProvider + * ***************************/ + +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) +{ + if(obj->auth_method) ms_free(obj->auth_method); + if(obj->username) ms_free(obj->username); + if(obj->password) ms_free(obj->password); + if(obj->base_object) ms_free(obj->base_object); + if(obj->attributes){ + int i=0; + for( ; obj->attributes[i]; i++){ + ms_free(obj->attributes[i]); + } + ms_free(obj->attributes); + } +} + +static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) +{ + if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); + obj->ld = NULL; + linphone_ldap_contact_provider_conf_destroy(obj); +} + +static LinphoneLDAPContactSearch* linphone_ldap_begin_search(LinphoneLDAPContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + LDAPRequestEntry* entry = ms_new0(LDAPRequestEntry,1); + if( entry){ + LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create(obj, predicate, cb, cb_data); + entry->msgid = request->msgid; + entry->request = request; + obj->requests = ms_list_append(obj->requests, entry); + obj->req_count++; + return request; + } else { + return NULL; + } +} + +static int linphone_ldap_request_entry_compare(const void*a, const void* b) +{ + const LDAPRequestEntry* ra = (const LDAPRequestEntry*)a; + const LDAPRequestEntry* rb = (const LDAPRequestEntry*)b; + return !(ra->msgid == rb->msgid); +} + +static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) +{ + LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req); + LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); + LDAPRequestEntry dummy = { ldap_req->msgid, ldap_req }; + int ret = 1; + + MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare, &dummy); + if( list_entry ) { + ldap_cp->requests = ms_list_remove(ldap_cp->requests, list_entry); + ldap_cp->req_count--; + ms_free(list_entry); + ret = 0; // return OK if we found it in the monitored requests + } else { + ms_warning("Couldn't find ldap request %p (id %d) in monitoring.", ldap_req, ldap_req->msgid); + } + belle_sip_object_unref(req); + return ret; +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); + +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= +{ + { + { + BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), + (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, + NULL, + NULL + }, + "LDAP", + (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, + (LinphoneContactProviderCancelSearchMethod)linphone_ldap_cancel_search + } +}; + +static bool_t linphone_ldap_contact_provider_iterate(void *data) +{ + LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); + if( obj->ld && (obj->req_count >= 0) ){ + int wait_for_all_results = 1; + // never block + struct timeval timeout = {0,0}; + LDAPMessage* results = NULL; + + int res = ldap_result(obj->ld, LDAP_RES_ANY, wait_for_all_results, &timeout, &results); + + switch( res ){ + case -1: + { + ms_warning("Error in ldap_result : returned -1"); + break; + } + case 0: break; // nothing to do + case LDAP_RES_BIND: + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_SEARCH_REFERENCE: + case LDAP_RES_SEARCH_RESULT: + case LDAP_RES_MODIFY: + case LDAP_RES_ADD: + case LDAP_RES_DELETE: + case LDAP_RES_MODDN: + case LDAP_RES_COMPARE: + case LDAP_RES_EXTENDED: + case LDAP_RES_INTERMEDIATE: + { + ms_message("Got LDAP result type %x", res); + ldap_msgfree(results); + break; + } + default: + ms_message("Unhandled LDAP result %x", res); + break; + } + } + return TRUE; +} + +static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, LpConfig* config) +{ + const char* section="ldap"; + char* attributes_list, *saveptr, *attr; + unsigned int attr_count = 0, attr_idx = 0, i; + obj->use_tls = lp_config_get_int(config, section, "use_tls", 0); + obj->timeout = lp_config_get_int(config, section, "timeout", 10); + obj->deref_aliases = lp_config_get_int(config, section, "deref_aliases", 0); + obj->max_results = lp_config_get_int(config, section, "max_results", 50); + + // free any pre-existing char* conf values + linphone_ldap_contact_provider_conf_destroy(obj); + + + // parse the attributes list + attributes_list = ms_strdup(lp_config_get_string(config, section, "attributes", "telephoneNumber,givenName,sn")); + + // count attributes: + for( i=0; attributes_list[i]; i++) + { + if( attributes_list[i] == ',') attr_count++; + } + obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*)); + + attr = strtok_r( attributes_list, ",", &saveptr ); + while( attr != NULL ){ + obj->attributes[attr_idx] = ms_strdup(attr); + attr_idx++; + attr = strtok_r(NULL, ",", &saveptr); + } + if( attr_idx == attr_count) + + + + obj->auth_method = ms_strdup(lp_config_get_string(config, section, "auth_method", "anonymous")); + obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); + obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); + obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "")); + +} + + +LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc) +{ + LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); + linphone_contact_provider_init(LINPHONE_CONTACT_PROVIDER(obj), lc); + memset(obj->requests, MAX_RUNNING_REQUESTS, sizeof(LDAPRequestEntry)); + + int proto_version = LDAP_VERSION3; + const char* url = "localhost"; + ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); + + linphone_ldap_contact_provider_loadconfig(obj, linphone_core_get_config(lc)); + + int ret = ldap_initialize(&(obj->ld),url); + + if( ret != LDAP_SUCCESS ){ + ms_error( "Problem initializing ldap on url '%s': %s", url, ldap_err2string(ret)); + linphone_ldap_contact_provider_destroy(obj); + return NULL; + } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ + ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); + linphone_ldap_contact_provider_destroy(obj); + return NULL; + } else { + // register our hook into iterate so that LDAP can do its magic asynchronously + linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); + } + return obj; +} + diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h new file mode 100644 index 000000000..bea77554b --- /dev/null +++ b/coreapi/ldap/ldapprovider.h @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "contactprovider.h" + +#include + +typedef struct _LinphoneLDAPContactProvider LinphoneLDAPContactProvider; + +/* LinphoneLDAPContactSearch */ +typedef struct _LinphoneLDAPContactSearch LinphoneLDAPContactSearch; + +#define LINPHONE_LDAP_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneLDAPContactSearch) + +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld, + const char* predicate, + ContactSearchCallback cb, + void* cb_data); + + +/* LinphoneLDAPContactProvider */ + +#define LINPHONE_LDAP_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactProvider) + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider) +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d8a0e26db..e85b35f8b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2152,10 +2152,12 @@ LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, co /** Contact Providers */ BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) -BELLE_SIP_TYPE_ID(linphone_contact_provider_t) +BELLE_SIP_TYPE_ID(LinphoneContactSearch), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) BELLE_SIP_DECLARE_TYPES_END -BELLE_SIP_DECLARE_VPTR(linphone_contact_provider_t) #ifdef __cplusplus }