2
GQ -- a GTK-based LDAP client
3
Copyright (C) 1998-2003 Bert Vermeulen
4
Copyright (C) 2002-2003 Peter Stamfest
6
This program is released under the Gnu General Public License with
7
the additional exemption that compiling, linking, and/or using
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 2 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
/* $Id: util.c 975 2006-09-07 18:44:41Z herzi $ */
28
#include <glib/gi18n.h>
30
#include <gdk/gdkkeysyms.h>
40
#endif /* HAVE_CONFIG_H */
44
#ifdef HAVE_LDAP_STR2OBJECTCLASS
45
# include <ldap_schema.h>
51
# include <sasl/sasl.h>
55
#ifdef LDAP_OPT_NETWORK_TIMEOUT
59
#include <glade/glade.h>
62
#include "configfile.h"
63
#include "errorchain.h"
64
#include "gq-keyring.h"
65
#include "gq-server-list.h"
73
#include "mainwin.h" /* message_log_append */
75
#define TRY_VERSION3 1
77
LDAP *open_connection_ex(int open_context,
78
GqServer *server, int *ldap_errno);
81
static int util_ldap_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in)
83
sasl_interact_t *interact = in;
84
GqServer *def = defaults;
86
for (; interact->id != SASL_CB_LIST_END; interact++) {
88
switch (interact->id) {
89
case SASL_CB_AUTHNAME:
90
interact->result = def->binddn;
91
interact->len = strlen(def->binddn);
96
if (def->enteredpw[0]) {
97
interact->result = def->enteredpw;
98
interact->len = strlen(def->enteredpw);
101
else if (def->bindpw[0]) {
102
interact->result = def->bindpw;
103
interact->len = strlen(def->bindpw);
113
do_ldap_auth(LDAP *ld, GqServer *server, int open_context) {
116
int rc = LDAP_SUCCESS;
118
if (server->binddn[0]) {
119
binddn = server->binddn;
122
/* do not ever use the bindpw if we have turned on to ask
124
/* Thanks to Tomas A. Maly <tomas_maly@yahoo.com> for
125
* indirectly causing me to check this area */
126
if (server->ask_pw) {
127
if (server->enteredpw[0])
128
bindpw = server->enteredpw;
130
else if (server->bindpw[0])
131
bindpw = server->bindpw;
133
/* take care of special characters... */
134
if (binddn) binddn = encoded_string(binddn);
135
if (bindpw) bindpw = encoded_string(bindpw);
137
switch (server->bindtype) {
138
case BINDTYPE_KERBEROS:
140
rc = ldap_bind_s(ld, binddn, bindpw, LDAP_AUTH_KRBV4);
142
error_push(open_context,
143
_("Cannot use Kerberos bind with '%s'.\n"
144
"GQ was compiled without Kerberos support.\n"
145
"Run 'configure --help' for more information\n"),
147
statusbar_msg_clear();
148
/* XXX - should merge kerberos into sasl (gssapi) */
149
rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
154
rc = ldap_sasl_interactive_bind_s(ld, NULL, NULL, NULL, NULL, LDAP_SASL_QUIET, util_ldap_sasl_interact, server);
155
if (rc == LDAP_SUCCESS)
158
error_push(open_context,
159
_("Cannot use SASL bind with '%s'.\n"
160
"GQ was compiled without SASL support.\n"
161
"Run 'configure --help' for more information\n"),
163
statusbar_msg_clear();
164
rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
168
rc = ldap_simple_bind_s(ld, binddn, bindpw);
172
if (binddn) free(binddn);
173
if (bindpw) free(bindpw);
178
static int do_ldap_connect(LDAP **ld_out, GqServer *server,
179
int open_context, int flags)
182
char *binddn = NULL, *bindpw = NULL;
183
int rc = LDAP_SUCCESS;
185
#ifdef LDAP_OPT_NETWORK_TIMEOUT
186
struct timeval nettimeout;
191
if (g_utf8_strchr(server->ldaphost, -1, ':') != NULL) {
192
#ifdef HAVE_LDAP_INITIALIZE
193
rc = ldap_initialize(&ld, server->ldaphost);
194
if (rc != LDAP_SUCCESS) {
199
error_push(open_context,
200
_("Failed to initialize LDAP structure for server '%1$s': %2$s."),
202
ldap_err2string(rc));
206
error_push(open_context,
207
_("Cannot connect to '%s'. No URI support available. Your LDAP toolkit does not support LDAP URIs."),
211
ld = ldap_init(server->ldaphost, server->ldapport);
213
error_push(open_context,
214
_("Failed to initialize LDAP structure for server %1$s: %2$s."),
221
server->server_down = 0;
222
server->version = LDAP_VERSION2;
225
i = DEFAULT_LDAP_TIMEOUT;
226
ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &i);
228
#ifdef LDAP_OPT_NETWORK_TIMEOUT
229
nettimeout.tv_sec = DEFAULT_NETWORK_TIMEOUT;
230
nettimeout.tv_usec = 0;
231
ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &nettimeout);
234
#ifndef HAVE_OPENLDAP12
235
if (flags & TRY_VERSION3) {
236
/* try to use LDAP Version 3 */
238
int version = LDAP_VERSION3;
239
if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
240
&version) == LDAP_OPT_SUCCESS) {
241
server->version = LDAP_VERSION3;
243
/* error_push(open_context, message); */
244
/* push_ldap_addl_error(ld, open_context); */
249
if (server->enabletls) {
250
#if defined(HAVE_TLS)
252
if (server->version != LDAP_VERSION3) {
253
error_push(open_context,
254
_("Server '%s': Couldn't set protocol version to LDAPv3."),
259
/* Let's turn on TLS */
260
rc = ldap_start_tls_s(ld, NULL, NULL);
261
if(rc != LDAP_SUCCESS) {
262
error_push(open_context,
263
_("Couldn't enable TLS on the LDAP connection to '%1$s': %2$s"),
265
ldap_err2string(rc));
266
push_ldap_addl_error(ld, open_context);
272
error_push(open_context,
273
_("Cannot use TLS with server '%s'. TLS was not found to be supported by your LDAP libraries.\n"
274
"See README.TLS for more information.\n"),
276
#endif /* defined(HAVE_TLS) */
279
if(server->local_cache_timeout >= 0) {
280
#if HAVE_LDAP_CLIENT_CACHE
281
ldap_enable_cache(ld, server->local_cache_timeout,
282
DEFAULT_LOCAL_CACHE_SIZE);
284
error_push(open_context,
285
_("Cannot cache LDAP objects for server '%s'.\n"
286
"OpenLDAP client-side caching was not enabled.\n"
287
"See configure --help for more information.\n"),
292
/* perform the auth */
293
rc = do_ldap_auth(ld, server, open_context);
295
if (rc != LDAP_SUCCESS) {
296
/* Maybe we cannot use LDAPv3 ... try again */
297
error_push(open_context,
298
_("Couldn't bind LDAP connection to '%1$s': %2$s"),
299
server->name, ldap_err2string(rc));
300
push_ldap_addl_error(ld, open_context);
301
statusbar_msg_clear();
302
/* might as well clean this up */
306
/* always store connection handle, regardless of connection
307
caching -- call close_connection() after each operation
308
to do the caching thing or not */
309
server->connection = ld;
310
server->missing_closes = 1;
311
server->incarnation++;
316
/* experimental referral stuff ... */
318
rc = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
320
if (rc != LDAP_OPT_SUCCESS ) {
321
error_push(open_context,
322
_("Could not disable following referrals on connection to server '%s'."), server->name);
323
push_ldap_addl_error(ld, open_context);
325
/* this is not a fatal error, so continue */
333
/** Returns a ldapserver object (either an existing or a newly
334
created) usable to search below the base_url.
336
The server gets looked up in the following way:
338
1) the credentials of the parent server get used with a
339
newly created ldapserver
341
2) The base_url gets looked up as the canonical name. If a match
342
is found and the credentials for this server work a copy of the
343
thus found object gets returned
345
3) An anonymous bind gets attempted.
348
get_referral_server(int error_context,
350
const char *base_url)
352
LDAPURLDesc *desc = NULL;
353
GqServer *newserver = NULL, *s;
358
if (ldap_url_parse(base_url, &desc) == 0) {
359
GString *new_uri = g_string_sized_new(strlen(base_url));
360
g_string_sprintf(new_uri, "%s://%s:%d/",
365
newserver = gq_server_new();
367
if (! config->never_leak_credentials) {
368
copy_ldapserver(newserver, parent);
370
g_free_and_dup(newserver->name, new_uri->str);
371
g_free_and_dup(newserver->ldaphost, new_uri->str);
372
g_free_and_dup(newserver->basedn, desc->lud_dn);
374
/* some sensible settings for the "usual" case:
375
Anonymous bind. Also show referrals */
376
newserver->ask_pw = 0;
377
newserver->show_ref = 1;
378
newserver->quiet = 1;
380
if (open_connection_ex(error_context,
381
newserver, &ld_err)) {
382
close_connection(newserver, FALSE);
384
statusbar_msg(_("Initialized temporary server-definition '%1$s' from existing server '%2$s'"), new_uri->str, parent->name);
388
if (ld_err == LDAP_SERVER_DOWN) {
392
reset_ldapserver(newserver);
394
/* check: do we have this server around already??? */
395
s = server_by_canon_name(new_uri->str, TRUE);
398
copy_ldapserver(newserver, s);
400
g_free_and_dup(newserver->name, new_uri->str);
401
g_free_and_dup(newserver->ldaphost, new_uri->str);
402
g_free_and_dup(newserver->basedn, desc->lud_dn);
404
/* some sensible settings for the "usual" case:
405
Anonymous bind. Also show referrals */
406
newserver->ask_pw = 0;
407
newserver->show_ref = 1;
408
newserver->quiet = 1;
410
if (open_connection_ex(error_context,
411
newserver, &ld_err)) {
412
close_connection(newserver, FALSE);
413
statusbar_msg(_("Initialized temporary server-definition '%1$s' from existing server '%2$s'"), new_uri->str, s->name);
416
if (ld_err == LDAP_SERVER_DOWN) {
422
reset_ldapserver(newserver);
425
copy_ldapserver(newserver, parent);
427
g_free_and_dup(newserver->name, new_uri->str);
428
g_free_and_dup(newserver->ldaphost, new_uri->str);
429
g_free_and_dup(newserver->basedn, desc->lud_dn);
431
g_free_and_dup(newserver->binddn, "");
432
g_free_and_dup(newserver->bindpw, "");
433
g_free_and_dup(newserver->enteredpw, "");
435
newserver->bindtype = BINDTYPE_SIMPLE;
437
if (open_connection_ex(error_context, newserver, &ld_err)) {
438
close_connection(newserver, FALSE);
439
statusbar_msg(_("Initialized temporary server-definition '%1$s' from existing server '%2$s'"), new_uri->str, parent->name);
442
if (ld_err == LDAP_SERVER_DOWN) {
448
if (desc) ldap_free_urldesc(desc);
450
newserver->quiet = 0;
451
canonicalize_ldapserver(newserver);
458
delete_on_escape(GtkDialog* dialog, GdkEventKey* ev) {
459
if(ev->keyval == GDK_Escape) {
460
gtk_dialog_response(dialog, GTK_RESPONSE_DELETE_EVENT);
467
get_password_from_dialog(GqServer* server) {
468
GladeXML * xml = NULL;
469
GtkSizeGroup* group_left = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
470
GtkSizeGroup* group_right = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
471
GtkWidget * old_grab = gtk_grab_get_current();
472
gchar const * password = NULL;
473
gchar * string = NULL;
475
xml = glade_xml_new(PACKAGE_PREFIX "/share/gq/gq.glade", "password_dialog", NULL);
477
GtkWidget* dlg = gtk_message_dialog_new(NULL, // FIXME: set modal parent
481
"%s", _("The user interface definition could not be "
482
"loaded, please make sure that GQ is correctly "
484
gtk_dialog_run(GTK_DIALOG(dlg));
485
gtk_widget_hide(dlg);
486
gtk_widget_destroy(dlg);
489
// FIXME: the GtkCTree has got the pointer grabbed
491
gtk_widget_hide(old_grab);
492
gtk_widget_show(old_grab);
495
g_signal_connect(glade_xml_get_widget(xml, "password_dialog"), "key-press-event",
496
G_CALLBACK(delete_on_escape), NULL);
498
gtk_size_group_add_widget(group_left, glade_xml_get_widget(xml, "label_hostname"));
499
gtk_size_group_add_widget(group_left, glade_xml_get_widget(xml, "label_bind_dn"));
500
gtk_size_group_add_widget(group_left, glade_xml_get_widget(xml, "label_bind_mode"));
501
gtk_size_group_add_widget(group_left, glade_xml_get_widget(xml, "label_password"));
502
gtk_size_group_add_widget(group_right, glade_xml_get_widget(xml, "input_hostname"));
503
gtk_size_group_add_widget(group_right, glade_xml_get_widget(xml, "input_bind_dn"));
504
gtk_size_group_add_widget(group_right, glade_xml_get_widget(xml, "input_bind_mode"));
505
gtk_size_group_add_widget(group_right, glade_xml_get_widget(xml, "input_password"));
507
if(!gnome_keyring_is_available()) {
508
gtk_widget_hide(glade_xml_get_widget(xml, "checkbutton_save_password"));
511
if(server->name && server->ldaphost &&
512
(!strcmp(server->name, server->ldaphost))) {
513
// Server Name and Hostname are equal, do not print twice
514
// TRANSLATORS: "hostname:port"
515
string = g_strdup_printf(_("%s:%d"), server->name, server->ldapport);
517
// TRANSLATORS: "servername (hostname:port)"
518
string = g_strdup_printf(_("%s (%s:%d)"), server->name, server->ldaphost, server->ldapport);
520
gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xml, "input_hostname")), string);
523
gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xml, "input_bind_dn")), server->binddn);
525
// TRANSLATORS: "(Simple,Kerberos,SASL) Authentication"
526
string = g_strdup_printf(_("%s Authentication"), token_bindtype[server->bindtype].keyword);
527
// FIXME: get this translatable as a whole text
528
gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xml, "input_bind_mode")), string);
532
switch(gtk_dialog_run(GTK_DIALOG(glade_xml_get_widget(xml, "password_dialog")))) {
533
case GTK_RESPONSE_OK:
534
g_free_and_dup(server->bindpw, gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(xml, "input_password"))));
536
// FIXME: store password only from successful connections
537
if(gnome_keyring_is_available() &&
538
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "checkbutton_save_password")))) {
539
gq_keyring_save_server_password(server);
542
case GTK_RESPONSE_HELP:
543
// FIXME: add documentation and something about the login dialog
547
gtk_widget_destroy(GTK_WIDGET(glade_xml_get_widget(xml, "password_dialog")));
549
g_object_unref(group_left);
550
g_object_unref(group_right);
556
* open connection to LDAP server, and store connection for caching
559
open_connection_ex(int open_context, GqServer *server, int *ldap_errno)
563
GString *message = NULL;
566
if (ldap_errno) *ldap_errno = LDAP_SUCCESS;
567
if(!server) return NULL;
569
server->missing_closes++;
571
/* reuse previous connection if available */
572
if(server->connection) {
573
if (server->server_down == 0)
574
return(server->connection);
576
/* do not leak file descriptors in case we need to
578
ldap_unbind(server->connection);
579
server->connection = NULL;
583
if (server->ask_pw &&
584
server->binddn[0] && /* makes sense only if we bind as someone */
585
/* server->bindpw[0] == 0 && */
586
server->enteredpw[0] == 0) {
593
ret = gq_keyring_get_password(server);
596
ret = get_password_from_dialog(server);
599
if (ret) { /* FIXME: somehow get modal_for widget */
601
g_free(server->enteredpw);
602
server->enteredpw = ret;
605
server->enteredpw[0] = 0;
612
if(server->ldapport == 389) {
613
statusbar_msg(_("Connecting to %s"), server->ldaphost);
615
statusbar_msg(_("Connecting to %1$s port %2$d"),
616
server->ldaphost, server->ldapport);
620
/* open_context = error_new_context(_("Error connecting to server")); */
622
rc = do_ldap_connect(&ld, server, open_context,
624
if (rc == LDAP_PROTOCOL_ERROR) {
625
/* this might be an indication that the server does not
626
understand LDAP_VERSION3 - retry without trying VERSION3 */
627
rc = do_ldap_connect(&ld, server, open_context, 0);
628
if (rc == LDAP_SUCCESS) error_clear(open_context);
629
} else if (rc == LDAP_INVALID_CREDENTIALS) {
630
/* Should the server configuration pop up? */
633
/* this is not quite OK: FIXME */
634
if (server->quiet) error_clear(open_context);
635
/* error_flush(open_context); */
637
if (rc != LDAP_SUCCESS) {
638
if (newpw) server->enteredpw[0] = 0;
641
if (ldap_errno) *ldap_errno = rc;
646
LDAP *open_connection(int open_context, GqServer *server)
648
return open_connection_ex(open_context, server, NULL);
652
* called after every set of LDAP operations. This preserves the connection
653
* if caching is enabled for the server. Set always to TRUE if you want to
654
* close the connection regardless of caching.
657
close_connection(GqServer *server, int always)
659
server->missing_closes--;
661
if(server->connection &&
662
((server->missing_closes == 0 && !server->cacheconn) || always))
664
/* definitely close this connection */
665
ldap_unbind(server->connection);
666
server->connection = NULL;
672
* clear cached server schema
674
void clear_server_schema(GqServer *server)
676
#ifdef HAVE_LDAP_STR2OBJECTCLASS
678
struct server_schema *ss;
687
ldap_objectclass_free(list->data);
693
/* attribute types */
697
ldap_attributetype_free(list->data);
707
ldap_matchingrule_free(list->data);
717
ldap_syntax_free(list->data);
723
FREE(server->ss, "struct server_schema");
727
server->flags &= ~SERVER_HAS_NO_SCHEMA;
736
gboolean delete_entry_full(int delete_context,
737
GqServer *server, char *dn,
744
LDAPControl *ctrls[2] = { NULL, NULL } ;
745
LDAPMessage *res = NULL, *e;
747
c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
748
c.ldctl_value.bv_val = NULL;
749
c.ldctl_value.bv_len = 0;
750
c.ldctl_iscritical = 1;
754
/* FIXME confirm-mod check here */
758
if( (ld = open_connection(delete_context, server) ) == NULL) {
764
int something_to_do = 1;
765
static char* attrs [] = {"dn", NULL};
767
while (something_to_do) {
769
msg = ldap_search_ext_s(ld, dn,
772
(char **)attrs, /* attrs */
774
ctrls, /* serverctrls */
775
NULL, /* clientctrls */
777
LDAP_NO_LIMIT, /* sizelimit */
780
if(msg == LDAP_NOT_SUPPORTED) {
781
msg = ldap_search_s(ld, dn, LDAP_SCOPE_ONELEVEL,
783
(char **) attrs, 1, &res);
786
if(msg == LDAP_SUCCESS) {
787
for (e = ldap_first_entry(ld, res); e ;
788
e = ldap_next_entry(ld, e)) {
789
char *dn2 = ldap_get_dn(ld, e);
790
gboolean delok = delete_entry_full(delete_context,
792
if (dn2) ldap_memfree(dn2);
800
} else if (msg == LDAP_SERVER_DOWN) {
801
server->server_down++;
804
if (res) ldap_msgfree(res);
809
statusbar_msg(_("Deleting: %s"), dn);
811
msg = ldap_delete_ext_s(ld, dn, ctrls, NULL);
813
if(msg == LDAP_NOT_SUPPORTED) {
814
msg = ldap_delete_s(ld, dn);
817
#if HAVE_LDAP_CLIENT_CACHE
818
ldap_uncache_entry(ld, dn);
821
if(msg != LDAP_SUCCESS) {
822
error_push(delete_context,
823
"Error deleting DN '%1$s' on '%2$s': %3$s",
824
dn, server->name, ldap_err2string(msg));
828
statusbar_msg(_("Deleted %s"), dn);
832
if (res) ldap_msgfree(res);
834
close_connection(server, FALSE);
840
gboolean delete_entry(int delete_context,
841
GqServer *server, char *dn)
843
return delete_entry_full(delete_context, server, dn, FALSE);
846
gboolean do_recursive_delete(int delete_context,
847
GqServer *server, char* dn)
849
return delete_entry_full(delete_context, server, dn, TRUE);
853
* display hourglass cursor on mainwin
855
void set_busycursor(void)
857
GdkCursor *busycursor;
859
busycursor = gdk_cursor_new(GDK_WATCH);
860
gdk_window_set_cursor(mainwin.mainwin->window, busycursor);
861
gdk_cursor_destroy(busycursor);
867
* set mainwin cursor to default
869
void set_normalcursor(void)
872
gdk_window_set_cursor(mainwin.mainwin->window, NULL);
877
* callback for key_press_event on a widget, destroys obj if key was esc
879
int close_on_esc(GtkWidget *widget, GdkEventKey *event, gpointer obj)
881
if(event && event->type == GDK_KEY_PRESS && event->keyval == GDK_Escape) {
882
gtk_widget_destroy(GTK_WIDGET(obj));
883
g_signal_stop_emission_by_name(widget, "key_press_event");
892
* callback for key_press_event on a widget, calls func if key was esc
894
int func_on_esc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
896
void (*func)(GtkWidget *);
898
if(event && event->type == GDK_KEY_PRESS && event->keyval == GDK_Escape) {
899
func = gtk_object_get_data(GTK_OBJECT(window), "close_func");
901
g_signal_stop_emission_by_name(widget, "key_press_event");
909
int tokenize(const struct tokenlist *list, const char *keyword)
913
for(i = 0; list[i].keyword && strlen(list[i].keyword); i++)
914
if(!strcasecmp(list[i].keyword, keyword))
915
return(list[i].token);
921
const char *detokenize(const struct tokenlist *list, int token)
925
for(i = 0; list[i].keyword && strlen(list[i].keyword); i++)
926
if(list[i].token == token)
927
return(list[i].keyword);
929
return(list[0].keyword);
933
const void *detokenize_data(const struct tokenlist *list, int token)
937
for(i = 0; strlen(list[i].keyword); i++)
938
if(list[i].token == token)
939
return(list[i].data);
941
return(list[0].data);
945
* return pointer to username (must be freed)
947
char *get_username(void)
949
struct passwd *pwent;
953
pwent = getpwuid(getuid());
954
if(pwent && pwent->pw_name)
955
username = strdup(pwent->pw_name);
962
/* these should probably belong to struct mainwin_data */
963
static guint context = 0, msgid = 0;
966
* display message in main window's statusbar, and flushes the
969
void statusbar_msg(const char *fmt, ...)
971
/* do not use g_string_sprintf, as it usually does not support
972
numbered arguments */
973
int len = strlen(fmt) * 2;
984
n = g_vsnprintf(buf, len, fmt, ap);
987
if (n > len || n == -1) {
998
statusbar_msg_clear();
1000
msgid = gtk_statusbar_push(GTK_STATUSBAR(mainwin.statusbar),
1002
message_log_append(buf);
1005
/* make sure statusbar gets updated right away */
1006
while(gtk_events_pending())
1007
gtk_main_iteration();
1010
void statusbar_msg_clear()
1014
gtk_statusbar_get_context_id(GTK_STATUSBAR(mainwin.statusbar),
1017
gtk_statusbar_remove(GTK_STATUSBAR(mainwin.statusbar),
1022
* return pointer to GqServer matching the canonical name
1024
GqServer *server_by_canon_name(const char *name,
1025
gboolean include_transient)
1027
GqServer *server = NULL;
1030
if(name == NULL || name[0] == '\0')
1033
server = gq_server_list_get_by_canon_name(gq_server_list_get(), name);
1034
if(!server && include_transient) {
1035
for (I = transient_servers ; I ; I = g_list_next(I)) {
1036
if(!strcmp(((GqServer*)I->data)->canon_name, name)) {
1046
is_transient_server(const GqServer *server) {
1047
g_return_val_if_fail(GQ_IS_SERVER(server), FALSE);
1048
return !gq_server_list_contains(gq_server_list_get(), server);
1052
* check if entry has a subtree
1054
int is_leaf_entry(int error_context,
1055
GqServer *server, char *dn)
1059
int msg, is_leaf, rc;
1065
LDAPControl *ctrls[2] = { NULL, NULL } ;
1068
c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
1069
c.ldctl_value.bv_val = NULL;
1070
c.ldctl_value.bv_len = 0;
1071
c.ldctl_iscritical = 1;
1079
if( (ld = open_connection(error_context, server) ) == NULL) {
1084
statusbar_msg(_("Checking subtree for %s"), dn);
1086
rc = ldap_search_ext(ld, dn, LDAP_SCOPE_ONELEVEL, "(objectclass=*)",
1089
ctrls, /* serverctrls */
1090
NULL, /* clientctrls */
1092
LDAP_NO_LIMIT, /* sizelimit */
1096
if( (ldap_result(ld, msg, 0, NULL, &res) != LDAP_RES_SEARCH_ENTRY))
1099
ldap_abandon(ld, msg);
1102
close_connection(server, FALSE);
1104
statusbar_msg_clear();
1110
* check if child is a direct subentry of possible_parent
1112
gboolean is_direct_parent(char *child, char *possible_parent)
1114
/* SHOULD use gq_ldap_explode_dn for this */
1115
char *c = g_utf8_strchr(child, -1, ',');
1116
if (c && (strcasecmp(c + 1, possible_parent) == 0)) return TRUE;
1121
* check if child is a (possibly indirect) subentry of possible_ancestor
1123
gboolean is_ancestor(char *child, char *possible_ancestor)
1125
char **rdn = gq_ldap_explode_dn(child, FALSE);
1128
gboolean rc = FALSE;
1130
for (n = 0 ; rdn[n] ; n++) {
1133
s = g_string_new("");
1134
for (n-- ; n >= 0 ; n--) {
1135
g_string_insert(s, 0, rdn[n]);
1136
if ((strcasecmp(s->str, possible_ancestor) == 0)) {
1140
g_string_insert(s, 0, ",");
1143
g_string_free(s, TRUE);
1144
gq_exploded_free(rdn);
1149
GList *ar2glist(char *ar[])
1155
/* gtk_combo_set_popdown_strings() can't handle an
1156
empty list, so give it a list with an empty entry */
1157
tmp = g_list_append(NULL, "");
1164
tmp = g_list_append(tmp, ar[i++]);
1171
* pops up a warning dialog (with hand icon), and displays all messages in
1172
* the GList , one per line. The GList is freed here.
1174
void warning_popup(GList *messages)
1177
GtkWidget *window, *vbox1, *vbox2, *vbox3, *label, *hbox0;
1178
GtkWidget *hbox1, *ok_button;
1181
window = gtk_dialog_new();
1182
gtk_container_border_width(GTK_CONTAINER(window), CONTAINER_BORDER_WIDTH);
1183
gtk_window_set_title(GTK_WINDOW(window), _("Warning"));
1184
gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
1185
vbox1 = GTK_DIALOG(window)->vbox;
1186
gtk_widget_show(vbox1);
1188
hbox1 = gtk_hbox_new(FALSE, 0);
1189
gtk_widget_show(hbox1);
1190
gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 10);
1191
pixmap = gtk_image_new_from_file(PACKAGE_PREFIX "/share/pixmaps/gq/warning.xpm");
1192
gtk_widget_show(pixmap);
1193
gtk_box_pack_start(GTK_BOX(hbox1), pixmap, TRUE, TRUE, 10);
1195
vbox2 = gtk_vbox_new(FALSE, 0);
1196
gtk_widget_show(vbox2);
1197
gtk_box_pack_start(GTK_BOX(hbox1), vbox2, TRUE, TRUE, 10);
1201
label = gtk_label_new((char *) list->data);
1202
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1203
gtk_widget_show(label);
1204
gtk_box_pack_start(GTK_BOX(vbox2), label, TRUE, TRUE, 0);
1209
vbox3 = GTK_DIALOG(window)->action_area;
1210
gtk_widget_show(vbox3);
1212
hbox0 = gtk_hbutton_box_new();
1213
gtk_widget_show(hbox0);
1214
gtk_box_pack_start(GTK_BOX(vbox3), hbox0, TRUE, TRUE, 0);
1216
ok_button = gtk_button_new_from_stock(GTK_STOCK_OK);
1218
g_signal_connect_swapped(ok_button, "clicked",
1219
G_CALLBACK(gtk_widget_destroy),
1221
gtk_box_pack_start(GTK_BOX(hbox0), ok_button, FALSE, FALSE, 0);
1222
GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT);
1223
gtk_widget_grab_default(ok_button);
1224
gtk_widget_show(ok_button);
1226
/* what does this mean? PS: 20030928 - FIXME */
1227
g_signal_connect_swapped(window, "destroy",
1228
G_CALLBACK(gtk_widget_destroy),
1231
g_signal_connect_swapped(window, "key_press_event",
1232
G_CALLBACK(close_on_esc),
1235
gtk_widget_show(window);
1237
g_list_free(messages);
1242
void single_warning_popup(char *message)
1246
msglist = g_list_append(NULL, message);
1247
warning_popup(msglist);
1252
#ifdef HAVE_LDAP_STR2OBJECTCLASS
1253
GList *find_at_by_mr_oid(GqServer *server, const char *oid)
1255
GList *list, *srvlist;
1256
LDAPAttributeType *at;
1259
srvlist = server->ss->at;
1261
at = (LDAPAttributeType *) srvlist->data;
1263
if( (at->at_equality_oid && !strcasecmp(oid, at->at_equality_oid)) ||
1264
(at->at_ordering_oid && !strcasecmp(oid, at->at_ordering_oid)) ||
1265
(at->at_substr_oid && !strcasecmp(oid, at->at_substr_oid)) ) {
1266
if(at->at_names && at->at_names[0])
1267
list = g_list_append(list, at->at_names[0]);
1269
list = g_list_append(list, at->at_oid);
1271
srvlist = srvlist->next;
1277
LDAPAttributeType *find_canonical_at_by_at(struct server_schema *schema,
1283
if (!schema) return NULL;
1285
for ( atlist = schema->at ; atlist ; atlist = atlist->next ) {
1286
LDAPAttributeType *at = (LDAPAttributeType *) atlist->data;
1289
for (n = at->at_names ; n && *n ; n++) {
1290
/* printf("%s ", *n); */
1291
if (strcasecmp(*n, attr) == 0) {
1300
GList *find_at_by_s_oid(GqServer *server, const char *oid)
1302
GList *list, *srvlist;
1303
LDAPAttributeType *at;
1306
srvlist = server->ss->at;
1308
at = (LDAPAttributeType *) srvlist->data;
1310
if(at->at_syntax_oid && !strcasecmp(oid, at->at_syntax_oid)) {
1311
if(at->at_names && at->at_names[0])
1312
list = g_list_append(list, at->at_names[0]);
1314
list = g_list_append(list, at->at_oid);
1316
srvlist = srvlist->next;
1323
GList *find_mr_by_s_oid(GqServer *server, const char *oid)
1325
GList *list, *srvlist;
1326
LDAPMatchingRule *mr;
1329
srvlist = server->ss->mr;
1331
mr = (LDAPMatchingRule *) srvlist->data;
1333
if(mr->mr_syntax_oid && !strcasecmp(oid, mr->mr_syntax_oid)) {
1334
if(mr->mr_names && mr->mr_names[0])
1335
list = g_list_append(list, mr->mr_names[0]);
1337
list = g_list_append(list, mr->mr_oid);
1339
srvlist = srvlist->next;
1346
GList *find_oc_by_at(int error_context,
1347
GqServer *server, const char *atname)
1349
GList *list, *oclist;
1350
LDAPObjectClass *oc;
1352
struct server_schema *ss = NULL;
1356
if (server == NULL) return NULL;
1357
ss = get_schema(error_context, server);
1358
if (ss == NULL) return NULL;
1362
oc = (LDAPObjectClass *) oclist->data;
1366
if(oc->oc_at_oids_must) {
1368
while(oc->oc_at_oids_must[i] && !found) {
1369
if(!strcasecmp(atname, oc->oc_at_oids_must[i])) {
1371
if(oc->oc_names && oc->oc_names[0])
1372
list = g_list_append(list, oc->oc_names[0]);
1374
list = g_list_append(list, oc->oc_oid);
1380
if(oc->oc_at_oids_may) {
1382
while(oc->oc_at_oids_may[i] && !found) {
1383
if(!strcasecmp(atname, oc->oc_at_oids_may[i])) {
1385
if(oc->oc_names && oc->oc_names[0])
1386
list = g_list_append(list, oc->oc_names[0]);
1388
list = g_list_append(list, oc->oc_oid);
1394
oclist = oclist->next;
1400
const char *find_s_by_at_oid(int error_context, GqServer *server,
1404
LDAPAttributeType *at;
1406
struct server_schema *ss = NULL;
1408
if (server == NULL) return NULL;
1409
ss = get_schema(error_context, server);
1411
if(ss == NULL || ss->at == NULL)
1416
at = (LDAPAttributeType *) srvlist->data;
1418
for (c = at->at_names ; c && *c ; c++) {
1419
if (!strcasecmp(oid, *c)) {
1420
return at->at_syntax_oid;
1423
srvlist = srvlist->next;
1429
#else /* HAVE_LDAP_STR2OBJECTCLASS */
1432
/* fall back to attributeName to find syntax. */
1434
struct oid2syntax_t {
1439
static struct oid2syntax_t oid2syntax[] = {
1440
{ "userPassword", "1.3.6.1.4.1.1466.115.121.1.40" },
1441
{ "jpegPhoto", "1.3.6.1.4.1.1466.115.121.1.28" },
1442
{ "audio", "1.3.6.1.4.1.1466.115.121.1.4" },
1443
{ "photo", "1.3.6.1.4.1.1466.115.121.1.4" },
1447
const char *find_s_by_at_oid(GqServer *server, const char *oid)
1449
struct oid2syntax_t *os;
1450
for (os = oid2syntax ; os->oid ; os++) {
1451
if (strcasecmp(os->oid, oid) == 0) return os->syntax;
1454
return "1.3.6.1.4.1.1466.115.121.1.3";
1458
#endif /* HAVE_LDAP_STR2OBJECTCLASS */
1461
struct gq_template *find_template_by_name(const char *templatename)
1465
for(I = config->templates ; I ; I = g_list_next(I)) {
1466
struct gq_template *template =
1467
(struct gq_template *) I->data;
1468
if(!strcasecmp(templatename, template->name))
1476
void dump_mods(LDAPMod **mods)
1484
switch(mod->mod_op) {
1485
case LDAP_MOD_ADD: printf("LDAP_MOD_ADD"); break;
1486
case LDAP_MOD_DELETE: printf("LDAP_MOD_DELETE"); break;
1487
case LDAP_MOD_REPLACE: printf("LDAP_MOD_REPLACE"); break;
1488
case LDAP_MOD_BVALUES: printf("LDAP_MOD_BVALUES"); break;
1490
printf(" %s\n", mod->mod_type);
1492
while(mod->mod_values && mod->mod_values[cval]) {
1493
printf("\t%s\n", mod->mod_values[cval]);
1509
static struct popup_comm *new_popup_comm()
1511
struct popup_comm *n = g_malloc0(sizeof(struct popup_comm));
1512
n->ended = n->destroyed = n->rc = 0;
1516
static void free_popup_comm(struct popup_comm *c)
1522
/* gtk2 checked (multiple destroy callbacks safety), confidence 0.7 */
1523
static void query_destroy(GtkWidget *window, struct popup_comm *comm) {
1527
gtk_main_quit(); /* quits only nested main loop */
1528
comm->destroyed = 1;
1531
static void query_ok(GtkWidget *button, struct popup_comm *comm) {
1536
static void query_cancel(GtkWidget *button, struct popup_comm *comm) {
1541
/* pops up a dialog to retrieve user data via a GtkEntry. This
1542
functions waits for the data and puts it into outbuf.
1544
inout_buf afterward points to allocate memory that has to be free'd
1545
using g_free. As an input parameter it points to the current value
1546
of the information to be entered (if not NULL). The passed-in
1547
information will not be changed.
1550
int query_popup(const char *title, gchar **inout_buf, gboolean is_password,
1551
GtkWidget *modal_for)
1553
GtkWidget *window, *vbox1, *vbox2, *label, *inputbox, *button, *hbox0;
1555
GtkWidget *f = gtk_grab_get_current();
1556
struct popup_comm *comm = new_popup_comm();
1558
/* This is a BAD hack - it solves a problem with the query popup
1559
dialog that locks up focus handling with all the
1560
window-managers I have been able to test this with. Actually,
1561
it should be sufficient to let go of the focus, but
1562
hiding/showing seems to work... (as I do not know how to
1563
release the focus in gtk) - Any gtk Hackers around? */
1570
modal_for = gtk_widget_get_toplevel(modal_for);
1573
window = gtk_dialog_new();
1574
gtk_container_border_width(GTK_CONTAINER(window), CONTAINER_BORDER_WIDTH);
1575
gtk_window_set_title(GTK_WINDOW(window), title);
1576
gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
1577
g_signal_connect(window, "destroy",
1578
G_CALLBACK(query_destroy),
1580
g_signal_connect_swapped(window, "key_press_event",
1581
G_CALLBACK(close_on_esc),
1585
gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1586
gtk_window_set_transient_for(GTK_WINDOW(window),
1587
GTK_WINDOW(modal_for));
1590
vbox1 = GTK_DIALOG(window)->vbox;
1591
gtk_widget_show(vbox1);
1593
label = gtk_label_new(title);
1594
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1595
gtk_widget_show(label);
1596
gtk_box_pack_start(GTK_BOX(vbox1), label, TRUE, TRUE, 0);
1598
inputbox = gtk_entry_new();
1600
GTK_WIDGET_SET_FLAGS(inputbox, GTK_CAN_FOCUS);
1601
GTK_WIDGET_SET_FLAGS(inputbox, GTK_CAN_DEFAULT);
1603
gtk_entry_set_visibility(GTK_ENTRY(inputbox), FALSE);
1606
if (inout_buf && *inout_buf) {
1608
gtk_editable_insert_text(GTK_EDITABLE(inputbox),
1609
*inout_buf, strlen(*inout_buf), &pos);
1612
gtk_widget_show(inputbox);
1613
g_signal_connect(inputbox, "activate",
1614
G_CALLBACK(query_ok), comm);
1615
gtk_box_pack_end(GTK_BOX(vbox1), inputbox, TRUE, TRUE, 5);
1617
vbox2 = GTK_DIALOG(window)->action_area;
1618
gtk_container_border_width(GTK_CONTAINER(vbox2), 0);
1619
gtk_widget_show(vbox2);
1621
hbox0 = gtk_hbutton_box_new();
1622
gtk_widget_show(hbox0);
1623
gtk_box_pack_start(GTK_BOX(vbox2), hbox0, TRUE, TRUE, 0);
1625
button = gtk_button_new_from_stock(GTK_STOCK_OK);
1627
g_signal_connect(button, "clicked",
1628
G_CALLBACK(query_ok), comm);
1629
gtk_box_pack_start(GTK_BOX(hbox0), button, FALSE, FALSE, 0);
1630
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1631
GTK_WIDGET_SET_FLAGS(button, GTK_RECEIVES_DEFAULT);
1632
gtk_widget_grab_default(button);
1633
gtk_widget_show(button);
1635
button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1637
g_signal_connect(button, "clicked",
1638
G_CALLBACK(query_cancel),
1641
gtk_box_pack_end(GTK_BOX(hbox0), button, FALSE, FALSE, 0);
1642
gtk_widget_show(button);
1644
/* gtk_window_set_transient_for(GTK_WINDOW(window), */
1645
/* GTK_WINDOW(getMainWin())); */
1646
gtk_widget_grab_focus(GTK_WIDGET(window));
1647
gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1649
gtk_widget_show(window);
1650
gtk_widget_grab_focus(inputbox);
1655
if (! comm->destroyed && comm->rc) {
1656
*inout_buf = gtk_editable_get_chars(GTK_EDITABLE(inputbox), 0, -1);
1661
if (! comm->destroyed ) {
1662
gtk_widget_destroy(window);
1666
free_popup_comm(comm);
1672
/* pops up a question dialog to ask the user a simple question. This
1673
functions waits for the answer and returns it. */
1675
int question_popup(const char *title, const char *question)
1677
GtkWidget *window, *hbox0, *hbox1, *vbox1, *hbox2, *label, *button, *pixmap;
1679
GtkWidget *f = gtk_grab_get_current();
1680
struct popup_comm *comm = new_popup_comm();
1682
/* This is a BAD hack - it solves a problem with the query popup
1683
dialog that locks up focus handling with all the
1684
window-managers I have been able to test this with. Actually,
1685
it should be sufficient to let go of the focus, but
1686
hiding/showing seems to work... (as I do not know how to
1687
release the focus in gtk) - Any gtk Hackers around? */
1693
window = gtk_dialog_new();
1694
gtk_container_border_width(GTK_CONTAINER(window), CONTAINER_BORDER_WIDTH);
1695
gtk_window_set_title(GTK_WINDOW(window), title);
1696
gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
1697
g_signal_connect(window, "destroy",
1698
G_CALLBACK(query_destroy),
1700
g_signal_connect_swapped(window, "key_press_event",
1701
G_CALLBACK(close_on_esc),
1704
gtk_widget_show(window);
1706
vbox1 = GTK_DIALOG(window)->vbox;
1707
gtk_widget_show(vbox1);
1709
hbox1 = gtk_hbox_new(FALSE, 0);
1710
gtk_widget_show(hbox1);
1711
gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 10);
1712
pixmap = gtk_image_new_from_file(PACKAGE_PREFIX "/share/pixmaps/gq/warning.xpm");
1713
gtk_widget_show(pixmap);
1714
gtk_box_pack_start(GTK_BOX(hbox1), pixmap, TRUE, TRUE, 10);
1716
label = gtk_label_new(question);
1717
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
1718
gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1719
gtk_widget_show(label);
1720
gtk_box_pack_end(GTK_BOX(hbox1), label, TRUE, TRUE, 0);
1722
hbox2 = GTK_DIALOG(window)->action_area;
1723
gtk_widget_show(hbox2);
1725
hbox0 = gtk_hbutton_box_new();
1726
gtk_widget_show(hbox0);
1727
gtk_box_pack_start(GTK_BOX(hbox2), hbox0, TRUE, TRUE, 0);
1729
button = gtk_button_new_from_stock(GTK_STOCK_YES);
1731
g_signal_connect(button, "clicked",
1732
G_CALLBACK(query_ok), comm);
1733
gtk_box_pack_start(GTK_BOX(hbox0), button, FALSE, FALSE, 0);
1734
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1735
GTK_WIDGET_SET_FLAGS(button, GTK_RECEIVES_DEFAULT);
1736
gtk_widget_grab_default(button);
1737
gtk_widget_show(button);
1739
button = gtk_button_new_from_stock(GTK_STOCK_NO);
1741
g_signal_connect(button, "clicked",
1742
G_CALLBACK(query_cancel),
1745
gtk_box_pack_end(GTK_BOX(hbox0), button, FALSE, FALSE, 0);
1746
gtk_widget_show(button);
1748
/* gtk_window_set_transient_for(GTK_WINDOW(window), */
1749
/* GTK_WINDOW(getMainWin())); */
1750
gtk_widget_grab_focus(GTK_WIDGET(window));
1751
gtk_window_set_modal(GTK_WINDOW(window), TRUE);
1753
gtk_widget_show(window);
1758
if (! comm->destroyed) {
1759
gtk_widget_destroy(window);
1763
free_popup_comm(comm);
1770
* get all suffixes a server considers itself authorative for.
1773
GList *get_suffixes(int error_context, GqServer *server)
1776
LDAPMessage *res, *e;
1778
int num_suffixes = 0;
1780
char *ldapv3_config[] = {
1785
GList *suffixes = NULL;
1789
if( (ld = open_connection(error_context, server)) == NULL) {
1794
/* try LDAP V3 style config */
1795
statusbar_msg(_("Base search on NULL DN on server '%s'"), server->name);
1796
msg = ldap_search_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
1797
ldapv3_config, 0, &res);
1798
if(msg == LDAP_SUCCESS) {
1799
e = ldap_first_entry(ld, res);
1801
vals = ldap_get_values(ld, e, "namingcontexts");
1803
for(i = 0; vals[i]; i++) {
1804
suffixes = g_list_append(suffixes, g_strdup(vals[i]));
1805
/* add_suffix(entry, ctreeroot, node, vals[i]); */
1808
ldap_value_free(vals);
1810
e = ldap_next_entry(ld, e);
1813
} else if (msg == LDAP_SERVER_DOWN) {
1814
server->server_down++;
1815
/* do not try V2 in case of server down problems */
1818
if(num_suffixes == 0) {
1819
/* try Umich style config */
1820
statusbar_msg(_("Base search on cn=config"));
1821
msg = ldap_search_s(ld, "cn=config", LDAP_SCOPE_BASE,
1822
"(objectclass=*)", NULL, 0, &res);
1824
if(msg == LDAP_SUCCESS) {
1825
e = ldap_first_entry(ld, res);
1829
vals = ldap_get_values(ld, e, "database");
1831
for (valptr = vals; valptr && *valptr; valptr++) {
1835
while (p[i] && p[i] != ':')
1837
while (p[i] && (p[i] == ':' || p[i] == ' '))
1840
int len = strlen(p + i);
1842
while (p[i + len - 1] == ' ')
1846
suffixes = g_list_append(suffixes,
1848
/* add_suffix(entry, ctreeroot, node, p + i); */
1852
ldap_value_free(vals);
1854
e = ldap_next_entry(ld, e);
1857
} else if (msg == LDAP_SERVER_DOWN) {
1858
server->server_down++;
1863
/* add the configured base DN if it's a different one */
1864
if(strlen(server->basedn) && (g_list_find_custom(suffixes, server->basedn, (GCompareFunc) strcmp) == NULL)) {
1865
suffixes = g_list_append(suffixes, g_strdup(server->basedn));
1870
close_connection(server, FALSE);
1872
statusbar_msg(ngettext("One suffix found", "%d suffixes found",
1876
return g_list_first(suffixes);
1879
#ifdef HAVE_LDAP_STR2DN
1881
/* OpenLDAP 2.1 both deprecated and broke ldap_explode_dn in one go (I
1882
won't comment on this).
1884
NOTE: this is just a first try to adapt code from Pierangelo
1885
Masarati <masarati@aero.polimi.it>
1889
gq_ldap_explode_dn(gchar const* dn, int dummy) {
1891
#if LDAP_API_VERSION > 2004
1896
GArray* array = NULL;
1897
gchar **retval = NULL;
1899
rc = ldap_str2dn(dn, &parts, LDAP_DN_FORMAT_LDAPV3);
1901
if (rc != LDAP_SUCCESS || parts == NULL) {
1905
array = g_array_new(TRUE, TRUE, sizeof(gchar*));
1906
for(i = 0; parts[i]; i++) {
1909
#if LDAP_API_VERSION > 2004
1914
&part, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
1916
/* don't append the last (empty) part, to be compatible
1917
* to ldap_explode_dn() */
1918
g_array_append_val(array, part);
1921
retval = (gchar**)array->data;
1922
g_array_free(array, FALSE);
1926
void gq_exploded_free(char **exploded_dn)
1928
if (exploded_dn) free(exploded_dn);
1933
static GtkWidget *enable_uline(GtkWidget *label) {
1934
gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
1938
static GtkWidget *bin_enable_uline(GtkWidget *w) {
1940
l = gtk_bin_get_child(GTK_BIN(w));
1946
GtkWidget *gq_label_new(const char *text) {
1947
return gtk_label_new_with_mnemonic(text);
1951
GtkWidget *gq_radio_button_new_with_label(GSList *group,
1954
return bin_enable_uline(gtk_radio_button_new_with_label(group, label));
1957
GtkWidget *gq_menu_item_new_with_label(const gchar *text) {
1958
return bin_enable_uline(gtk_menu_item_new_with_label(text));
1961
GtkWidget *gq_check_button_new_with_label(const gchar *text) {
1962
return bin_enable_uline(gtk_check_button_new_with_label(text));
1965
GtkWidget *gq_button_new_with_label(const gchar *text) {
1966
return bin_enable_uline(gtk_button_new_with_label(text));
1969
GtkWidget *gq_toggle_button_new_with_label(const gchar *text) {
1970
return bin_enable_uline(gtk_toggle_button_new_with_label(text));
1974
struct dn_on_server *new_dn_on_server(const char *d,
1977
struct dn_on_server *dos = g_malloc0(sizeof(struct dn_on_server));
1978
dos->server = g_object_ref(s);
1981
dos->dn = g_strdup(d);
1989
void free_dn_on_server(struct dn_on_server *s)
1994
g_object_unref(s->server);