2007-05-31 [colin] 2.9.2cvs24
[claws.git] / src / addressbook.c
index cfb0c1bce628a1e35c8b4d95c609381a8f420ded..b563ae2d4a917380a4199dc668f5db6477e2ca29 100644 (file)
@@ -89,6 +89,7 @@
 #include <pthread.h>
 #include "ldapserver.h"
 #include "editldap.h"
+#include "ldapupdate.h"
 
 #define ADDRESSBOOK_LDAP_BUSYMSG "Busy"
 #endif
@@ -534,17 +535,21 @@ static ErrMsgTableEntry _lutErrorsGeneral_[] = {
  * Lookup table of error messages for LDAP errors.
  */
 static ErrMsgTableEntry _lutErrorsLDAP_[] = {
-       { LDAPRC_SUCCESS,       N_("Success") },
-       { LDAPRC_CONNECT,       N_("Error connecting to LDAP server") },
-       { LDAPRC_INIT,          N_("Error initializing LDAP") },
-       { LDAPRC_BIND,          N_("Error binding to LDAP server") },
-       { LDAPRC_SEARCH,        N_("Error searching LDAP database") },
-       { LDAPRC_TIMEOUT,       N_("Timeout performing LDAP operation") },
-       { LDAPRC_CRITERIA,      N_("Error in LDAP search criteria") },
-       { LDAPRC_NOENTRIES,     N_("No LDAP entries found for search criteria") },
-       { LDAPRC_STOP_FLAG,     N_("LDAP search terminated on request") },
-       { LDAPRC_TLS,           N_("Error starting TLS connection") },
-       { 0,                    NULL }
+       { LDAPRC_SUCCESS,                       N_("Success") },
+       { LDAPRC_CONNECT,                       N_("Error connecting to LDAP server") },
+       { LDAPRC_INIT,                          N_("Error initializing LDAP") },
+       { LDAPRC_BIND,                          N_("Error binding to LDAP server") },
+       { LDAPRC_SEARCH,                        N_("Error searching LDAP database") },
+       { LDAPRC_TIMEOUT,                       N_("Timeout performing LDAP operation") },
+       { LDAPRC_CRITERIA,                      N_("Error in LDAP search criteria") },
+       { LDAPRC_NOENTRIES,                     N_("No LDAP entries found for search criteria") },
+       { LDAPRC_STOP_FLAG,                     N_("LDAP search terminated on request") },
+       { LDAPRC_TLS,                           N_("Error starting TLS connection") },
+       { LDAPRC_NODN,                          N_("Distinguised Name (dn) is missing") },
+       { LDAPRC_NAMING_VIOLATION,              N_("Missing required information") },
+       { LDAPRC_ALREADY_EXIST,                 N_("Another contact exists with that key") },
+       { LDAPRC_STRONG_AUTH,                   N_("Strong(er) authentication required") },
+       { 0,                                    NULL }
 };
 #endif
 
@@ -1126,15 +1131,15 @@ static void addressbook_create(void)
                         G_CALLBACK(addressbook_lup_clicked), NULL);
 
        to_btn = gtk_button_new_with_label
-               (prefs_common.trans_hdr ? _("To:") : "To:");
+               (prefs_common_translated_header_name("To:"));
        GTK_WIDGET_SET_FLAGS(to_btn, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(hbbox), to_btn, TRUE, TRUE, 0);
        cc_btn = gtk_button_new_with_label
-               (prefs_common.trans_hdr ? _("Cc:") : "Cc:");
+               (prefs_common_translated_header_name("Cc:"));
        GTK_WIDGET_SET_FLAGS(cc_btn, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(hbbox), cc_btn, TRUE, TRUE, 0);
        bcc_btn = gtk_button_new_with_label
-               (prefs_common.trans_hdr ? _("Bcc:") : "Bcc:");
+               (prefs_common_translated_header_name("Bcc:"));
        GTK_WIDGET_SET_FLAGS(bcc_btn, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(hbbox), bcc_btn, TRUE, TRUE, 0);
 
@@ -1456,10 +1461,18 @@ static void addressbook_del_clicked(GtkButton *button, gpointer data)
                        }
                        else if( aio->type == ADDR_ITEM_PERSON ) {
                                ItemPerson *item = ( ItemPerson * ) aio;
+                               item->status = DELETE_ENTRY; 
                                addressbook_folder_remove_one_person( clist, item );
                                if (pobj->type == ADDR_ITEM_FOLDER)
                                        addritem_folder_remove_person(ADAPTER_FOLDER(pobj)->itemFolder, item);
                                item = addrbook_remove_person( abf, item );
+#ifdef USE_LDAP
+                               if (ds->type == ADDR_IF_LDAP) {
+                                       LdapServer *server = ds->rawDataSource;
+                                       ldapsvr_set_modified(server, TRUE);
+                                       ldapsvr_update_book(server, item);
+                               }
+#endif
                                if( item ) {
                                        addritem_free_item_person( item );
                                }
@@ -1881,7 +1894,8 @@ static void addressbook_list_menu_setup( void ) {
                iface = ds->interface;
                if( ! iface->readOnly ) {
                        menu_set_sensitive( addrbook.list_factory, "/New Address", TRUE );
-                       menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
+                       if (iface->type != ADDR_IF_LDAP)
+                               menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
                        gtk_widget_set_sensitive( addrbook.reg_btn, TRUE );
                        if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
                        if( ! addrselect_test_empty( _addressSelect_ ) ) canCut = TRUE;
@@ -1892,6 +1906,8 @@ static void addressbook_list_menu_setup( void ) {
        else if( pobj->type != ADDR_INTERFACE ) {
                /* Parent object is not an interface */
                ds = addressbook_find_datasource( addrbook.treeSelected );
+               if (!ds)
+                       return;
                iface = ds->interface;
                if( ! iface->readOnly ) {
                        /* Folder or group */
@@ -1902,7 +1918,8 @@ static void addressbook_list_menu_setup( void ) {
                        }
                        /* Folder */
                        if( pobj->type == ADDR_ITEM_FOLDER ) {
-                               menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
+                               if (iface->type != ADDR_IF_LDAP)
+                                       menu_set_sensitive( addrbook.list_factory, "/New Group", TRUE );
                                if( obj ) canEdit = TRUE;
                        }
                        if( ! addrclip_is_empty( _clipBoard_ ) ) canPaste = TRUE;
@@ -1912,7 +1929,7 @@ static void addressbook_list_menu_setup( void ) {
                if( iface->type == ADDR_IF_LDAP ) {
                        if( obj ) canBrowse = TRUE;
                        canEdit = TRUE;
-                       canDelete = FALSE;
+                       canDelete = TRUE;
                }
        }
        if( ! addrselect_test_empty( _addressSelect_ ) ) canCopy = TRUE;
@@ -2849,6 +2866,7 @@ static void addressbook_treenode_delete_cb(
 static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
 {
        if( person && addrbook.treeSelected == addrbook.opened ) {
+               person->status = ADD_ENTRY;
                gtk_clist_unselect_all( GTK_CLIST(addrbook.clist) );
                addressbook_folder_refresh_one_person(
                        GTK_CTREE(addrbook.clist), person );
@@ -2859,6 +2877,7 @@ static void addressbook_new_address_from_book_post_cb( ItemPerson *person )
 static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
 {
        if( person && addrbook.treeSelected == addrbook.opened) {
+               person->status = ADD_ENTRY;
                gtk_sctree_select( GTK_SCTREE(addrbook.ctree), addrbook.opened );
                addressbook_set_clist(
                        gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree),
@@ -2868,26 +2887,171 @@ static void addressbook_new_address_from_folder_post_cb( ItemPerson *person )
        addressbook_address_list_set_focus();
 }
 
+/**
+ * Label (a format string) that is used to name each folder.
+ */
+static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
+
+/**
+ * Search ctree widget callback function.
+ * \param  pA Pointer to node.
+ * \param  pB Pointer to data item being sought.
+ * \return Zero (0) if folder found.
+ */
+static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
+       AddressObject *aoA;
+
+       aoA = ( AddressObject * ) pA;
+       if( aoA->type == ADDR_ITEM_FOLDER ) {
+               ItemFolder *folder, *fld;
+
+               fld = ADAPTER_FOLDER(aoA)->itemFolder;
+               folder = ( ItemFolder * ) pB;
+               if( fld == folder ) return 0;   /* Found folder */
+       }
+       return 1;
+}
+
+static ItemFolder * addressbook_setup_subf(
+               AddressDataSource *ds, gchar *title,
+               GtkCTreeNode *pNode )
+{
+       AddrBookBase *adbase;
+       AddressCache *cache;
+       ItemFolder *folder;
+       GtkCTree *ctree;
+       GtkCTreeNode *nNode;
+       gchar *name;
+       AddressObjectType aoType = ADDR_NONE;
+       GList *children;
+       /* Setup a query */
+       if( *title == '\0' || strlen( title ) < 1 ) return NULL;
+
+       if( ds->type == ADDR_IF_LDAP ) {
+#if USE_LDAP
+               aoType = ADDR_LDAP_QUERY;
+#endif
+       }
+       else {
+               return NULL;
+       }
+
+       ctree = GTK_CTREE(addrbook.ctree);
+       /* Get reference to address cache */    
+       adbase = ( AddrBookBase * ) ds->rawDataSource;
+       cache = adbase->addressCache;
+       
+       if ((children = addrcache_get_list_folder(cache)) != NULL) {
+               GList *cur = children;
+               for (; cur; cur = cur->next) {
+                       ItemFolder *child = (ItemFolder *) cur->data;
+                       if (!strcmp2(ADDRITEM_NAME(child), title)) {
+                               nNode = gtk_ctree_find_by_row_data_custom(
+                                       ctree, NULL, child,
+                                       addressbook_treenode_find_folder_cb );
+                               if( nNode ) {
+                                       addrindex_remove_results( ds, child );
+                                       while( child->listPerson ) {
+                                               ItemPerson *item = ( ItemPerson * ) child->listPerson->data;
+                                               item = addrcache_remove_person( cache, item );
+                                               if( item ) {
+                                                       addritem_free_item_person( item );
+                                                       item = NULL;
+                                               }
+                                       }
+                                       gtk_sctree_select( GTK_SCTREE(ctree), nNode );
+                                       addrbook.treeSelected = nNode;
+                               }       
+                               return child;
+                       }
+               }
+       }
+       
+       /* Create a folder */
+       folder = addrcache_add_new_folder( cache, NULL );
+       name = g_strdup_printf( "%s", title );
+       addritem_folder_set_name( folder, name );
+       addritem_folder_set_remarks( folder, "" );
+       g_free( name );
+
+       /* Now let's see the folder */
+       nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
+       gtk_ctree_expand( ctree, pNode );
+       if( nNode ) {
+               gtk_sctree_select( GTK_SCTREE(ctree), nNode );
+               addrbook.treeSelected = nNode;
+               return folder;
+       }
+       return NULL;
+}
+
 static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *widget ) {
        AddressObject *pobj = NULL;
        AddressDataSource *ds = NULL;
        AddressBookFile *abf = NULL;
-
+       debug_print("adding address\n");
        pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
-       if( pobj == NULL ) return;
+       if( pobj == NULL ) {
+               debug_print("no row data\n");
+               return;
+       }
        ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
-       if( ds == NULL ) return;
+       if( ds == NULL ) {
+               debug_print("no datasource\n");
+               return;
+       }
 
        abf = ds->rawDataSource;
-       if( abf == NULL ) return;
+       if( abf == NULL ) {
+               printf("no addressbook file\n");
+               return;
+       }
 
        if( pobj->type == ADDR_DATASOURCE ) {
-               if( ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ) {
-                       /* New address */
-                       ItemPerson *person = addressbook_edit_person( abf, NULL, NULL, FALSE,
-                                                                                                                 addrbook.editaddress_vbox,
-                                                                                                                 addressbook_new_address_from_book_post_cb,
-                                                                                                                 TRUE );
+               if (ADAPTER_DSOURCE(pobj)->subType == ADDR_BOOK ||
+                   ADAPTER_DSOURCE(pobj)->subType == ADDR_LDAP) {
+                       ItemPerson *person;
+                       ItemFolder *folder = NULL;
+#ifdef USE_LDAP
+                       if (abf->type == ADDR_IF_LDAP) {
+                               GtkCTreeNode *parentNode;
+                               ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
+                               if( ds == NULL ) return;
+
+                               /* We must have a datasource that is an external interface */
+                               if( ! ds->interface->haveLibrary ) return;
+                               if( ! ds->interface->externalQuery ) return;
+
+                               if( pobj->type == ADDR_ITEM_FOLDER ) {
+                                       parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
+                               }
+                               else {
+                                       parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
+                               }
+                               folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
+
+                               pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
+                               ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
+                               abf = ds->rawDataSource;
+                       }
+#endif
+                       person = addressbook_edit_person( abf, folder, NULL, FALSE,
+                                                                 addrbook.editaddress_vbox,
+                                                                 addressbook_new_address_from_book_post_cb,
+                                                                 TRUE );
+#ifdef USE_LDAP
+                       if (abf->type == ADDR_IF_LDAP) {
+                               LdapServer *server = ds->rawDataSource;
+                               ldapsvr_set_modified(server, TRUE);
+                               ldapsvr_update_book(server, NULL);
+                               if (server->retVal != LDAPRC_SUCCESS) {
+                                       alertpanel( _("Add address(es)"),
+                                               addressbook_err2string(_lutErrorsLDAP_, server->retVal),
+                                               GTK_STOCK_CLOSE, NULL, NULL );
+                                       return;
+                               }
+                       }
+#endif
                        if (prefs_common.addressbook_use_editaddress_dialog)
                                addressbook_new_address_from_book_post_cb( person );
                }
@@ -2895,10 +3059,48 @@ static void addressbook_new_address_cb( gpointer data, guint action, GtkWidget *
        else if( pobj->type == ADDR_ITEM_FOLDER ) {
                /* New address */
                ItemFolder *folder = ADAPTER_FOLDER(pobj)->itemFolder;
-               ItemPerson *person = addressbook_edit_person( abf, folder, NULL, FALSE,
-                                                                                                         addrbook.editaddress_vbox,
-                                                                                                         addressbook_new_address_from_folder_post_cb,
-                                                                                                         TRUE );
+               ItemPerson *person;
+#ifdef USE_LDAP
+               if (abf->type == ADDR_IF_LDAP) {
+                       GtkCTreeNode *parentNode;
+                       ds = addressbook_find_datasource( GTK_CTREE_NODE( addrbook.treeSelected ) );
+                       if( ds == NULL ) return;
+
+                       /* We must have a datasource that is an external interface */
+                       if( ! ds->interface->haveLibrary ) return;
+                       if( ! ds->interface->externalQuery ) return;
+
+                       if( pobj->type == ADDR_ITEM_FOLDER ) {
+                               parentNode = GTK_CTREE_ROW(GTK_CTREE_NODE( addrbook.treeSelected ) )->parent;
+                       }
+                       else {
+                               parentNode = GTK_CTREE_NODE( addrbook.treeSelected );
+                       }
+                       folder = addressbook_setup_subf( ds, _("New Contacts"), parentNode );
+                       if (!folder)
+                               return;
+                       pobj = gtk_ctree_node_get_row_data(GTK_CTREE(addrbook.ctree), addrbook.treeSelected);
+                       ds = addressbook_find_datasource( GTK_CTREE_NODE(addrbook.treeSelected) );
+                       abf = ds->rawDataSource;
+               }
+#endif
+               person = addressbook_edit_person( abf, folder, NULL, FALSE,
+                                                         addrbook.editaddress_vbox,
+                                                         addressbook_new_address_from_folder_post_cb,
+                                                         TRUE );
+#ifdef USE_LDAP
+               if (abf->type == ADDR_IF_LDAP) {
+                       LdapServer *server = ds->rawDataSource;
+                       ldapsvr_set_modified(server, TRUE);
+                       ldapsvr_update_book(server, NULL);
+                       if (server->retVal != LDAPRC_SUCCESS) {
+                               alertpanel( _("Add address(es)"),
+                                               addressbook_err2string(_lutErrorsLDAP_, server->retVal),
+                                       GTK_STOCK_CLOSE, NULL, NULL );
+                               return;
+                       }
+               }
+#endif
                if (prefs_common.addressbook_use_editaddress_dialog)
                        addressbook_new_address_from_folder_post_cb( person );
        }
@@ -2951,7 +3153,7 @@ static AddressBookFile *addressbook_get_book_file() {
 
        ds = addressbook_find_datasource( addrbook.treeSelected );
        if( ds == NULL ) return NULL;
-       if( ds->type == ADDR_IF_BOOK ) abf = ds->rawDataSource;
+       if( ds->type == ADDR_IF_BOOK || ds->type == ADDR_IF_LDAP ) abf = ds->rawDataSource;
        return abf;
 }
 
@@ -2984,6 +3186,7 @@ static void addressbook_move_nodes_up( GtkCTree *ctree, GtkCTreeNode *node ) {
 static void addressbook_edit_address_post_cb( ItemPerson *person )
 {
        if( person ) {
+
                addressbook_folder_refresh_one_person( GTK_CTREE(addrbook.clist), person );
                invalidate_address_completion();
        }
@@ -3057,7 +3260,13 @@ static void addressbook_edit_address( gpointer data, guint action, GtkWidget *wi
                        if  ( addressbook_edit_person( abf, NULL, person, TRUE, addrbook.editaddress_vbox,
                                                                                   addressbook_edit_address_post_cb,
                                                                                   (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
-                                 != NULL ) {
+                                 != NULL ) { 
+#ifdef USE_LDAP
+                               if (abf->type == ADDR_IF_LDAP) {
+                                       ldapsvr_set_modified( (LdapServer *) abf, TRUE );
+                                       person->status = UPDATE_ENTRY;
+                               }
+#endif
                                if (prefs_common.addressbook_use_editaddress_dialog)
                                        addressbook_edit_address_post_cb( person );
                        }
@@ -3071,8 +3280,14 @@ static void addressbook_edit_address( gpointer data, guint action, GtkWidget *wi
                                                                          addressbook_edit_address_post_cb,
                                                                          (prefs_common.addressbook_use_editaddress_dialog||force_focus) )
                        != NULL ) {
-                       if (prefs_common.addressbook_use_editaddress_dialog)
-                               addressbook_edit_address_post_cb( person );
+#ifdef USE_LDAP
+                               if (abf->type == ADDR_IF_LDAP) {
+                                       ldapsvr_set_modified( (LdapServer *) abf, TRUE );
+                                       person->status = UPDATE_ENTRY;
+                               }
+#endif
+                               if (prefs_common.addressbook_use_editaddress_dialog)
+                                       addressbook_edit_address_post_cb( person );
                }
                return;
        }
@@ -3188,6 +3403,7 @@ static void addressbook_folder_load_one_person(
        gchar *text[N_LIST_COLS];
        gboolean flgFirst = TRUE, haveAddr = FALSE;
        GList *node;
+       AddressBookFile *abf = addressbook_get_book_file();
 
        if( person == NULL ) return;
 
@@ -3208,6 +3424,18 @@ static void addressbook_folder_load_one_person(
                        if( str ) {
                                text[COL_NAME] = str;
                        }
+#ifdef USE_LDAP
+                       else if( abf->type == ADDR_IF_LDAP && person->nickName ) {
+                               if (person->nickName) {
+                                       if (strcmp(person->nickName, "") != 0) {
+                                               text[COL_NAME] = person->nickName;
+                                       }
+                                       else {
+                                               text[COL_NAME] = ADDRITEM_NAME(person);
+                                       }
+                               }
+                       }
+#endif
                        else {
                                text[COL_NAME] = ADDRITEM_NAME(person);
                        }
@@ -3361,26 +3589,6 @@ static int addressbook_treenode_find_group_cb( gconstpointer pA, gconstpointer p
        return 1;
 }
 
-/**
- * Search ctree widget callback function.
- * \param  pA Pointer to node.
- * \param  pB Pointer to data item being sought.
- * \return Zero (0) if folder found.
- */
-static int addressbook_treenode_find_folder_cb( gconstpointer pA, gconstpointer pB ) {
-       AddressObject *aoA;
-
-       aoA = ( AddressObject * ) pA;
-       if( aoA->type == ADDR_ITEM_FOLDER ) {
-               ItemFolder *folder, *fld;
-
-               fld = ADAPTER_FOLDER(aoA)->itemFolder;
-               folder = ( ItemFolder * ) pB;
-               if( fld == folder ) return 0;   /* Found folder */
-       }
-       return 1;
-}
-
 /*
 * Remove folder and group nodes from tree widget for items contained ("cut")
 * in clipboard.
@@ -4108,11 +4316,6 @@ static void addressbook_search_callback_end(
        addrindex_stop_search( queryID );
 }
 
-/**
- * Label (a format string) that is used to name each folder.
- */
-static gchar *_queryFolderLabel_ = N_( "Search '%s'" );
-
 /**
  * Perform search.
  *
@@ -4127,12 +4330,12 @@ static void addressbook_perform_search(
        AddrBookBase *adbase;
        AddressCache *cache;
        ItemFolder *folder;
-       GtkCTree *ctree;
-       GtkCTreeNode *nNode;
        gchar *name;
        gint queryID;
        guint idleID;
+#ifdef USE_LDAP
        AddressObjectType aoType = ADDR_NONE;
+#endif
 
        /* Setup a query */
        if( *searchTerm == '\0' || strlen( searchTerm ) < 1 ) return;
@@ -4145,27 +4348,15 @@ static void addressbook_perform_search(
        else {
                return;
        }
-
        /* Get reference to address cache */    
        adbase = ( AddrBookBase * ) ds->rawDataSource;
        cache = adbase->addressCache;
 
        /* Create a folder for the search results */
-       folder = addrcache_add_new_folder( cache, NULL );
        name = g_strdup_printf( _queryFolderLabel_, searchTerm );
-       addritem_folder_set_name( folder, name );
-       addritem_folder_set_remarks( folder, "" );
+       folder = addressbook_setup_subf(ds, name, pNode);
        g_free( name );
 
-       /* Now let's see the folder */
-       ctree = GTK_CTREE(addrbook.ctree);
-       nNode = addressbook_node_add_folder( pNode, ds, folder, aoType );
-       gtk_ctree_expand( ctree, pNode );
-       if( nNode ) {
-               gtk_sctree_select( GTK_SCTREE(ctree), nNode );
-               addrbook.treeSelected = nNode;
-       }
-
        /* Setup the search */
        queryID = addrindex_setup_explicit_search(
                ds, searchTerm, folder, addressbook_search_callback_end, NULL );