Merge branch 'ldap'

This commit is contained in:
Guillaume BIENKOWSKI 2013-12-18 15:20:50 +01:00
commit 8d21c03f40
21 changed files with 2178 additions and 49 deletions

View file

@ -165,6 +165,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)])],
@ -864,6 +882,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"

View file

@ -24,11 +24,12 @@ bin_PROGRAMS+=linphoned
endif
linphonec_SOURCES=linphonec.c linphonec.h commands.c
linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS)
linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) $(BELLESIP_CFLAGS)
linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \
$(READLINE_LIBS) \
$(SQLITE3_LIBS) \
$(X11_LIBS)
$(X11_LIBS) \
$(BELLESIP_LIBS)
if BUILD_WIN32
#special build of linphonec to detach from the windows console

View file

@ -48,11 +48,17 @@ liblinphone_la_SOURCES=\
message_storage.c \
info.c \
event.c event.h \
contactprovider.c contactprovider.h \
dict.c \
$(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 \
@ -104,7 +110,8 @@ liblinphone_la_LIBADD= \
$(TUNNEL_LIBS) \
$(LIBSOUP_LIBS) \
$(SQLITE3_LIBS) \
$(LIBXML2_LIBS)
$(LIBXML2_LIBS) \
$(LDAP_LIBS)
if ENABLE_TESTS

101
coreapi/contactprovider.c Normal file
View file

@ -0,0 +1,101 @@
/*
* 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 <linphonecore.h>
/* 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;
ms_message("LinphoneContactSearch@%p(id:%d, pred:%s, cb:%p, data:%p)",
obj, obj->id, obj->predicate, obj->cb, obj->data);
}
static void linphone_contact_search_destroy( LinphoneContactSearch* req) {
ms_message( "~LinphoneContactSearch(%p)", req);
if( req->predicate ) ms_free(req->predicate);
}
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, 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 */
};

63
coreapi/contactprovider.h Normal file
View file

@ -0,0 +1,63 @@
/*
* 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 <belle-sip/object.h>
#include "linphonecore.h"
/* LinphoneContactSearchRequest */
struct _LinphoneContactSearch{
belle_sip_object_t base;
ContactSearchID id;
char* predicate;
ContactSearchCallback cb;
void* data;
};
#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);
/* 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);

159
coreapi/dict.c Normal file
View file

@ -0,0 +1,159 @@
/*
linphone
Copyright (C) 2009 Simon MORLAT (simon.morlat@linphone.org)
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 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 "linphonecore.h"
#include "lpconfig.h"
#include "private.h"
#include <belle-sip/belle-sip.h>
#include <belle-sip/object.h>
#include <belle-sip/dict.h>
/**
* @addtogroup linphone_dict
* @{
**/
LinphoneDictionary* linphone_dictionary_new()
{
return belle_sip_dict_create();
}
LinphoneDictionary* linphone_dictionary_clone(const LinphoneDictionary* src)
{
LinphoneDictionary* cloned = linphone_dictionary_new();
if( cloned ){
belle_sip_dict_clone(src, cloned);
}
return cloned;
}
LinphoneDictionary* linphone_dictionary_ref(LinphoneDictionary* obj)
{
return BELLE_SIP_DICT(belle_sip_object_ref(obj));
}
void linphone_dictionary_unref(LinphoneDictionary *obj)
{
belle_sip_object_unref(obj);
}
void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value)
{
belle_sip_dict_set_int(obj, key, value);
}
int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value)
{
return belle_sip_dict_get_int(obj, key, default_value);
}
void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value)
{
belle_sip_dict_set_string(obj, key, value);
}
const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value)
{
return belle_sip_dict_get_string(obj, key, default_value);
}
void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value)
{
belle_sip_dict_set_int64(obj, key, value);
}
int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value)
{
return belle_sip_dict_get_int64(obj, key, default_value);
}
int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key)
{
return belle_sip_dict_remove(obj, key);
}
void linphone_dictionary_clear(LinphoneDictionary* obj)
{
belle_sip_dict_clear(obj);
}
int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key)
{
return belle_sip_dict_haskey(obj, key);
}
void linphone_dictionary_foreach(const LinphoneDictionary* obj, void (*apply_func)(const char*, void*, void*), void* userdata)
{
return belle_sip_dict_foreach(obj, apply_func, userdata);
}
struct lp_config_to_dict {
const char* section;
const LpConfig* config;
LinphoneDictionary* dict;
};
static void lp_config_section_to_dict_cb(const char*key, struct lp_config_to_dict* userdata)
{
const char* value = lp_config_get_string(userdata->config, userdata->section, key, "");
linphone_dictionary_set_string(userdata->dict, key, value);
}
LinphoneDictionary* lp_config_section_to_dict(const LpConfig* lpconfig, const char* section)
{
LinphoneDictionary* dict = NULL;
struct lp_config_to_dict fd;
fd.config = lpconfig;
fd.section = section;
dict = linphone_dictionary_new();
fd.dict = dict;
lp_config_for_each_entry(lpconfig, section,
(void (*)(const char*, void*))lp_config_section_to_dict_cb,
&fd);
return dict;
}
struct lp_config_from_dict {
const char* section;
LpConfig* config;
};
static void lp_config_dict_dump_cb( const char* key, void* value, void* userdata)
{
struct lp_config_from_dict* fd= (struct lp_config_from_dict*)userdata;
lp_config_set_string(fd->config, fd->section, key, (const char*)value);
}
void lp_config_load_dict_to_section(LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict)
{
struct lp_config_from_dict pvdata = { section, lpconfig };
linphone_dictionary_foreach(dict,lp_config_dict_dump_cb, &pvdata);
}
/**
* @}
**/

View file

@ -53,7 +53,8 @@ LINPHONE_TUTOS=$(helloworld_SOURCES)
helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la \
$(MEDIASTREAMER_LIBS) \
$(ORTP_LIBS)
$(ORTP_LIBS) \
$(BELLESIP_LIBS)
registration_SOURCES=registration.c
LINPHONE_TUTOS+=$(registration_SOURCES)
@ -85,7 +86,8 @@ AM_CFLAGS=\
-DLOG_DOMAIN=\"LinphoneCore\" \
$(IPV6_CFLAGS) \
-DORTP_INET6 \
$(VIDEO_CFLAGS)
$(VIDEO_CFLAGS) \
$(BELLESIP_CFLAGS)
tutodir=$(datadir)/tutorials/linphone

773
coreapi/ldap/ldapprovider.c Normal file
View file

@ -0,0 +1,773 @@
/*
* 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.h"
#include "linphonecore_utils.h"
#include "lpconfig.h"
#include <belle-sip/dict.h>
#include <ldap.h>
#include <sasl/sasl.h>
#define MAX_RUNNING_REQUESTS 10
#define FILTER_MAX_SIZE 512
typedef enum {
ANONYMOUS,
PLAIN,
SASL
} LDAPAuthMethod;
struct LDAPFriendData {
char* name;
char* sip;
};
struct _LinphoneLDAPContactProvider
{
LinphoneContactProvider base;
LinphoneDictionary* config;
LDAP* ld;
MSList* requests;
uint req_count;
// bind transaction
int bind_msgid;
const char* auth_mechanism;
bool_t connected;
// config
int use_tls;
LDAPAuthMethod auth_method;
const char* username;
const char* password;
const char* server;
const char* base_object;
const char* sip_attr;
const char* name_attr;
const char* filter;
char** attributes;
int timeout;
int deref_aliases;
int max_results;
};
struct _LinphoneLDAPContactSearch
{
LinphoneContactSearch base;
LDAP* ld;
int msgid;
char* filter;
bool_t complete;
MSList* found_entries;
unsigned int found_count;
};
/* *************************
* 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);
struct timeval timeout = { cp->timeout, 0 };
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;
ms_message("Calling ldap_search_ext with predicate '%s' on base %s", search->filter, cp->base_object);
int ret = ldap_search_ext(search->ld,
cp->base_object, // base from which to start
LDAP_SCOPE_SUBTREE,
search->filter, // search predicate
cp->attributes, // which attributes to get
0, // 0 = get attrs AND value, 1 = get attrs only
NULL,
NULL,
&timeout, // server timeout for the search
cp->max_results,// max result number
&search->msgid );
if( ret != LDAP_SUCCESS ){
ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret));
belle_sip_object_unref(search);
return NULL;
} else {
ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", search, search->msgid);
}
return search;
}
void linphone_ldap_contact_search_destroy_friend( void* entry )
{
linphone_friend_destroy((LinphoneFriend*)entry);
}
unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj)
{
return obj->found_count;
}
static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj )
{
ms_message("~LinphoneLDAPContactSearch(%p)", obj);
ms_list_for_each(obj->found_entries, linphone_ldap_contact_search_destroy_friend);
obj->found_entries = ms_list_free(obj->found_entries);
if( obj->filter ) ms_free(obj->filter);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch,
(belle_sip_object_destroy_t)linphone_ldap_contact_search_destroy,
NULL,
NULL,
TRUE
);
/* ***************************
* LinphoneLDAPContactProvider
* ***************************/
static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid );
static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req);
static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj );
static bool_t linphone_ldap_contact_provider_iterate(void *data);
static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact);
/* Authentication methods */
struct AuthMethodDescription{
LDAPAuthMethod method;
const char* description;
};
static struct AuthMethodDescription ldap_auth_method_description[] = {
{ANONYMOUS, "anonymous"},
{PLAIN, "plain"},
{SASL, "sasl"},
{0, NULL}
};
static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description )
{
struct AuthMethodDescription* desc = ldap_auth_method_description;
while( desc && desc->description ){
if( strcmp(description, desc->description) == 0)
return desc->method;
desc++;
}
return ANONYMOUS;
}
static void linphone_ldap_contact_provider_destroy_request_cb(void *req)
{
belle_sip_object_unref(req);
}
static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj )
{
ms_message("linphone_ldap_contact_provider_destroy");
linphone_core_remove_iterate_hook(LINPHONE_CONTACT_PROVIDER(obj)->lc, linphone_ldap_contact_provider_iterate,obj);
// clean pending requests
ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request_cb);
if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL);
obj->ld = NULL;
if( obj->config ) linphone_dictionary_unref(obj->config);
linphone_ldap_contact_provider_conf_destroy(obj);
}
static int linphone_ldap_contact_provider_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results )
{
int ret;
if( obj->auth_method == ANONYMOUS ) {
ms_message("ANONYMOUS BIND OK");
ret = LDAP_SUCCESS;
} else {
ms_message("COMPLICATED BIND follow-up");
ret = ldap_sasl_interactive_bind(obj->ld,
NULL, // dn, should be NULL
"DIGEST-MD5",
NULL,NULL, // server and client controls
LDAP_SASL_QUIET, // never prompt, only use callback
linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed
obj, // private data
results, // result, to pass later on when a ldap_result() comes
&obj->auth_mechanism,
&obj->bind_msgid );
if( ret != LDAP_SUCCESS){
ms_error("ldap_parse_sasl_bind_result failed(%d)", ret);
}
}
if( ret == LDAP_SUCCESS ){
obj->connected = TRUE;
obj->bind_msgid = 0;
}
return ret;
}
static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value)
{
if( strcmp(attr_name, obj->name_attr ) == 0 ){
lf->name = ms_strdup(attr_value);
} else if( strcmp(attr_name, obj->sip_attr) == 0 ) {
lf->sip = ms_strdup(attr_value);
}
// return 1 if the structure has enough data to create a linphone friend
if( lf->name && lf->sip )
return 1;
else
return 0;
}
static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req, LDAPMessage* message )
{
int msgtype = ldap_msgtype(message);
switch(msgtype){
case LDAP_RES_SEARCH_ENTRY:
case LDAP_RES_EXTENDED:
{
LDAPMessage *entry = ldap_first_entry(obj->ld, message);
LinphoneCore* lc = LINPHONE_CONTACT_PROVIDER(obj)->lc;
while( entry != NULL ){
struct LDAPFriendData ldap_data = {0};
bool_t contact_complete = FALSE;
BerElement* ber = NULL;
char* attr = ldap_first_attribute(obj->ld, entry, &ber);
char* dn = ldap_get_dn(obj->ld, entry);
if( dn ){
//ms_message("search result: dn: %s", dn);
ldap_memfree(dn);
}
while( attr ){
struct berval** values = ldap_get_values_len(obj->ld, entry, attr);
struct berval** it = values;
while( values && *it && (*it)->bv_val && (*it)->bv_len )
{
//ms_message("%s -> %s", attr, (*it)->bv_val);
contact_complete = linphone_ldap_contact_provider_complete_contact(obj, &ldap_data, attr, (*it)->bv_val);
if( contact_complete ) break;
it++;
}
if( values ) ldap_value_free_len(values);
ldap_memfree(attr);
if( contact_complete ) break;
attr = ldap_next_attribute(obj->ld, entry, ber);
}
if( contact_complete ) {
LinphoneAddress* la = linphone_core_interpret_url(lc, ldap_data.sip);
if( la ){
LinphoneFriend* lf = linphone_core_create_friend(lc);
linphone_friend_set_address(lf, la);
linphone_friend_set_name(lf, ldap_data.name);
req->found_entries = ms_list_append(req->found_entries, lf);
req->found_count++;
//ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip);
ms_free(ldap_data.sip);
ms_free(ldap_data.name);
linphone_address_destroy(la);
}
}
if( ber ) ber_free(ber, 0);
entry = ldap_next_entry(obj->ld, entry);
}
}
break;
case LDAP_RES_SEARCH_RESULT:
{
// this one is received when a request is finished
req->complete = TRUE;
linphone_contact_search_invoke_cb(LINPHONE_CONTACT_SEARCH(req), req->found_entries);
}
break;
default: ms_message("[LDAP] Unhandled message type %x", msgtype); break;
}
}
static bool_t linphone_ldap_contact_provider_iterate(void *data)
{
LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data);
if( obj->ld && ((obj->req_count > 0) || (obj->bind_msgid != 0) )){
// never block
struct timeval timeout = {0,0};
LDAPMessage* results = NULL;
int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ONE, &timeout, &results);
if( ret != 0 && ret != -1) ms_message("ldap_result %x", ret);
switch( ret ){
case -1:
{
ms_warning("Error in ldap_result : returned -1 (req_count %d, bind_msgid %d): %s", obj->req_count, obj->bind_msgid, ldap_err2string(errno));
break;
}
case 0: break; // nothing to do
case LDAP_RES_BIND:
{
ms_message("iterate: LDAP_RES_BIND");
if( ldap_msgid( results ) != obj->bind_msgid ) {
ms_error("Bad msgid");
} else {
linphone_ldap_contact_provider_parse_bind_results( obj, results );
}
break;
}
case LDAP_RES_EXTENDED:
case LDAP_RES_SEARCH_ENTRY:
case LDAP_RES_SEARCH_REFERENCE:
case LDAP_RES_INTERMEDIATE:
case LDAP_RES_SEARCH_RESULT:
{
LDAPMessage* message = ldap_first_message(obj->ld, results);
LinphoneLDAPContactSearch* req = linphone_ldap_contact_provider_request_search(obj, ldap_msgid(message));
while( message != NULL ){
//ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req);
linphone_ldap_contact_provider_handle_search_result(obj, req, message );
message = ldap_next_message(obj->ld, message);
}
if( req && ret == LDAP_RES_SEARCH_RESULT) linphone_ldap_contact_provider_cancel_search(LINPHONE_CONTACT_PROVIDER(obj), LINPHONE_CONTACT_SEARCH(req));
break;
}
case LDAP_RES_MODIFY:
case LDAP_RES_ADD:
case LDAP_RES_DELETE:
case LDAP_RES_MODDN:
case LDAP_RES_COMPARE:
default:
ms_message("Unhandled LDAP result %x", ret);
break;
}
if( results )
ldap_msgfree(results);
}
return TRUE;
}
static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj )
{
if(obj->attributes){
int i=0;
for( ; obj->attributes[i]; i++){
ms_free(obj->attributes[i]);
}
ms_free(obj->attributes);
}
}
static char* required_config_keys[] = {
// connection
"server",
"use_tls",
"auth_method",
"username",
"password",
// search
"base_object",
"filter",
"name_attribute",
"sip_attribute",
"attributes",
// misc
"timeout",
"max_results",
"deref_aliases",
NULL
};
static bool_t linphone_ldap_contact_provider_valid_config(const LinphoneDictionary* dict)
{
char** config_name = required_config_keys;
bool_t valid = TRUE;
bool_t has_key;
while(*config_name ){
has_key = linphone_dictionary_haskey(dict, *config_name);
if( !has_key ) ms_error("Missing LDAP config value for '%s'", *config_name);
valid &= has_key;
config_name++;
}
return valid;
}
static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, const LinphoneDictionary* dict)
{
char* attributes_list, *saveptr, *attr;
unsigned int attr_count = 0, attr_idx = 0, i;
if( !linphone_ldap_contact_provider_valid_config(dict) ) return;
// free any pre-existing attributes values
linphone_ldap_contact_provider_conf_destroy(obj);
if( obj->config ) linphone_dictionary_unref(obj->config);
// clone new config into the dictionary
obj->config = linphone_dictionary_ref(linphone_dictionary_clone(dict));
obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0);
obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10);
obj->deref_aliases = linphone_dictionary_get_int(obj->config, "deref_aliases", 0);
obj->max_results = linphone_dictionary_get_int(obj->config, "max_results", 50);
obj->username = linphone_dictionary_get_string(obj->config, "username", "");
obj->password = linphone_dictionary_get_string(obj->config, "password", "");
obj->base_object = linphone_dictionary_get_string(obj->config, "base_object", "dc=example,dc=com");
obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://192.168.0.230:10389");
obj->filter = linphone_dictionary_get_string(obj->config, "filter", "uid=*%s*");
obj->name_attr = linphone_dictionary_get_string(obj->config, "name_attribute", "givenName");
obj->sip_attr = linphone_dictionary_get_string(obj->config, "sip_attribute", "mobile");
/*
* Get authentication method
*/
obj->auth_method = linphone_ldap_contact_provider_auth_method(
linphone_dictionary_get_string(obj->config, "auth_method", "anonymous")
);
/*
* parse the attributes list
*/
attributes_list = ms_strdup(
linphone_dictionary_get_string(obj->config,
"attributes",
"telephoneNumber,givenName,sn,mobile,homePhone")
);
// count attributes:
for( i=0; attributes_list[i]; i++) {
if( attributes_list[i] == ',') attr_count++;
}
// 1 more for the first attr without ',', the other for the null-finished list
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+1) ms_error("Invalid attribute number!!! %d expected, got %d", attr_count+1, attr_idx);
ms_free(attributes_list);
}
static int linphone_ldap_contact_provider_bind_interact(LDAP *ld,
unsigned flags,
void *defaults,
void *sasl_interact)
{
sasl_interact_t *interact = (sasl_interact_t*)sasl_interact;
LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(defaults);
ms_message("bind_interact called: ld %p, flags %x, default %p, interact %p",
ld, flags, defaults, sasl_interact);
if( ld == NULL ) return LDAP_PARAM_ERROR;
while( interact->id != SASL_CB_LIST_END ) {
const char *dflt = interact->defresult;
switch( interact->id ) {
case SASL_CB_GETREALM:
ms_message("* SASL_CB_GETREALM");
dflt=NULL;
break;
case SASL_CB_USER:
case SASL_CB_AUTHNAME:
ms_message("* SASL_CB_AUTHNAME -> %s", obj->username);
dflt=obj->username;
break;
case SASL_CB_PASS:
ms_message("* SASL_CB_PASS -> %s", obj->password);
dflt=obj->password;
break;
default:
ms_message("my_sasl_interact asked for unknown %lx\n",interact->id);
}
interact->result = (dflt && *dflt) ? dflt : (const char*)"";
interact->len = strlen( (const char*)interact->result );
interact++;
}
return LDAP_SUCCESS;
}
static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj )
{
int ret;
const char* auth_mechanism = linphone_dictionary_get_string(obj->config, "auth_method", "anonymous");
LDAPAuthMethod method = obj->auth_method;
if( method == ANONYMOUS ){
// for anonymous authentication, use a simple sasl_bind
struct berval creds = {strlen(obj->password), ms_strdup(obj->password)};
ret = ldap_sasl_bind(obj->ld, obj->base_object, NULL, &creds, NULL, NULL, &obj->bind_msgid);
if(creds.bv_val) ms_free(creds.bv_val);
} else {
ret = ldap_sasl_interactive_bind(obj->ld,
NULL, // dn, should be NULL
"SIMPLE",//"DIGEST-MD5",
NULL,NULL, // server and client controls
LDAP_SASL_QUIET, // never prompt, only use callback
linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed
obj, // private data
NULL, // result, to pass later on when a ldap_result() comes
&obj->auth_mechanism,
&obj->bind_msgid );
}
if( ret == LDAP_SUCCESS || ret == LDAP_SASL_BIND_IN_PROGRESS ) {
if( ret == LDAP_SASL_BIND_IN_PROGRESS) ms_message("BIND_IN_PROGRESS");
ms_message("LDAP bind request sent, auth: %s, msgid %x", obj->auth_mechanism?obj->auth_mechanism:"-", obj->bind_msgid);
} else {
int err;
ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err);
ms_error("ldap_sasl_bind error returned %d, err %d (%s), auth_method: %s",
ret, err, ldap_err2string(err), auth_mechanism );
}
return 0;
}
unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj)
{
return obj->max_results;
}
static void linphone_ldap_contact_provider_config_dump_cb(const char*key, void* value, void* userdata)
{
ms_message("- %s -> %s", key, (const char* )value);
}
LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config)
{
LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider);
int proto_version = LDAP_VERSION3;
linphone_contact_provider_init((LinphoneContactProvider*)obj, lc);
ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name);
if( !linphone_ldap_contact_provider_valid_config(config) ) {
ms_error( "Invalid configuration for LDAP, aborting creation");
belle_sip_object_unref(obj);
obj = NULL;
} else {
linphone_dictionary_foreach( config, linphone_ldap_contact_provider_config_dump_cb, 0 );
linphone_ldap_contact_provider_loadconfig(obj, config);
int ret = ldap_initialize(&(obj->ld),obj->server);
if( ret != LDAP_SUCCESS ){
ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret));
belle_sip_object_unref(obj);
obj = 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));
belle_sip_object_unref(obj);
obj = NULL;
} else {
// register our hook into iterate so that LDAP can do its magic asynchronously.
//linphone_ldap_contact_provider_bind(obj);
linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj);
}
}
return obj;
}
/**
* Search an LDAP request in the list of current LDAP requests to serve, only taking
* the msgid as a key to search.
*/
static int linphone_ldap_request_entry_compare_weak(const void*a, const void* b)
{
const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a;
const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b;
return !(ra->msgid == rb->msgid); // 0 if equal
}
/**
* Search an LDAP request in the list of current LDAP requests to serve, with strong search
* comparing both msgid and request pointer
*/
static int linphone_ldap_request_entry_compare_strong(const void*a, const void* b)
{
const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a;
const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b;
return !(ra->msgid == rb->msgid) && !(ra == rb);
}
static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid )
{
LinphoneLDAPContactSearch dummy = {};
dummy.msgid = msgid;
MSList* list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy);
if( list_entry ) return list_entry->data;
else return NULL;
}
static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req)
{
LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req);
LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj);
int ret = 1;
MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare_strong, req);
if( list_entry ) {
ldap_cp->requests = ms_list_remove_link(ldap_cp->requests, list_entry);
ldap_cp->req_count--;
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); // unref request even if not found
return ret;
}
static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( LinphoneLDAPContactProvider* obj,
const char* predicate,
ContactSearchCallback cb,
void* cb_data )
{
// if we're not yet connected, bind
if( !obj->connected ) linphone_ldap_contact_provider_bind(obj);
LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create ( obj, predicate, cb, cb_data );
if ( request != NULL ) {
ms_message ( "Created search %d for '%s', msgid %d, @%p", obj->req_count, predicate, request->msgid, request );
obj->requests = ms_list_append ( obj->requests, request );
obj->req_count++;
}
return request;
}
static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* obj, char* buff, size_t buff_size, size_t *offset)
{
belle_sip_error_code error = BELLE_SIP_OK;
error = belle_sip_snprintf(buff, buff_size, offset, "ld:%p,\n", obj->ld);
if(error!= BELLE_SIP_OK) return error;
error = belle_sip_snprintf(buff, buff_size, offset, "req_count:%d,\n", obj->req_count);
if(error!= BELLE_SIP_OK) return error;
error = belle_sip_snprintf(buff, buff_size, offset, "bind_msgid:%d,\n", obj->bind_msgid);
if(error!= BELLE_SIP_OK) return error;
error = belle_sip_snprintf(buff, buff_size, offset,
"CONFIG:\n"
"tls: %d \n"
"auth: %d \n"
"user: %s \n"
"pass: %s \n"
"server: %s \n"
"base: %s \n"
"filter: %s \n"
"timeout: %d \n"
"deref: %d \n"
"max_res: %d \n"
"sip_attr:%s \n"
"name_attr:%s \n"
"attrs:\n",
obj->use_tls, obj->auth_method,
obj->username, obj->password, obj->server,
obj->base_object, obj->filter,
obj->timeout, obj->deref_aliases,
obj->max_results,
obj->sip_attr, obj->name_attr);
if(error!= BELLE_SIP_OK) return error;
char **attr = obj->attributes;
while( *attr ){
error = belle_sip_snprintf(buff, buff_size, offset, "- %s\n", *attr);
if(error!= BELLE_SIP_OK) return error;
else attr++;
}
return error;
}
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,
(belle_sip_object_marshal_t)linphone_ldap_contact_provider_marshal
},
"LDAP",
(LinphoneContactProviderStartSearchMethod)linphone_ldap_contact_provider_begin_search,
(LinphoneContactProviderCancelSearchMethod)linphone_ldap_contact_provider_cancel_search
}
};

View file

@ -0,0 +1,45 @@
/*
* 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 <ldap.h>
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);
unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj);
/* 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, const LinphoneDictionary* config);
unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj);

View file

@ -1350,6 +1350,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
lc->tunnel=linphone_core_tunnel_new(lc);
if (lc->tunnel) linphone_tunnel_configure(lc->tunnel);
#endif
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Ready"));
lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
@ -5674,16 +5675,23 @@ static void linphone_core_uninit(LinphoneCore *lc)
}
#endif //BUILD_UPNP
#ifdef BUILD_LDAP
if( lc->ldap != NULL ) {
belle_sip_object_unref(lc->ldap);
lc->ldap = NULL;
}
#endif
if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
lp_config_destroy(lc->config);
lc->config = NULL; /* Mark the config as NULL to block further calls */
ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy);
lc->call_logs=ms_list_free(lc->call_logs);
ms_list_for_each(lc->last_recv_msg_ids,ms_free);
lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids);
// Free struct variable
if(lc->zrtp_secrets_cache != NULL) {
ms_free(lc->zrtp_secrets_cache);
@ -6287,5 +6295,3 @@ void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){
linphone_core_message_storage_init(lc);
}
}

View file

@ -32,6 +32,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "lpconfig.h"
#include <belle-sip/object.h>
#include <belle-sip/dict.h>
#define LINPHONE_IPADDR_SIZE 64
#define LINPHONE_HOSTNAME_SIZE 128
@ -118,6 +121,8 @@ typedef enum _LinphoneTransportType LinphoneTransportType;
*/
typedef struct SalAddress LinphoneAddress;
typedef struct belle_sip_dict LinphoneDictionary;
/**
* The LinphoneContent struct holds data that can be embedded in a signaling message.
* @ingroup misc
@ -181,6 +186,37 @@ typedef enum _LinphoneReason LinphoneReason;
**/
const char *linphone_reason_to_string(LinphoneReason err);
/* linphone dictionary */
LINPHONE_PUBLIC LinphoneDictionary* linphone_dictionary_new();
LinphoneDictionary * linphone_dictionary_clone(const LinphoneDictionary* src);
LinphoneDictionary * linphone_dictionary_ref(LinphoneDictionary* obj);
void linphone_dictionary_unref(LinphoneDictionary* obj);
LINPHONE_PUBLIC void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value);
LINPHONE_PUBLIC int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value);
LINPHONE_PUBLIC void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value);
LINPHONE_PUBLIC const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value);
LINPHONE_PUBLIC void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value);
LINPHONE_PUBLIC int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value);
LINPHONE_PUBLIC int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key);
LINPHONE_PUBLIC void linphone_dictionary_clear(LinphoneDictionary* obj);
LINPHONE_PUBLIC int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key);
LINPHONE_PUBLIC void linphone_dictionary_foreach( const LinphoneDictionary* obj, void (*apply_func)(const char*key, void* value, void* userdata), void* userdata);
/**
* Converts a config section into a dictionary.
* @return a #LinphoneDictionary with all the keys from a section, or NULL if the section doesn't exist
* @ingroup misc
*/
LinphoneDictionary* lp_config_section_to_dict( const LpConfig* lpconfig, const char* section );
/**
* Loads a dictionary into a section of the lpconfig. If the section doesn't exist it is created.
* Overwrites existing keys, creates non-existing keys.
* @ingroup misc
*/
void lp_config_load_dict_to_section( LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict);
#ifdef IN_LINPHONE
#include "linphonefriend.h"
#include "event.h"
@ -402,7 +438,7 @@ typedef enum _LinphonePrivacy {
*
**/
LinphonePrivacyCritical=0x10,
/**
* Special keyword to use privacy as defined either globally or by proxy using linphone_proxy_config_set_privacy()
*/
@ -442,7 +478,7 @@ LINPHONE_PUBLIC LinphoneInfoMessage *linphone_info_message_copy(const LinphoneIn
* @ingroup media_parameters
**/
struct _LinphoneVideoPolicy{
bool_t automatically_initiate; /**<Whether video shall be automatically proposed for outgoing calls.*/
bool_t automatically_initiate; /**<Whether video shall be automatically proposed for outgoing calls.*/
bool_t automatically_accept; /**<Whether video shall be automatically accepted for incoming calls*/
bool_t unused[2];
};
@ -901,7 +937,7 @@ struct _LinphoneChatRoom;
* <br> Can be created by linphone_chat_room_create_message().
*/
typedef struct _LinphoneChatMessage LinphoneChatMessage;
/**
* A chat room is the place where text messages are exchanged.
* <br> Can be created by linphone_core_create_chat_room().
@ -945,7 +981,7 @@ LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoo
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg);
LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state);
@ -1023,23 +1059,23 @@ typedef void (*LinphoneCoreCallEncryptionChangedCb)(LinphoneCore *lc, LinphoneCa
* Registration state notification callback prototype
* */
typedef void (*LinphoneCoreRegistrationStateChangedCb)(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message);
/** Callback prototype
* @deprecated
/** Callback prototype
* @deprecated
*/
typedef void (*ShowInterfaceCb)(LinphoneCore *lc);
/** Callback prototype
* @deprecated
/** Callback prototype
* @deprecated
*/
typedef void (*DisplayStatusCb)(LinphoneCore *lc, const char *message);
/** Callback prototype
* @deprecated
/** Callback prototype
* @deprecated
*/
typedef void (*DisplayMessageCb)(LinphoneCore *lc, const char *message);
/** Callback prototype
* @deprecated
/** Callback prototype
* @deprecated
*/
typedef void (*DisplayUrlCb)(LinphoneCore *lc, const char *message, const char *url);
/** Callback prototype
/** Callback prototype
*/
typedef void (*LinphoneCoreCbFunc)(LinphoneCore *lc,void * user_data);
/**
@ -1057,7 +1093,7 @@ typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneF
* Callback prototype
*/
typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
/**
/**
* Callback for requesting authentication information to application or user.
* @param lc the LinphoneCore
* @param realm the realm (domain) on which authentication is required.
@ -1066,7 +1102,7 @@ typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, Linphon
*/
typedef void (*LinphoneCoreAuthInfoRequestedCb)(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
/**
/**
* Callback to notify a new call-log entry has been added.
* This is done typically when a call terminates.
* @param lc the LinphoneCore
@ -1093,8 +1129,8 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat
* @param LinphoneChatMessage incoming message
*/
typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
/**
/**
* Callback for being notified of DTMFs received.
* @param lc the linphone core
* @param call the call that received the dtmf
@ -1114,7 +1150,7 @@ typedef void (*LinphoneCoreBuddyInfoUpdatedCb)(LinphoneCore *lc, LinphoneFriend
*/
typedef void (*LinphoneCoreTransferStateChangedCb)(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
/**
/**
* Callback for receiving quality statistics for calls.
* @param lc the LinphoneCore
* @param call the call
@ -1122,11 +1158,11 @@ typedef void (*LinphoneCoreTransferStateChangedCb)(LinphoneCore *lc, LinphoneCal
*/
typedef void (*LinphoneCoreCallStatsUpdatedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats);
/**
/**
* Callback prototype for receiving info messages.
* @param lc the LinphoneCore
* @param call the call whose info message belongs to.
* @param msg the info message.
* @param msg the info message.
*/
typedef void (*LinphoneCoreInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg);
@ -1431,7 +1467,7 @@ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadT
* @param rate can be #LINPHONE_FIND_PAYLOAD_IGNORE_RATE
* @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS
* @return Returns NULL if not found.
*/
*/
LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ;
LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt);
@ -1447,7 +1483,7 @@ LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *
* @ingroup proxy
*/
LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc);
LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc);
@ -1604,28 +1640,28 @@ LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *l
* @ingroup network_parameters
* Return the availability of uPnP.
*
* @return true if uPnP is available otherwise return false.
* @return true if uPnP is available otherwise return false.
*/
bool_t linphone_core_upnp_available();
/**
* @ingroup network_parameters
* Return the internal state of uPnP.
* Return the internal state of uPnP.
*
* @param lc #LinphoneCore
* @return an LinphoneUpnpState.
* @return an LinphoneUpnpState.
*/
LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc);
/**
* @ingroup network_parameters
* Return the external ip address of router.
* Return the external ip address of router.
* In some cases the uPnP can have an external ip address but not a usable uPnP
* (state different of Ok).
* (state different of Ok).
*
* @param lc #LinphoneCore
* @return a null terminated string containing the external ip address. If the
* the external ip address is not available return null.
* the external ip address is not available return null.
*/
const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc);
@ -2167,6 +2203,23 @@ LINPHONE_PUBLIC const char *linphone_core_get_video_display_filter(LinphoneCore
LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filtername);
/** Contact Providers
*/
BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000)
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
typedef unsigned int ContactSearchID;
struct _LinphoneContactSearch;
typedef struct _LinphoneContactSearch LinphoneContactSearch;
typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data );
#ifdef __cplusplus
}
#endif

View file

@ -74,6 +74,10 @@ extern "C" {
#endif
#endif
#ifdef BUILD_LDAP
#include "ldap/ldapprovider.h"
#endif
struct _LinphoneCallParams{
LinphoneCall *referer; /*in case this call creation is consecutive to an incoming transfer, this points to the original call */
int audio_bw; /* bandwidth limit for audio stream */
@ -656,6 +660,10 @@ struct _LinphoneCore
#ifdef BUILD_UPNP
UpnpContext *upnp;
#endif //BUILD_UPNP
#ifdef BUILD_LDAP
LinphoneLDAPContactProvider* ldap;
#endif //BUILD_LDAP
};

View file

@ -55,7 +55,7 @@ linphone_SOURCES+= \
endif
linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \
$(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS)
$(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS) $(BELLESIP_LIBS)
if BUILD_WIN32
@ -77,7 +77,7 @@ endif
AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \
$(MEDIASTREAMER_CFLAGS) \
$(ORTP_CFLAGS) \
$(ORTP_CFLAGS) $(BELLESIP_CFLAGS) \
$(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \
$(TUNNEL_CFLAGS) \
$(SQLITE3_CFLAGS)

View file

@ -28,6 +28,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "linphonecore.h"
#ifdef BUILD_LDAP
#include "ldap/ldapprovider.h"
#endif
#ifdef ENABLE_NLS
# include <libintl.h>
# undef _
@ -46,6 +51,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define LINPHONE_VERSION LINPHONE_VERSION_DATE
#endif
enum {
COMPLETION_HISTORY,
COMPLETION_LDAP
};
GdkPixbuf * create_pixbuf(const gchar *filename);
GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename);
void add_pixmap_directory(const gchar *directory);
@ -63,6 +73,8 @@ void linphone_gtk_show_assistant(void);
void linphone_gtk_close_assistant(void);
LinphoneCore *linphone_gtk_get_core(void);
LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void);
void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap);
GtkWidget *linphone_gtk_get_main_window();
void linphone_gtk_display_something(GtkMessageType type,const gchar *message);
void linphone_gtk_start_call(GtkWidget *button);

View file

@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphone.h"
void linphone_gtk_login_frame_connect_clicked(GtkWidget *button);
void test_button_clicked_cb(GtkWidget *button);
void linphone_gtk_exit_login_frame(void);
enum {

View file

@ -50,6 +50,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
static LinphoneCore *the_core=NULL;
static LinphoneLDAPContactProvider* ldap_provider = NULL;
static GtkWidget *the_ui=NULL;
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
@ -69,7 +70,7 @@ void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpoi
static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
void linphone_gtk_status_icon_set_blinking(gboolean val);
void _linphone_gtk_enable_video(gboolean val);
void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data);
#ifndef HAVE_GTK_OSX
static gint main_window_x=0;
@ -231,6 +232,23 @@ static const char *linphone_gtk_get_factory_config_file(){
return _factory_config_file;
}
LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){
#ifdef BUILD_LDAP
return ldap_provider;
#else
return NULL;
#endif
}
void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap)
{
if( ldap_provider )
belle_sip_object_unref(ldap_provider);
ldap_provider = ldap ? LINPHONE_LDAP_CONTACT_PROVIDER(belle_sip_object_ref( ldap ))
: NULL;
}
static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file, const char *db_file) {
LinphoneCoreVTable vtable={0};
@ -256,7 +274,16 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
//lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
#ifdef BUILD_LDAP
if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){
LpConfig* cfg = linphone_core_get_config(the_core);
LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap");
linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(the_core, ldap_cfg) );
}
#endif
linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
@ -279,7 +306,7 @@ GtkWidget *linphone_gtk_get_main_window(){
}
void linphone_gtk_destroy_main_window() {
linphone_gtk_destroy_window(the_ui);
linphone_gtk_destroy_window(the_ui);
the_ui = NULL;
}
@ -629,12 +656,31 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
return TRUE;
}
static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, const gchar *key, GtkTreeIter *iter, gpointer user_data){
char* address = NULL;
gboolean ret = FALSE;
gchar *tmp= NULL;
gtk_tree_model_get(gtk_entry_completion_get_model(completion),iter,0,&address,-1);
tmp = g_utf8_casefold(address,-1);
if (tmp){
if (strstr(tmp,key))
ret=TRUE;
g_free(tmp);
}
if( address)
g_free(address);
return ret;
}
static void load_uri_history(){
GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
char key[20];
int i;
GtkEntryCompletion *gep=gtk_entry_completion_new();
GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
GtkListStore *model=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_INT);
for (i=0;;i++){
const char *uri;
snprintf(key,sizeof(key),"uri%i",i);
@ -642,14 +688,18 @@ static void load_uri_history(){
if (uri!=NULL) {
GtkTreeIter iter;
gtk_list_store_append(model,&iter);
gtk_list_store_set(model,&iter,0,uri,-1);
gtk_list_store_set(model,&iter,0,uri,1,COMPLETION_HISTORY,-1);
if (i==0) gtk_entry_set_text(uribar,uri);
}
else break;
}
gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
gtk_entry_completion_set_text_column(gep,0);
gtk_entry_completion_set_popup_completion(gep, TRUE);
gtk_entry_completion_set_match_func(gep,uribar_completion_matchfunc, NULL, NULL);
gtk_entry_completion_set_minimum_key_length(gep,3);
gtk_entry_set_completion(uribar,gep);
g_signal_connect (G_OBJECT (uribar), "changed", G_CALLBACK(linphone_gtk_on_uribar_changed), NULL);
}
static void save_uri_history(){
@ -697,10 +747,130 @@ static void completion_add_text(GtkEntry *entry, const char *text){
}
/* and prepend it on top of the list */
gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,1,COMPLETION_HISTORY,-1);
save_uri_history();
}
void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* friends, void* data )
{
GtkTreeIter iter;
GtkEntry* uribar = GTK_ENTRY(data);
GtkEntryCompletion* compl = gtk_entry_get_completion(uribar);
GtkTreeModel* model = gtk_entry_completion_get_model(compl);
GtkListStore* list = GTK_LIST_STORE(model);
gboolean valid;
// clear completion list from previous non-history entries
valid = gtk_tree_model_get_iter_first(model,&iter);
while(valid)
{
char* url;
int type;
gtk_tree_model_get(model,&iter, 0,&url, 1,&type, -1);
if (type != COMPLETION_HISTORY) {
valid = gtk_list_store_remove(list, &iter);
} else {
valid = gtk_tree_model_iter_next(model,&iter);
}
if( url ) g_free(url);
if( !valid ) break;
}
// add new non-history related matches
while( friends ){
LinphoneFriend* lf = friends->data;
if( lf ) {
const LinphoneAddress* la = linphone_friend_get_address(lf);
if( la ){
char *addr = linphone_address_as_string(la);
if( addr ){
ms_message("[LDAP]Insert match: %s", addr);
gtk_list_store_insert_with_values(list, &iter, -1,
0, addr,
1, COMPLETION_LDAP, -1);
ms_free(addr);
}
}
}
friends = friends->next;
}
gtk_entry_completion_complete(compl);
// save the number of LDAP results to better decide if new results should be fetched when search predicate gets bigger
gtk_object_set_data(GTK_OBJECT(uribar), "ldap_res_cout",
GINT_TO_POINTER(
linphone_ldap_contact_search_result_count(LINPHONE_LDAP_CONTACT_SEARCH(req))
)
);
// Gtk bug? we need to emit a "changed" signal so that the completion appears if
// the list of results was previously empty
g_signal_handlers_block_by_func(uribar, linphone_gtk_on_uribar_changed, NULL);
g_signal_emit_by_name(uribar, "changed");
g_signal_handlers_unblock_by_func(uribar, linphone_gtk_on_uribar_changed, NULL);
}
struct CompletionTimeout {
guint timeout_id;
};
static gboolean launch_contact_provider_search(void *userdata)
{
LinphoneLDAPContactProvider* ldap = linphone_gtk_get_ldap();
GtkWidget* uribar = GTK_WIDGET(userdata);
const gchar* predicate = gtk_entry_get_text(GTK_ENTRY(uribar));
gchar* previous_search = gtk_object_get_data(GTK_OBJECT(uribar), "previous_search");
unsigned int prev_res_count = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "ldap_res_cout"));
if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates
unsigned int max_res_count = linphone_ldap_contact_provider_get_max_result(ldap);
if( previous_search &&
(strstr(predicate, previous_search) == predicate) && // last search contained results from this one
(prev_res_count != max_res_count) ){ // and we didn't reach the max result limit
ms_message("Don't launch search on already searched data (current: %s, old search: %s), (%d/%d results)",
predicate, previous_search, prev_res_count, max_res_count);
return FALSE;
}
// save current search
if( previous_search ) ms_free(previous_search);
gtk_object_set_data(GTK_OBJECT(uribar), "previous_search", ms_strdup(predicate));
ms_message("launch_contact_provider_search");
LinphoneContactSearch* search =
BELLE_SIP_OBJECT_VPTR(ldap,LinphoneContactProvider)->begin_search(
LINPHONE_CONTACT_PROVIDER(ldap),
predicate,
on_contact_provider_search_results,
uribar);
if(search)
belle_sip_object_ref(search);
}
return FALSE;
}
void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data)
{
#ifdef BUILD_LDAP
gchar* text = gtk_editable_get_chars(uribar, 0,-1);
gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout"));
if( text ) g_free(text);
if( timeout != 0 ) {
g_source_remove(timeout);
}
timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar);
gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) );
#endif
}
bool_t linphone_gtk_video_enabled(void){
const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
return vpol->automatically_accept && vpol->automatically_initiate;
@ -1873,6 +2043,9 @@ static void linphone_gtk_quit(void){
g_source_remove_by_user_data(linphone_gtk_get_core());
#ifdef BUILD_WIZARD
linphone_gtk_close_assistant();
#endif
#ifdef BUILD_LDAP
linphone_gtk_set_ldap(NULL);
#endif
linphone_gtk_uninit_instance();
linphone_gtk_destroy_log_window();

View file

@ -1109,6 +1109,12 @@
<property name="position">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
@ -1547,8 +1553,8 @@
</child>
<child>
<object class="GtkButton" id="proxy_refresh_button">
<property name="can_focus">True</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="relief">none</property>
@ -1762,6 +1768,9 @@
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>

View file

@ -9,6 +9,12 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment10">
<property name="upper">500</property>
<property name="value">50</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment2">
<property name="lower">1</property>
<property name="upper">65535</property>
@ -54,6 +60,12 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment9">
<property name="upper">100</property>
<property name="value">10</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment_max_audio_port">
<property name="upper">65535</property>
<property name="step_increment">2</property>
@ -81,6 +93,23 @@
<property name="page_increment">10</property>
</object>
<object class="GtkListStore" id="liststore1"/>
<object class="GtkListStore" id="liststore2">
<columns>
<!-- column-name authmethod -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">anonymous</col>
</row>
<row>
<col id="0" translatable="yes">GSSAPI</col>
</row>
<row>
<col id="0" translatable="yes">SASL</col>
</row>
</data>
</object>
<object class="GtkListStore" id="model1">
<columns>
<!-- column-name gchararray -->
@ -2428,6 +2457,540 @@
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="ldap_tab">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">5</property>
<property name="n_columns">2</property>
<child>
<object class="GtkLabel" id="label41">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xpad">1</property>
<property name="label" translatable="yes">Server address:</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label43">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Authentication method:</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label44">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Username:</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label45">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="ldap_use_tls">
<property name="label" translatable="yes">Use TLS Connection</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_server">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_username">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_password">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="ldap_auth_method">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">liststore2</property>
<property name="row_span_column">0</property>
<property name="column_span_column">0</property>
<property name="active">0</property>
<child>
<object class="GtkCellRendererText" id="renderer1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label17">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Connection&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">5</property>
<property name="n_columns">2</property>
<child>
<object class="GtkLabel" id="label46">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Base object:</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label47">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Filter (%s for name):</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label48">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Name Attribute:</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label49">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">SIP address attribute:</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label50">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Attributes to query:</property>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_base_object">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_filter">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_name_attribute">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_sip_attribute">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ldap_attributes">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label37">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Search&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<child>
<object class="GtkLabel" id="label51">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Timeout for search:</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label52">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Max results:</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="ldap_timeout">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment9</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="ldap_max_results">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">3</property>
<property name="invisible_char">•</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
<property name="adjustment">adjustment10</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="ldap_deref_aliases">
<property name="label" translatable="yes">Follow Aliases</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label40">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Miscellaneous&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="ldap_save">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_ldap_save" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ldap_reset">
<property name="label" translatable="yes">Reset</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="linphone_gtk_ldap_reset" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="position">5</property>
</packing>
</child>
<child type="tab">
<object class="GtkHBox" id="hbox19">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-disconnect</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label16">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">LDAP</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">5</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>

View file

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphone.h"
#include "linphone_tunnel.h"
#include "lpconfig.h"
typedef enum {
CAP_IGNORE,
@ -59,6 +60,131 @@ static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices,
gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active);
}
static void linphone_gtk_ldap_load_settings(GtkWidget* param)
{
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
LpConfig* config = linphone_core_get_config(linphone_gtk_get_core());
LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap");
GtkEntry* entry;
GtkToggleButton* toggle;
GtkSpinButton* spin;
toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_use_tls"));
gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"use_tls", 0) );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://example.com") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_password"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"password", "") );
// TODO
// GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method"));
// gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "anonymous") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_filter"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"filter", "uid=*%s*") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_name_attribute"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"name_attribute", "cn") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_sip_attribute"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sip_attribute", "mobile") );
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_attributes"));
gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"attributes", "cn,givenName,sn,mobile,homePhone") );
toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_deref_aliases"));
gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"deref_aliases", 0) );
spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_max_results"));
gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"max_results", 50) );
spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout"));
gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) );
}
void linphone_gtk_ldap_reset(GtkWidget *tabmgr)
{
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
ms_message("RESET LDAP");
linphone_gtk_ldap_load_settings(pb);
}
void linphone_gtk_ldap_save(GtkWidget *tabmgr)
{
LinphoneCore *lc = linphone_gtk_get_core();
LpConfig* conf = linphone_core_get_config(lc);
LinphoneDictionary* dict = linphone_dictionary_new();
GtkWidget *mw = linphone_gtk_get_main_window();
GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters");
GtkEntry* entry;
GtkToggleButton* toggle;
GtkSpinButton* spin;
ms_message("SAVE LDAP");
toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_use_tls"));
linphone_dictionary_set_int(dict, "use_tls", gtk_toggle_button_get_active(toggle));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server"));
linphone_dictionary_set_string(dict, "server", gtk_entry_get_text(entry));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username"));
linphone_dictionary_set_string(dict, "username", gtk_entry_get_text(entry));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_password"));
linphone_dictionary_set_string(dict, "password", gtk_entry_get_text(entry));
GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method"));
linphone_dictionary_set_string(dict, "auth_method", gtk_combo_box_get_active_text(cbox));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object"));
linphone_dictionary_set_string(dict, "base_object", gtk_entry_get_text(entry));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_filter"));
linphone_dictionary_set_string(dict, "filter", gtk_entry_get_text(entry));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_name_attribute"));
linphone_dictionary_set_string(dict, "name_attribute", gtk_entry_get_text(entry));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_sip_attribute"));
linphone_dictionary_set_string(dict, "sip_attribute", gtk_entry_get_text(entry));
entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_attributes"));
linphone_dictionary_set_string(dict, "attributes", gtk_entry_get_text(entry));
toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_deref_aliases"));
linphone_dictionary_set_int(dict, "deref_aliases", gtk_toggle_button_get_active(toggle));
spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_max_results"));
linphone_dictionary_set_int(dict, "max_results", gtk_spin_button_get_value(spin) );
spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout"));
linphone_dictionary_set_int(dict, "timeout", gtk_spin_button_get_value(spin) );
ms_message("Create LDAP from config");
// create new LDAP according to the validated config
linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(lc, dict) );
// save the config to linphonerc:
lp_config_load_dict_to_section(conf, "ldap", dict);
}
void linphone_gtk_fill_video_sizes(GtkWidget *combo){
const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());;
int i,active=0;
@ -1301,6 +1427,15 @@ void linphone_gtk_show_parameters(void){
gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_label")), TRUE);
}
/* LDAP CONFIG */
#ifdef BUILD_LDAP
linphone_gtk_ldap_load_settings(pb);
#else
// hide the LDAP tab
GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1"));
gtk_notebook_remove_page(notebook,5);
#endif
gtk_widget_show(pb);
}

View file

@ -23,11 +23,11 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\
AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi
LDADD=$(top_builddir)/coreapi/liblinphone.la
LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS)
AM_LDFLAGS=$(CUNIT_LIBS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS)
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS)
test: liblinphone_tester
./liblinphone_tester --config $(abs_srcdir)

View file

@ -1053,7 +1053,6 @@ static void early_media_call_forking(void) {
linphone_core_use_files (marie1->lc,TRUE);
linphone_core_set_play_file(marie1->lc,ringbackpath);
linphone_core_enable_video(marie2->lc,TRUE,TRUE);
linphone_core_set_video_policy(marie2->lc,&pol);
linphone_core_set_audio_port_range(marie2->lc,40200,40300);