2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2012 Match Grun and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "claws-features.h"
34 #include <glib/gi18n.h>
35 #include <gdk/gdkkeysyms.h>
40 #include "stock_pixmap.h"
41 #include "prefs_common.h"
42 #include "browseldap.h"
44 #include "addrindex.h"
45 #include "manage_window.h"
47 #include "ldapquery.h"
48 #include "ldapserver.h"
49 #include "ldaplocate.h"
56 #define BROWSELDAP_WIDTH 450
57 #define BROWSELDAP_HEIGHT 420
60 #define COL_WIDTH_NAME 140
61 #define COL_WIDTH_VALUE 140
63 static struct _LDAPEntry_dlg
{
65 GtkWidget
*label_server
;
66 GtkWidget
*label_address
;
67 GtkWidget
*list_entry
;
74 static GList
*_displayQueue_
= NULL
;
77 * Mutex to protect callback from multiple threads.
79 static pthread_mutex_t _browseMutex_
= PTHREAD_MUTEX_INITIALIZER
;
84 static gint _queryID_
= 0;
89 static guint _browseIdleID_
= 0;
92 * Search complete indicator.
94 static gboolean _searchComplete_
= FALSE
;
97 * Callback entry point for each LDAP entry processed. The background thread
98 * (if any) appends the address list to the display queue.
100 * \param qry LDAP query object.
101 * \param queryID Query ID of search request.
102 * \param listEMail List of zero of more email objects that met search
104 * \param data User data.
106 static gint
browse_callback_entry(
107 LdapQuery
*qry
, gint queryID
, GList
*listValues
, gpointer data
)
112 debug_print("browse_callback_entry...\n");
113 pthread_mutex_lock( & _browseMutex_
);
114 /* Append contents to end of display queue */
117 nvp
= ( NameValuePair
* ) node
->data
;
118 debug_print("adding to list: %s->%s\n",
119 nvp
->name
?nvp
->name
:"null",
120 nvp
->value
?nvp
->value
:"null");
121 _displayQueue_
= g_list_append( _displayQueue_
, nvp
);
123 node
= g_list_next( node
);
125 pthread_mutex_unlock( & _browseMutex_
);
126 /* g_print( "browse_callback_entry...done\n" ); */
132 * Callback entry point for end of LDAP locate search.
134 * \param qry LDAP query object.
135 * \param queryID Query ID of search request.
136 * \param status Status/error code.
137 * \param data User data.
139 static gint
browse_callback_end(
140 LdapQuery
*qry
, gint queryID
, gint status
, gpointer data
)
142 debug_print("search completed\n");
143 _searchComplete_
= TRUE
;
148 * Clear the display queue.
150 static void browse_clear_queue( void ) {
151 /* Clear out display queue */
152 pthread_mutex_lock( & _browseMutex_
);
154 ldapqry_free_list_name_value( _displayQueue_
);
155 g_list_free( _displayQueue_
);
156 _displayQueue_
= NULL
;
158 pthread_mutex_unlock( & _browseMutex_
);
162 * Close window callback.
163 * \param widget Widget.
164 * \param event Event.
165 * \param cancelled Cancelled flag.
167 static gint
browse_delete_event(
168 GtkWidget
*widget
, GdkEventAny
*event
, gboolean
*cancelled
)
175 * Respond to key press in window.
176 * \param widget Widget.
177 * \param event Event.
178 * \param cancelled Cancelled flag.
180 static void browse_key_pressed(
181 GtkWidget
*widget
, GdkEventKey
*event
, gboolean
*cancelled
)
183 if (event
&& event
->keyval
== GDK_KEY_Escape
) {
189 * Callback to close window.
190 * \param widget Widget.
191 * \param cancelled Cancelled flag.
193 static void browse_close( GtkWidget
*widget
, gboolean
*cancelled
) {
198 * Create the window to display data.
200 static void browse_create( void ) {
205 GtkWidget
*label_server
;
206 GtkWidget
*label_addr
;
207 GtkWidget
*list_entry
;
211 GtkWidget
*close_btn
;
214 debug_print("creating browse widget\n");
215 window
= gtk_dialog_new();
216 gtk_widget_set_size_request( window
, BROWSELDAP_WIDTH
, BROWSELDAP_HEIGHT
);
217 gtk_container_set_border_width( GTK_CONTAINER(window
), 0 );
218 gtk_window_set_title( GTK_WINDOW(window
), _("Browse Directory Entry") );
219 gtk_window_set_position( GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
220 g_signal_connect(G_OBJECT(window
), "delete_event",
221 G_CALLBACK(browse_delete_event
), NULL
);
222 g_signal_connect(G_OBJECT(window
), "key_press_event",
223 G_CALLBACK(browse_key_pressed
), NULL
);
225 vbox
= gtk_vbox_new(FALSE
, 8);
226 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window
)->vbox
), vbox
, TRUE
, TRUE
, 0);
227 gtk_container_set_border_width( GTK_CONTAINER(vbox
), 8 );
229 table
= gtk_table_new(2, 2, FALSE
);
230 gtk_box_pack_start(GTK_BOX(vbox
), table
, FALSE
, FALSE
, 0);
231 gtk_container_set_border_width( GTK_CONTAINER(table
), 8 );
232 gtk_table_set_row_spacings(GTK_TABLE(table
), 8);
233 gtk_table_set_col_spacings(GTK_TABLE(table
), 8);
237 label
= gtk_label_new(_("Server Name :"));
238 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
239 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0.5);
241 label_server
= gtk_label_new("");
242 gtk_table_attach(GTK_TABLE(table
), label_server
, 1, 2, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
243 gtk_misc_set_alignment(GTK_MISC(label_server
), 0, 0.5);
247 label
= gtk_label_new(_("Distinguished Name (dn) :"));
248 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
249 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0.5);
251 label_addr
= gtk_label_new("");
252 gtk_table_attach(GTK_TABLE(table
), label_addr
, 1, 2, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
253 gtk_misc_set_alignment(GTK_MISC(label_addr
), 0, 0.5);
255 /* Address book/folder tree */
256 vlbox
= gtk_vbox_new(FALSE
, 8);
257 gtk_box_pack_start(GTK_BOX(vbox
), vlbox
, TRUE
, TRUE
, 0);
258 gtk_container_set_border_width( GTK_CONTAINER(vlbox
), 8 );
260 tree_win
= gtk_scrolled_window_new( NULL
, NULL
);
261 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win
),
262 GTK_POLICY_AUTOMATIC
,
263 GTK_POLICY_AUTOMATIC
);
264 gtk_box_pack_start( GTK_BOX(vlbox
), tree_win
, TRUE
, TRUE
, 0 );
266 list_entry
= gtk_cmclist_new( N_COLS
);
267 gtk_container_add( GTK_CONTAINER(tree_win
), list_entry
);
268 gtk_cmclist_column_titles_show( GTK_CMCLIST(list_entry
) );
269 gtk_cmclist_set_column_title(
270 GTK_CMCLIST(list_entry
), COL_NAME
, _( "LDAP Name" ) );
271 gtk_cmclist_set_column_title(
272 GTK_CMCLIST(list_entry
), COL_VALUE
, _( "Attribute Value" ) );
273 gtk_cmclist_set_selection_mode(
274 GTK_CMCLIST(list_entry
), GTK_SELECTION_BROWSE
);
275 gtk_cmclist_set_column_width( GTK_CMCLIST(list_entry
),
276 COL_NAME
, COL_WIDTH_NAME
);
277 gtk_cmclist_set_auto_sort( GTK_CMCLIST(list_entry
), TRUE
);
280 gtkut_stock_button_set_create(&hbbox
, &close_btn
, GTK_STOCK_CLOSE
,
281 NULL
, NULL
, NULL
, NULL
);
282 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
283 gtk_container_set_border_width( GTK_CONTAINER(hbbox
), 0 );
285 g_signal_connect(G_OBJECT(close_btn
), "clicked",
286 G_CALLBACK(browse_close
), NULL
);
287 gtk_widget_grab_default(close_btn
);
289 gtk_widget_show_all(vbox
);
291 browseldap_dlg
.window
= window
;
292 browseldap_dlg
.label_server
= label_server
;
293 browseldap_dlg
.label_address
= label_addr
;
294 browseldap_dlg
.list_entry
= list_entry
;
295 browseldap_dlg
.close_btn
= close_btn
;
297 gtk_widget_show_all( window
);
302 * Idler function. This function is called by the main (UI) thread during UI
303 * idle time while an address search is in progress. Items from the display
304 * queue are processed and appended to the address list.
306 * \param data Target data object.
307 * \return <i>TRUE</i> to ensure that idle event do not get ignored.
309 static gboolean
browse_idle( gpointer data
) {
314 /* Process all entries in display queue */
315 pthread_mutex_lock( & _browseMutex_
);
316 if( _displayQueue_
) {
317 node
= _displayQueue_
;
319 /* Add entry into list */
320 nvp
= ( NameValuePair
* ) node
->data
;
321 text
[COL_NAME
] = nvp
->name
;
322 text
[COL_VALUE
] = nvp
->value
;
323 debug_print("Adding row to list: %s->%s\n",
324 nvp
->name
?nvp
->name
:"null",
325 nvp
->value
?nvp
->value
:"null");
327 GTK_CMCLIST(browseldap_dlg
.list_entry
), text
);
330 ldapqry_free_name_value( nvp
);
332 node
= g_list_next( node
);
334 g_list_free( _displayQueue_
);
335 _displayQueue_
= NULL
;
337 pthread_mutex_unlock( & _browseMutex_
);
339 if( _searchComplete_
) {
341 if( _browseIdleID_
!= 0 ) {
342 g_source_remove( _browseIdleID_
);
344 gtk_cmclist_select_row(
345 GTK_CMCLIST( browseldap_dlg
.list_entry
), 0, 0 );
353 * Main entry point to browse LDAP entries.
354 * \param ds Data source to process.
355 * \param dn Distinguished name to retrieve.
356 * \return <code>TRUE</code>
358 gboolean
browseldap_entry( AddressDataSource
*ds
, const gchar
*dn
) {
364 server
= ds
->rawDataSource
;
366 if( ! browseldap_dlg
.window
) browse_create();
367 gtk_widget_grab_focus(browseldap_dlg
.close_btn
);
368 gtk_widget_show(browseldap_dlg
.window
);
369 manage_window_set_transient(GTK_WINDOW(browseldap_dlg
.window
));
370 gtk_window_set_modal(GTK_WINDOW(browseldap_dlg
.window
), TRUE
);
371 gtk_cmclist_select_row( GTK_CMCLIST( browseldap_dlg
.list_entry
), 0, 0 );
372 gtk_widget_show(browseldap_dlg
.window
);
374 gtk_label_set_text( GTK_LABEL(browseldap_dlg
.label_address
), "" );
377 GTK_LABEL(browseldap_dlg
.label_address
), dn
);
380 GTK_LABEL(browseldap_dlg
.label_server
),
381 ldapsvr_get_name( server
) );
383 debug_print("browsing server: %s\n", ldapsvr_get_name(server
));
385 _searchComplete_
= FALSE
;
386 _queryID_
= ldaplocate_search_setup(
387 server
, dn
, browse_callback_entry
, browse_callback_end
);
388 debug_print("query id: %d\n", _queryID_
);
389 _browseIdleID_
= g_idle_add( (GSourceFunc
) browse_idle
, NULL
);
392 debug_print("starting search\n");
393 ldaplocate_search_start( _queryID_
);
397 gtk_widget_hide( browseldap_dlg
.window
);
398 gtk_window_set_modal(GTK_WINDOW(browseldap_dlg
.window
), FALSE
);
400 debug_print("stopping search\n");
401 ldaplocate_search_stop( _queryID_
);
403 if( _browseIdleID_
!= 0 ) {
404 g_source_remove( _browseIdleID_
);
407 browse_clear_queue();
408 gtk_cmclist_clear( GTK_CMCLIST( browseldap_dlg
.list_entry
) );
413 #endif /* USE_LDAP */