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"
57 #define BROWSELDAP_WIDTH 450
58 #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
;
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
;
210 GtkWidget
*close_btn
;
211 GtkWidget
*content_area
;
215 GtkTreeSelection
*sel
;
216 GtkCellRenderer
*rdr
;
217 GtkTreeViewColumn
*col
;
219 debug_print("creating browse widget\n");
220 window
= gtk_dialog_new();
221 gtk_widget_set_size_request( window
, BROWSELDAP_WIDTH
, BROWSELDAP_HEIGHT
);
222 gtk_container_set_border_width( GTK_CONTAINER(window
), 0 );
223 gtk_window_set_title( GTK_WINDOW(window
), _("Browse Directory Entry") );
224 gtk_window_set_position( GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
225 g_signal_connect(G_OBJECT(window
), "delete_event",
226 G_CALLBACK(browse_delete_event
), NULL
);
227 g_signal_connect(G_OBJECT(window
), "key_press_event",
228 G_CALLBACK(browse_key_pressed
), NULL
);
230 vbox
= gtk_vbox_new(FALSE
, 8);
231 content_area
= gtk_dialog_get_content_area(GTK_DIALOG(window
));
232 gtk_box_pack_start(GTK_BOX(content_area
), vbox
, TRUE
, TRUE
, 0);
233 gtk_container_set_border_width( GTK_CONTAINER(vbox
), 8 );
235 table
= gtk_table_new(2, 2, FALSE
);
236 gtk_box_pack_start(GTK_BOX(vbox
), table
, FALSE
, FALSE
, 0);
237 gtk_container_set_border_width( GTK_CONTAINER(table
), 8 );
238 gtk_table_set_row_spacings(GTK_TABLE(table
), 8);
239 gtk_table_set_col_spacings(GTK_TABLE(table
), 8);
243 label
= gtk_label_new(_("Server Name:"));
244 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
245 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0.5);
247 label_server
= gtk_label_new("");
248 gtk_table_attach(GTK_TABLE(table
), label_server
, 1, 2, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
249 gtk_misc_set_alignment(GTK_MISC(label_server
), 0, 0.5);
253 label
= gtk_label_new(_("Distinguished Name (dn):"));
254 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
255 gtk_misc_set_alignment(GTK_MISC(label
), 1, 0.5);
257 label_addr
= gtk_label_new("");
258 gtk_table_attach(GTK_TABLE(table
), label_addr
, 1, 2, top
, (top
+ 1), GTK_FILL
, 0, 0, 0);
259 gtk_misc_set_alignment(GTK_MISC(label_addr
), 0, 0.5);
261 /* Address book/folder tree */
262 vlbox
= gtk_vbox_new(FALSE
, 8);
263 gtk_box_pack_start(GTK_BOX(vbox
), vlbox
, TRUE
, TRUE
, 0);
264 gtk_container_set_border_width( GTK_CONTAINER(vlbox
), 8 );
266 tree_win
= gtk_scrolled_window_new( NULL
, NULL
);
267 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(tree_win
),
268 GTK_POLICY_AUTOMATIC
,
269 GTK_POLICY_AUTOMATIC
);
270 gtk_box_pack_start( GTK_BOX(vlbox
), tree_win
, TRUE
, TRUE
, 0 );
272 store
= gtk_list_store_new(N_COLS
,
273 G_TYPE_STRING
, G_TYPE_STRING
,
276 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
277 g_object_unref(store
);
278 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view
), TRUE
);
279 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(view
), FALSE
);
280 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(view
));
281 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_NONE
);
283 rdr
= gtk_cell_renderer_text_new();
284 col
= gtk_tree_view_column_new_with_attributes(_("LDAP Name"), rdr
,
285 "markup", COL_NAME
, NULL
);
286 gtk_tree_view_column_set_min_width(col
, COL_WIDTH_NAME
);
287 gtk_tree_view_append_column(GTK_TREE_VIEW(view
), col
);
289 rdr
= gtk_cell_renderer_text_new();
290 col
= gtk_tree_view_column_new_with_attributes(_("Attribute Value"), rdr
,
291 "markup", COL_VALUE
, NULL
);
292 gtk_tree_view_column_set_min_width(col
, COL_WIDTH_VALUE
);
293 gtk_tree_view_append_column(GTK_TREE_VIEW(view
), col
);
295 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
),
296 COL_NAME
, GTK_SORT_ASCENDING
);
298 gtk_container_add( GTK_CONTAINER(tree_win
), view
);
301 gtkut_stock_button_set_create(&hbbox
, &close_btn
, GTK_STOCK_CLOSE
,
302 NULL
, NULL
, NULL
, NULL
);
303 gtk_box_pack_end(GTK_BOX(vbox
), hbbox
, FALSE
, FALSE
, 0);
304 gtk_container_set_border_width( GTK_CONTAINER(hbbox
), 0 );
306 g_signal_connect(G_OBJECT(close_btn
), "clicked",
307 G_CALLBACK(browse_close
), NULL
);
308 gtk_widget_grab_default(close_btn
);
310 gtk_widget_show_all(vbox
);
312 browseldap_dlg
.window
= window
;
313 browseldap_dlg
.label_server
= label_server
;
314 browseldap_dlg
.label_address
= label_addr
;
315 browseldap_dlg
.list_view
= view
;
316 browseldap_dlg
.close_btn
= close_btn
;
318 gtk_widget_show_all( window
);
323 * Idler function. This function is called by the main (UI) thread during UI
324 * idle time while an address search is in progress. Items from the display
325 * queue are processed and appended to the address list.
327 * \param data Target data object.
328 * \return <i>TRUE</i> to ensure that idle event do not get ignored.
330 static gboolean
browse_idle( gpointer data
) {
333 GtkWidget
*view
= browseldap_dlg
.list_view
;
334 GtkListStore
*store
= GTK_LIST_STORE(
335 gtk_tree_view_get_model(GTK_TREE_VIEW(view
)));
338 /* Process all entries in display queue */
339 pthread_mutex_lock( & _browseMutex_
);
340 if( _displayQueue_
) {
341 node
= _displayQueue_
;
343 /* Add entry into list */
344 nvp
= ( NameValuePair
* ) node
->data
;
345 debug_print("Adding row to list: %s->%s\n",
346 nvp
->name
?nvp
->name
:"null",
347 nvp
->value
?nvp
->value
:"null");
348 gtk_list_store_append(store
, &iter
);
349 gtk_list_store_set(store
, &iter
,
351 COL_VALUE
, nvp
->value
,
355 ldapqry_free_name_value( nvp
);
357 node
= g_list_next( node
);
359 g_list_free( _displayQueue_
);
360 _displayQueue_
= NULL
;
362 pthread_mutex_unlock( & _browseMutex_
);
364 if( _searchComplete_
) {
366 if( _browseIdleID_
!= 0 ) {
367 g_source_remove( _browseIdleID_
);
376 * Main entry point to browse LDAP entries.
377 * \param ds Data source to process.
378 * \param dn Distinguished name to retrieve.
379 * \return <code>TRUE</code>
381 gboolean
browseldap_entry( AddressDataSource
*ds
, const gchar
*dn
) {
389 server
= ds
->rawDataSource
;
391 if( ! browseldap_dlg
.window
) browse_create();
392 gtk_widget_grab_focus(browseldap_dlg
.close_btn
);
393 gtk_widget_show(browseldap_dlg
.window
);
394 manage_window_set_transient(GTK_WINDOW(browseldap_dlg
.window
));
395 gtk_window_set_modal(GTK_WINDOW(browseldap_dlg
.window
), TRUE
);
396 gtk_widget_show(browseldap_dlg
.window
);
398 gtk_label_set_text( GTK_LABEL(browseldap_dlg
.label_address
), "" );
401 GTK_LABEL(browseldap_dlg
.label_address
), dn
);
404 GTK_LABEL(browseldap_dlg
.label_server
),
405 ldapsvr_get_name( server
) );
407 debug_print("browsing server: %s\n", ldapsvr_get_name(server
));
409 _searchComplete_
= FALSE
;
410 _queryID_
= ldaplocate_search_setup(
411 server
, dn
, browse_callback_entry
, browse_callback_end
);
412 debug_print("query id: %d\n", _queryID_
);
413 _browseIdleID_
= g_idle_add( (GSourceFunc
) browse_idle
, NULL
);
416 debug_print("starting search\n");
417 ldaplocate_search_start( _queryID_
);
421 gtk_widget_hide( browseldap_dlg
.window
);
422 gtk_window_set_modal(GTK_WINDOW(browseldap_dlg
.window
), FALSE
);
424 debug_print("stopping search\n");
425 ldaplocate_search_stop( _queryID_
);
427 if( _browseIdleID_
!= 0 ) {
428 g_source_remove( _browseIdleID_
);
431 browse_clear_queue();
433 view
= browseldap_dlg
.list_view
;
434 store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(view
)));
435 gtk_list_store_clear(store
);
440 #endif /* USE_LDAP */