Use network log for LDAP operations output
[claws.git] / src / ldapquery.c
index ff5582649addb916ea493e40145268bc0f43d145..7f0d2930ea972e2cc7f56e41fb4094a2ef76f832 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 2003-2007 Match Grun and the Claws Mail team
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2003-2018 Match Grun and the Claws Mail team
  *
  * 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
@@ -14,7 +14,6 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
- * 
  */
 
 /*
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
+#include "claws-features.h"
 #endif
 
 #ifdef USE_LDAP
 
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <sys/time.h>
 #include <string.h>
-#include <lber.h>
 
+#include "defs.h"
 #include "ldaputil.h"
 #include "ldapquery.h"
 #include "ldapctrl.h"
+#include "ldapserver.h"
 #include "mgutils.h"
 
 #include "addritem.h"
 #include "addrcache.h"
 #include "common/utils.h"
+#include "log.h"
 
 /*
  * Key for thread specific data.
@@ -104,7 +107,7 @@ LdapQuery *ldapqry_create( void ) {
  * \param ctl Control object.
  */
 void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
        qry->control = ctl;
 }
 
@@ -114,9 +117,10 @@ void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
  * \param value Name.
  */
 void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
-       g_return_if_fail( qry != NULL );
-       g_return_if_fail( ADDRQUERY_OBJECT(qry) != NULL );
+       cm_return_if_fail( qry != NULL );
        ADDRQUERY_NAME(qry) = mgu_replace_string( ADDRQUERY_NAME(qry), value );
+       if (ADDRQUERY_NAME(qry) == NULL)
+               return;
        g_strstrip( ADDRQUERY_NAME(qry) );
        debug_print("set name: %s\n", ADDRQUERY_NAME(qry));
 }
@@ -127,9 +131,10 @@ void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
  * \param value 
  */
 void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
-       g_return_if_fail( qry != NULL );
-       g_return_if_fail( ADDRQUERY_OBJECT(qry) != NULL );
+       cm_return_if_fail( qry != NULL );
        ADDRQUERY_SEARCHVALUE(qry) = mgu_replace_string( ADDRQUERY_SEARCHVALUE(qry), value );
+       if (ADDRQUERY_SEARCHVALUE(qry) == NULL)
+               return;
        g_strstrip( ADDRQUERY_SEARCHVALUE(qry) );
        debug_print("search value: %s\n", ADDRQUERY_SEARCHVALUE(qry));
 }
@@ -156,8 +161,7 @@ void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
  * \param value Type.
  */
 void ldapqry_set_search_type( LdapQuery *qry, const AddrSearchType value ) {
-       g_return_if_fail( qry != NULL );
-       g_return_if_fail( ADDRQUERY_OBJECT(qry) != NULL );
+       cm_return_if_fail( qry != NULL );
        ADDRQUERY_SEARCHTYPE(qry) = value;
 }
 
@@ -167,8 +171,7 @@ void ldapqry_set_search_type( LdapQuery *qry, const AddrSearchType value ) {
  * \param value ID for the query.
  */
 void ldapqry_set_query_id( LdapQuery* qry, const gint value ) {
-       g_return_if_fail( qry != NULL );
-       g_return_if_fail( ADDRQUERY_OBJECT(qry) != NULL );
+       cm_return_if_fail( qry != NULL );
        ADDRQUERY_ID(qry) = value;
 }
 
@@ -225,7 +228,7 @@ void ldapqry_set_callback_end( LdapQuery *qry, void *func ) {
  * \param value Value of stop flag.
  */
 void ldapqry_set_stop_flag( LdapQuery *qry, const gboolean value ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
        pthread_mutex_lock( qry->mutexStop );
        qry->stopFlag = value;
@@ -240,7 +243,7 @@ void ldapqry_set_stop_flag( LdapQuery *qry, const gboolean value ) {
  */
 static gboolean ldapqry_get_stop_flag( LdapQuery *qry ) {
        gboolean value;
-       g_return_val_if_fail( qry != NULL, TRUE );
+       cm_return_val_if_fail( qry != NULL, TRUE );
 
        pthread_mutex_lock( qry->mutexStop );
        value = qry->stopFlag;
@@ -254,7 +257,7 @@ static gboolean ldapqry_get_stop_flag( LdapQuery *qry ) {
  * \param value Value of busy flag.
  */
 static void ldapqry_set_busy_flag( LdapQuery *qry, const gboolean value ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
        if (qry->mutexBusy == NULL)
                return; /* exiting, mutex already freed */
 
@@ -271,7 +274,7 @@ static void ldapqry_set_busy_flag( LdapQuery *qry, const gboolean value ) {
  */
 static gboolean ldapqry_get_busy_flag( LdapQuery *qry ) {
        gboolean value;
-       g_return_val_if_fail( qry != NULL, FALSE );
+       cm_return_val_if_fail( qry != NULL, FALSE );
 
        pthread_mutex_lock( qry->mutexBusy );
        value = qry->busyFlag;
@@ -285,7 +288,7 @@ static gboolean ldapqry_get_busy_flag( LdapQuery *qry ) {
  * \param value Value of aged flag.
  */
 static void ldapqry_set_aged_flag( LdapQuery *qry, const gboolean value ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
        qry->agedFlag = value;
 }
 
@@ -294,7 +297,7 @@ static void ldapqry_set_aged_flag( LdapQuery *qry, const gboolean value ) {
  * \param qry Query object.
  */
 static void ldapqry_clear( LdapQuery *qry ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
        /* Free internal stuff */
        g_free( ADDRQUERY_NAME(qry) );
@@ -324,7 +327,7 @@ static void ldapqry_clear( LdapQuery *qry ) {
  * \param qry Query object to process.
  */
 void ldapqry_free( LdapQuery *qry ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
        /* Clear out internal members */
        ADDRQUERY_TYPE(qry) = ADDRQUERY_NONE;
@@ -414,9 +417,19 @@ static GSList *ldapqry_add_single_value( LDAP *ld, LDAPMessage *entry, char *att
 
        if( ( vals = ldap_get_values_len( ld, entry, attr ) ) != NULL ) {
                if( vals[0] != NULL ) {
-                       debug_print("sv\t%s: %s\n", attr?attr:"null",
-                                       vals[0]->bv_val?vals[0]->bv_val:"null");
-                       list = g_slist_append( list, g_strndup( vals[0]->bv_val, vals[0]->bv_len ));
+                       if (strcmp(attr, "jpegPhoto")) {
+                               debug_print("sv\t%s: %s\n", attr?attr:"null",
+                                               vals[0]->bv_val?vals[0]->bv_val:"null");
+                               list = g_slist_append( list, g_strndup( vals[0]->bv_val, vals[0]->bv_len ));
+                       } else {
+                               char *file = get_tmp_file();
+                               FILE *fp = g_fopen(file, "wb");
+                               if (fp) {
+                                       fwrite(vals[0]->bv_val, 1, vals[0]->bv_len, fp);
+                                       fclose(fp);
+                               }
+                               list = g_slist_append( list, file);
+                       }
                }
        }
        ldap_value_free_len( vals );
@@ -455,6 +468,7 @@ static GList *ldapqry_build_items_fl(
        ItemPerson *person;
        ItemEMail *email;
        ItemFolder *folder;
+       gchar *picfile = NULL;
        GList *listReturn = NULL;
 
        folder = ADDRQUERY_FOLDER(qry);
@@ -494,7 +508,7 @@ static GList *ldapqry_build_items_fl(
                                }
                        }
                        if( fullName ) {
-                               g_strchug( fullName ); g_strchomp( fullName );
+                               g_strstrip( fullName );
                                allocated = TRUE;
                        }
                }
@@ -511,7 +525,24 @@ static GList *ldapqry_build_items_fl(
        
        for (cur = attributes; cur; cur = cur->next) {
                UserAttribute *attrib = addritem_copy_attribute((UserAttribute *)cur->data);
-               addritem_person_add_attribute( person, attrib );
+               if (attrib->name && strcmp(attrib->name, "jpegPhoto")) {
+                       addritem_person_add_attribute( person, attrib );
+               } else {
+                       if (qry->server && qry->server->control) {
+                               gchar *dir = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, 
+                                                       ADDRBOOK_DIR, G_DIR_SEPARATOR_S, NULL );
+                               gchar *filename = g_strdup_printf("%s-%s-%s",
+                                       qry->server->control->hostName?qry->server->control->hostName:"nohost", 
+                                       qry->server->control->baseDN?qry->server->control->baseDN:"nobase", 
+                                       dn);
+                               picfile = g_strdup_printf("%s%s.png", dir, filename);
+                               addritem_person_set_picture( person, filename );
+                               rename_force(attrib->value, picfile);
+                               g_free(filename);
+                               g_free(picfile);
+                               g_free(dir);
+                       }
+               }
        }
        
        addrcache_folder_add_person( cache, ADDRQUERY_FOLDER(qry), person );
@@ -610,7 +641,7 @@ static GList *ldapqry_process_single_entry(
        if( ber != NULL ) {
                ber_free( ber, 0 );
        }
-       g_free( dnEntry );
+       ldap_memfree( dnEntry );
 
        return listReturn;
 }
@@ -659,9 +690,6 @@ void ldapqry_touch( LdapQuery *qry ) {
 static gint ldapqry_connect( LdapQuery *qry ) {
        LdapControl *ctl;
        LDAP *ld = NULL;
-       gint rc;
-       gint version;
-       gchar *uri = NULL;
 
        /* Initialize connection */
        if (debug_get_mode()) {
@@ -678,13 +706,7 @@ static gint ldapqry_connect( LdapQuery *qry ) {
        qry->elapsedTime = -1;
        ADDRQUERY_RETVAL(qry) = LDAPRC_INIT;
 
-       ldapsrv_set_options (ctl->timeOut, NULL);
-
-       uri = g_strdup_printf("ldap%s://%s:%d",
-                               ctl->enableSSL?"s":"",
-                               ctl->hostName, ctl->port);
-       ldap_initialize(&ld, uri);
-       g_free(uri);
+       ld = ldapsvr_connect(ctl);
 
        if (ld == NULL)
                return ADDRQUERY_RETVAL(qry);
@@ -699,42 +721,6 @@ static gint ldapqry_connect( LdapQuery *qry ) {
        debug_print("connected to LDAP host %s on port %d\n",
                        ctl->hostName?ctl->hostName:"null", ctl->port);
 
-#ifdef USE_LDAP_TLS
-       /* Handle TLS */
-       version = LDAP_VERSION3;
-       rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
-       if( rc == LDAP_OPT_SUCCESS ) {
-               ctl->version = LDAP_VERSION3;
-       }
-
-       if( ctl->version == LDAP_VERSION3 ) {
-               if( ctl->enableTLS && !ctl->enableSSL ) {
-                       ADDRQUERY_RETVAL(qry) = LDAPRC_TLS;
-                       rc = ldap_start_tls_s( ld, NULL, NULL );
-                       
-                       debug_print("rc=%d\n", rc);
-                       debug_print("LDAP Status: set_option: %s\n", ldap_err2string(rc));
-
-                       if( rc != LDAP_SUCCESS ) {
-                               return ADDRQUERY_RETVAL(qry);
-                       }
-               }
-       }
-#endif
-
-       /* Bind to the server, if required */
-       ADDRQUERY_RETVAL(qry) = LDAPRC_BIND;
-       if( ctl->bindDN ) {
-               if( * ctl->bindDN != '\0' ) {
-                       debug_print("binding...\n");
-                       rc = claws_ldap_simple_bind_s( ld, ctl->bindDN, ctl->bindPass );
-                       debug_print("rc=%d\n", rc);
-                       if( rc != LDAP_SUCCESS ) {
-                               debug_print("LDAP Error: ldap_simple_bind_s: %s\n",     ldap_err2string(rc));
-                               return ADDRQUERY_RETVAL(qry);
-                       }
-               }
-       }
        ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
        if( ldapqry_get_stop_flag( qry ) ) {
                return ADDRQUERY_RETVAL(qry);
@@ -752,8 +738,17 @@ static gint ldapqry_connect( LdapQuery *qry ) {
  * \return Error/status code.
  */
 static gint ldapqry_disconnect( LdapQuery *qry ) {
+       gint rc;
        /* Disconnect */
-       if( qry->ldap ) ldap_unbind_ext( qry->ldap, NULL, NULL );
+       if( qry->ldap ) {
+               rc = ldap_unbind_ext( qry->ldap, NULL, NULL );
+               if (rc != LDAP_SUCCESS) {
+                       log_error(LOG_PROTOCOL, _("LDAP error (unbind): %d (%s)\n"),
+                                       rc, ldaputil_get_error(qry->ldap));
+               } else {
+                       log_message(LOG_PROTOCOL, _("LDAP (unbind): successful\n"));
+               }
+       }
        qry->ldap = NULL;
 
        ldapqry_touch( qry );
@@ -775,7 +770,7 @@ static gint ldapqry_disconnect( LdapQuery *qry ) {
 static gint ldapqry_search_retrieve( LdapQuery *qry ) {
        LdapControl *ctl;
        LDAP *ld;
-       LDAPMessage *result, *e = NULL;
+       LDAPMessage *result = NULL, *e = NULL;
        char **attribs;
        gchar *criteria;
        gboolean searchFlag;
@@ -809,12 +804,12 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) {
        ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
        rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
                attribs, 0, NULL, NULL, &timeout, 0, &result );
-       debug_print("LDAP Error: ldap_search_st: %d\n", rc);
-       debug_print("LDAP Error: ldap_search_st: %s\n", ldap_err2string(rc));
+       debug_print("LDAP ldap_search_ext_s: %d (%s)\n", rc, ldaputil_get_error(ld));
        ldapctl_free_attribute_array( attribs );
        g_free( criteria );
        criteria = NULL;
        if( rc == LDAP_TIMEOUT ) {
+               log_warning(LOG_PROTOCOL, _("LDAP (search): timeout\n"));
                return ADDRQUERY_RETVAL(qry);
        }
        ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
@@ -822,22 +817,28 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) {
        /* Test valid returns */
        searchFlag = FALSE;
        if( rc == LDAP_ADMINLIMIT_EXCEEDED ) {
+               log_warning(LOG_PROTOCOL, _("LDAP (search): server limits exceeded\n"));
                searchFlag = TRUE;
        }
        else if( rc == LDAP_SUCCESS ) {
+               log_message(LOG_PROTOCOL, _("LDAP (search): successful\n"));
                searchFlag = TRUE;
        }
-       else if( rc == LDAP_PARTIAL_RESULTS ) {
+       else if( rc == LDAP_PARTIAL_RESULTS || (result && ldap_count_entries(ld, result) > 0) ) {
+               log_message(LOG_PROTOCOL, _("LDAP (search): successful (partial results)\n"));
                searchFlag = TRUE;
        }
        else {
-               debug_print("LDAP Error: ldap_search_st: %d\n", rc);
-               debug_print("LDAP Error: ldap_search_st: %s\n", ldap_err2string(rc));
+               log_error(LOG_PROTOCOL, _("LDAP error (search): %d (%s)\n"), rc, ldaputil_get_error(ld));
                return ADDRQUERY_RETVAL(qry);
        }
        ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
 
+#ifdef G_OS_WIN32
+       debug_print("Total results are: %lu\n", ldap_count_entries(ld, result));
+#else
        debug_print("Total results are: %d\n", ldap_count_entries(ld, result));
+#endif
 
        /* Process results */
        first = TRUE;
@@ -868,19 +869,10 @@ static gint ldapqry_search_retrieve( LdapQuery *qry ) {
                listEMail = ldapqry_process_single_entry( cache, qry, ld, e );
 
                /* Process callback */
-               if( qry->callBackEntry ) {
+               if( qry->callBackEntry )
                        qry->callBackEntry( qry, ADDRQUERY_ID(qry), listEMail, qry->data );
-               }
-               else {
-                       /*if (debug_get_mode()) {
-                               GList *node = listEMail;
-                               while (node) {
-                                       addritem_print_item_email(node->data, stdout);
-                                       node = g_list_next(node);
-                               }
-                       }*/
+               else
                        g_list_free( listEMail );
-               }
                pthread_mutex_unlock( qry->mutexEntry );
        }
 
@@ -934,8 +926,8 @@ static gint ldapqry_perform_locate( LdapQuery *qry );
 static gint ldapqry_search( LdapQuery *qry ) {
        gint retVal;
 
-       g_return_val_if_fail( qry != NULL, -1 );
-       g_return_val_if_fail( qry->control != NULL, -1 );
+       cm_return_val_if_fail( qry != NULL, -1 );
+       cm_return_val_if_fail( qry->control != NULL, -1 );
 
        ldapqry_touch( qry );
        qry->completed = FALSE;
@@ -986,8 +978,8 @@ static gint ldapqry_search( LdapQuery *qry ) {
  * \return Error/status code.
  */
 gint ldapqry_read_data_th( LdapQuery *qry ) {
-       g_return_val_if_fail( qry != NULL, -1 );
-       g_return_val_if_fail( qry->control != NULL, -1 );
+       cm_return_val_if_fail( qry != NULL, -1 );
+       cm_return_val_if_fail( qry->control != NULL, -1 );
 
        ldapqry_set_stop_flag( qry, FALSE );
        ldapqry_touch( qry );
@@ -998,8 +990,12 @@ gint ldapqry_read_data_th( LdapQuery *qry ) {
                        qry->thread = g_malloc0( sizeof( pthread_t ) );
 
                        /* Setup thread */                      
-                       pthread_create( qry->thread, NULL,
-                               (void *) ldapqry_search, (void *) qry );
+                       if (pthread_create( qry->thread, NULL,
+                               (void *) ldapqry_search, (void *) qry ) != 0) {
+                               g_free(qry->thread);
+                               qry->thread = NULL;
+                               ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
+                       }
                }
        }
        return ADDRQUERY_RETVAL(qry);
@@ -1014,10 +1010,7 @@ static void ldapqry_destroyer( void * ptr ) {
        LdapQuery *qry;
 
        qry = ( LdapQuery * ) ptr;
-       g_return_if_fail( qry != NULL );
-
-       debug_print("ldapqry_destroyer::%d::%s\n", (int) pthread_self(),
-                       ADDRQUERY_NAME(qry)?ADDRQUERY_NAME(qry):"null");
+       cm_return_if_fail( qry != NULL );
 
        /* Perform any destruction here */
        if( qry->control != NULL ) {
@@ -1033,9 +1026,8 @@ static void ldapqry_destroyer( void * ptr ) {
  * \param qry Query object to process.
  */
 void ldapqry_cancel( LdapQuery *qry ) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
-       debug_print("cancelling::%d::%s\n", (int) pthread_self(), ADDRQUERY_NAME(qry));
        if( ldapqry_get_busy_flag( qry ) ) {
                if( qry->thread ) {
                        debug_print("calling pthread_cancel\n");
@@ -1066,7 +1058,7 @@ void ldapqry_initialize( void ) {
 void ldapqry_age( LdapQuery *qry, gint maxAge ) {
        gint age;
 
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
        /* Limit the time that queries can hang around */       
        if( maxAge < 1 ) maxAge = LDAPCTL_MAX_QUERY_AGE;
@@ -1086,7 +1078,7 @@ void ldapqry_delete_folder( LdapQuery *qry ) {
        AddressCache *cache;
        ItemFolder *folder;
 
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
        folder = ADDRQUERY_FOLDER(qry);
        if( folder ) {
@@ -1238,11 +1230,20 @@ static gint ldapqry_locate_retrieve( LdapQuery *qry ) {
        }
        ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
        if( rc != LDAP_SUCCESS ) {
-               debug_print("LDAP Error: ldap_search_st: %s\n", ldap_err2string(rc));
+               log_error(LOG_PROTOCOL, _("LDAP error (search): %d (%s)\n"),
+                               rc, ldaputil_get_error(ld));
+               debug_print("LDAP Error: ldap_search_ext_s: %d (%s)\n",
+                               rc, ldaputil_get_error(ld));
                return ADDRQUERY_RETVAL(qry);
+       } else {
+               log_message(LOG_PROTOCOL, _("LDAP (search): successful\n"));
        }
 
+#ifdef G_OS_WIN32
+       debug_print("Total results are: %lu\n", ldap_count_entries(ld, result));
+#else
        debug_print("Total results are: %d\n", ldap_count_entries(ld, result));
+#endif
 
        /* Process results */
        ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
@@ -1347,7 +1348,7 @@ gboolean ldapquery_remove_results( LdapQuery *qry ) {
 }
 
 void ldapqry_print(LdapQuery *qry, FILE *stream) {
-       g_return_if_fail( qry != NULL );
+       cm_return_if_fail( qry != NULL );
 
        ldapsvr_print_data(qry->server, stream);
        ldapctl_print(qry->control, stream);