r11382: Require number of required M4 macros
[abartlet/samba.git/.git] / source4 / gtk / tools / gregedit.c
1 /* 
2    Unix SMB/CIFS implementation.
3    GTK+ registry frontend
4    
5    Copyright (C) Jelmer Vernooij 2004-2005
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "lib/registry/registry.h"
24 #include "lib/cmdline/popt_common.h"
25 #include "gtk/common/select.h"
26 #include "gtk/common/gtk-smb.h"
27
28 static GtkTreeStore *store_keys;
29 static GtkListStore *store_vals;
30 static GtkWidget *tree_keys;
31 static GtkWidget *tree_vals;
32 static GtkWidget *mainwin;
33 static GtkWidget *mnu_add_key, *mnu_set_value, *mnu_del_key, *mnu_del_value, *mnu_find;
34 static TALLOC_CTX *mem_ctx; /* FIXME: Split up */
35
36 static GtkWidget *save;
37 static GtkWidget *save_as;
38 static GtkWidget* create_openfilewin (void);
39 static GtkWidget* create_savefilewin (void);
40 struct registry_context *registry = NULL;
41 struct registry_key *current_key = NULL;
42
43 static GtkWidget* create_FindDialog (void)
44 {
45   GtkWidget *FindDialog;
46   GtkWidget *dialog_vbox2;
47   GtkWidget *vbox1;
48   GtkWidget *hbox1;
49   GtkWidget *label6;
50   GtkWidget *entry_pattern;
51   GtkWidget *frame3;
52   GtkWidget *alignment3;
53   GtkWidget *vbox2;
54   GtkWidget *checkbutton1;
55   GtkWidget *checkbutton2;
56   GtkWidget *checkbutton3;
57   GtkWidget *label7;
58   GtkWidget *dialog_action_area2;
59   GtkWidget *cancelbutton2;
60   GtkWidget *okbutton2;
61
62   FindDialog = gtk_dialog_new ();
63   gtk_window_set_title (GTK_WINDOW (FindDialog), "Find Key or Value");
64   gtk_window_set_resizable (GTK_WINDOW (FindDialog), FALSE);
65   gtk_window_set_type_hint (GTK_WINDOW (FindDialog), GDK_WINDOW_TYPE_HINT_DIALOG);
66
67   dialog_vbox2 = GTK_DIALOG (FindDialog)->vbox;
68
69   vbox1 = gtk_vbox_new (FALSE, 0);
70   gtk_box_pack_start (GTK_BOX (dialog_vbox2), vbox1, TRUE, TRUE, 0);
71
72   hbox1 = gtk_hbox_new (FALSE, 0);
73   gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
74
75   label6 = gtk_label_new ("Find String");
76   gtk_box_pack_start (GTK_BOX (hbox1), label6, FALSE, FALSE, 0);
77
78   entry_pattern = gtk_entry_new ();
79   gtk_box_pack_start (GTK_BOX (hbox1), entry_pattern, TRUE, TRUE, 0);
80
81   frame3 = gtk_frame_new (NULL);
82   gtk_box_pack_start (GTK_BOX (vbox1), frame3, TRUE, TRUE, 0);
83   gtk_frame_set_shadow_type (GTK_FRAME (frame3), GTK_SHADOW_NONE);
84
85   alignment3 = gtk_alignment_new (0.5, 0.5, 1, 1);
86   gtk_container_add (GTK_CONTAINER (frame3), alignment3);
87   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment3), 0, 0, 12, 0);
88
89   vbox2 = gtk_vbox_new (FALSE, 0);
90   gtk_container_add (GTK_CONTAINER (alignment3), vbox2);
91
92   checkbutton1 = gtk_check_button_new_with_mnemonic ("_Key Names");
93   gtk_box_pack_start (GTK_BOX (vbox2), checkbutton1, FALSE, FALSE, 0);
94
95   checkbutton2 = gtk_check_button_new_with_mnemonic ("_Value Names");
96   gtk_box_pack_start (GTK_BOX (vbox2), checkbutton2, FALSE, FALSE, 0);
97
98   checkbutton3 = gtk_check_button_new_with_mnemonic ("Value _Data");
99   gtk_box_pack_start (GTK_BOX (vbox2), checkbutton3, FALSE, FALSE, 0);
100
101   label7 = gtk_label_new ("<b>Search in</b>");
102   gtk_frame_set_label_widget (GTK_FRAME (frame3), label7);
103   gtk_label_set_use_markup (GTK_LABEL (label7), TRUE);
104
105   dialog_action_area2 = GTK_DIALOG (FindDialog)->action_area;
106   gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2), GTK_BUTTONBOX_END);
107
108   cancelbutton2 = gtk_button_new_from_stock ("gtk-cancel");
109   gtk_dialog_add_action_widget (GTK_DIALOG (FindDialog), cancelbutton2, GTK_RESPONSE_CANCEL);
110   GTK_WIDGET_SET_FLAGS (cancelbutton2, GTK_CAN_DEFAULT);
111
112   okbutton2 = gtk_button_new_from_stock ("gtk-ok");
113   gtk_dialog_add_action_widget (GTK_DIALOG (FindDialog), okbutton2, GTK_RESPONSE_OK);
114   GTK_WIDGET_SET_FLAGS (okbutton2, GTK_CAN_DEFAULT);
115
116   gtk_widget_show_all (dialog_vbox2);
117
118   return FindDialog;
119 }
120
121 static GtkWidget* create_SetValueDialog (GtkWidget **entry_name, GtkWidget **entry_type, GtkWidget **entry_data)
122 {
123   GtkWidget *SetValueDialog;
124   GtkWidget *dialog_vbox1;
125   GtkWidget *table1;
126   GtkWidget *label3;
127   GtkWidget *label4;
128   GtkWidget *label5;
129   GtkWidget *entry_value_name;
130   GtkWidget *value_data;
131   GtkWidget *combo_data_type;
132   GtkWidget *dialog_action_area1;
133   GtkWidget *cancelbutton1;
134   GtkWidget *okbutton1;
135
136   SetValueDialog = gtk_dialog_new ();
137   gtk_window_set_title (GTK_WINDOW (SetValueDialog), "Set Registry Value");
138   gtk_window_set_position (GTK_WINDOW (SetValueDialog), GTK_WIN_POS_CENTER);
139   gtk_window_set_resizable (GTK_WINDOW (SetValueDialog), FALSE);
140   gtk_window_set_type_hint (GTK_WINDOW (SetValueDialog), GDK_WINDOW_TYPE_HINT_DIALOG);
141
142   dialog_vbox1 = GTK_DIALOG (SetValueDialog)->vbox;
143
144   table1 = gtk_table_new (3, 2, FALSE);
145   gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 0);
146
147   label3 = gtk_label_new ("Value name:");
148   gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 0, 1,
149                     (GtkAttachOptions) (GTK_FILL),
150                     (GtkAttachOptions) (0), 0, 0);
151   gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5);
152
153   label4 = gtk_label_new ("Data Type:");
154   gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 1, 2,
155                     (GtkAttachOptions) (GTK_FILL),
156                     (GtkAttachOptions) (0), 0, 0);
157   gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5);
158
159   label5 = gtk_label_new ("Data:");
160   gtk_table_attach (GTK_TABLE (table1), label5, 0, 1, 2, 3,
161                     (GtkAttachOptions) (GTK_FILL),
162                     (GtkAttachOptions) (0), 0, 0);
163   gtk_misc_set_alignment (GTK_MISC (label5), 0, 0.5);
164
165   *entry_name = entry_value_name = gtk_entry_new ();
166   gtk_table_attach (GTK_TABLE (table1), entry_value_name, 1, 2, 0, 1,
167                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
168                     (GtkAttachOptions) (0), 0, 0);
169
170   *entry_data = value_data = gtk_entry_new ();
171   gtk_table_attach (GTK_TABLE (table1), value_data, 1, 2, 2, 3,
172                     (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
173                     (GtkAttachOptions) (0), 0, 0);
174
175   *entry_type = combo_data_type = gtk_combo_box_new_text ();
176
177   gtk_combo_box_append_text(GTK_COMBO_BOX(combo_data_type), "REG_NONE");
178   gtk_combo_box_append_text(GTK_COMBO_BOX(combo_data_type), "REG_SZ");
179   gtk_combo_box_append_text(GTK_COMBO_BOX(combo_data_type), "REG_EXPAND_SZ");
180   gtk_combo_box_append_text(GTK_COMBO_BOX(combo_data_type), "REG_BINARY");
181   gtk_combo_box_append_text(GTK_COMBO_BOX(combo_data_type), "REG_DWORD_LE");
182   gtk_combo_box_append_text(GTK_COMBO_BOX(combo_data_type), "REG_DWORD_BE");
183   
184   gtk_table_attach (GTK_TABLE (table1), combo_data_type, 1, 2, 1, 2,
185                     (GtkAttachOptions) (GTK_FILL),
186                     (GtkAttachOptions) (GTK_FILL), 0, 0);
187
188   dialog_action_area1 = GTK_DIALOG (SetValueDialog)->action_area;
189   gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);
190
191   cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel");
192   gtk_dialog_add_action_widget (GTK_DIALOG (SetValueDialog), cancelbutton1, GTK_RESPONSE_CANCEL);
193   GTK_WIDGET_SET_FLAGS (cancelbutton1, GTK_CAN_DEFAULT);
194
195   okbutton1 = gtk_button_new_from_stock ("gtk-ok");
196   gtk_dialog_add_action_widget (GTK_DIALOG (SetValueDialog), okbutton1, GTK_RESPONSE_OK);
197   GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT);
198
199   gtk_widget_show_all (dialog_vbox1);
200
201   return SetValueDialog;
202 }
203
204 static GtkWidget* create_NewKeyDialog (GtkWidget **name_entry)
205 {
206   GtkWidget *NewKeyDialog;
207   GtkWidget *dialog_vbox2;
208   GtkWidget *hbox1;
209   GtkWidget *label6;
210   GtkWidget *entry_key_name;
211   GtkWidget *dialog_action_area2;
212   GtkWidget *cancelbutton2;
213   GtkWidget *okbutton2;
214
215   NewKeyDialog = gtk_dialog_new ();
216   gtk_window_set_title (GTK_WINDOW (NewKeyDialog), "New Registry Key");
217   gtk_window_set_position (GTK_WINDOW (NewKeyDialog), GTK_WIN_POS_CENTER);
218   gtk_window_set_resizable (GTK_WINDOW (NewKeyDialog), FALSE);
219   gtk_window_set_type_hint (GTK_WINDOW (NewKeyDialog), GDK_WINDOW_TYPE_HINT_DIALOG);
220
221   dialog_vbox2 = GTK_DIALOG (NewKeyDialog)->vbox;
222
223   hbox1 = gtk_hbox_new (FALSE, 0);
224   gtk_box_pack_start (GTK_BOX (dialog_vbox2), hbox1, TRUE, TRUE, 0);
225
226   label6 = gtk_label_new ("Name:");
227   gtk_box_pack_start (GTK_BOX (hbox1), label6, FALSE, FALSE, 0);
228
229   entry_key_name = gtk_entry_new ();
230   gtk_box_pack_start (GTK_BOX (hbox1), entry_key_name, TRUE, TRUE, 0);
231
232   dialog_action_area2 = GTK_DIALOG (NewKeyDialog)->action_area;
233   gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2), GTK_BUTTONBOX_END);
234
235   *name_entry = entry_key_name;
236
237   cancelbutton2 = gtk_button_new_from_stock ("gtk-cancel");
238   gtk_dialog_add_action_widget (GTK_DIALOG (NewKeyDialog), cancelbutton2, GTK_RESPONSE_CANCEL);
239   GTK_WIDGET_SET_FLAGS (cancelbutton2, GTK_CAN_DEFAULT);
240
241   okbutton2 = gtk_button_new_from_stock ("gtk-ok");
242   gtk_dialog_add_action_widget (GTK_DIALOG (NewKeyDialog), okbutton2, GTK_RESPONSE_OK);
243   GTK_WIDGET_SET_FLAGS (okbutton2, GTK_CAN_DEFAULT);
244
245   gtk_widget_show_all (dialog_vbox2);
246
247   return NewKeyDialog;
248 }
249
250 static void expand_key(GtkTreeView *treeview, GtkTreeIter *parent, GtkTreePath *arg2)
251 {
252         GtkTreeIter firstiter, iter, tmpiter;
253         struct registry_key *k, *sub;
254         char *name;
255         WERROR error;
256         int i;
257
258         gtk_tree_model_iter_children(GTK_TREE_MODEL(store_keys), &firstiter, parent);
259
260         /* See if this row has ever had a name gtk_tree_store_set()'ed to it.
261            If not, read the directory contents */
262         gtk_tree_model_get(GTK_TREE_MODEL(store_keys), &firstiter, 0, &name, -1);
263
264         if(name) return;
265
266         gtk_tree_model_get(GTK_TREE_MODEL(store_keys), parent, 1, &k, -1);
267
268         g_assert(k);
269         
270         for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, k, i, &sub)); i++) {
271                 uint32_t count;
272                 /* Replace the blank child with the first directory entry
273            You may be tempted to remove the blank child node and then 
274            append a new one.  Don't.  If you remove the blank child 
275            node GTK gets confused and won't expand the parent row. */
276
277                 if(i == 0) {
278                         iter = firstiter;
279                 } else {
280                         gtk_tree_store_append(store_keys, &iter, parent);
281                 }
282                 gtk_tree_store_set (store_keys,
283                                             &iter, 
284                                                 0,
285                                                 sub->name,
286                                                 1, 
287                                                 sub,
288                                                 -1);
289                 
290                 if(W_ERROR_IS_OK(reg_key_num_subkeys(sub, &count)) && count > 0) 
291                         gtk_tree_store_append(store_keys, &tmpiter, &iter);
292         }
293
294         if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) { 
295                 gtk_show_werror(mainwin, "While enumerating subkeys", error);
296         }
297 }
298
299 static void registry_load_hive(struct registry_key *root)
300 {
301         GtkTreeIter iter, tmpiter;
302         gtk_list_store_clear(store_vals);
303         /* Add the root */
304         gtk_tree_store_append(store_keys, &iter, NULL);
305         gtk_tree_store_set (store_keys,
306                                     &iter, 
307                                         0,
308                                         root->name?root->name:"",
309                                         1,
310                                         root,
311                                         -1);
312
313         gtk_tree_store_append(store_keys, &tmpiter, &iter);
314
315         gtk_widget_set_sensitive( save, True );
316         gtk_widget_set_sensitive( save_as, True );
317 }
318
319 static void registry_load_root(void) 
320 {
321         struct registry_key *root;
322         uint32_t i = 0;
323         if(!registry) return;
324
325         gtk_list_store_clear(store_vals);
326         gtk_tree_store_clear(store_keys);
327
328         for(i = HKEY_CLASSES_ROOT; i <= HKEY_PERFORMANCE_NLSTEXT; i++) 
329         {
330                 if (!W_ERROR_IS_OK(reg_get_predefined_key(registry, i, &root))) { continue; }
331
332                 registry_load_hive(root);
333         }
334 }
335
336 static void on_open_file_activate (GtkMenuItem *menuitem, gpointer user_data)
337 {
338         GtkWidget *openfilewin;
339         gint result;
340         char *filename, *tmp;
341         struct registry_key *root;
342         WERROR error;
343
344         openfilewin = create_openfilewin();
345
346         result = gtk_dialog_run(GTK_DIALOG(openfilewin));
347
348         switch(result) {
349         case GTK_RESPONSE_OK:
350                 filename = strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(openfilewin)));
351                 error = reg_open_hive(NULL, user_data, filename, NULL, &root);
352                 if(!W_ERROR_IS_OK(error)) {
353                         gtk_show_werror(mainwin, "Error while opening hive", error);
354                         break;
355                 }
356
357                 tmp = g_strdup_printf("Registry Editor - %s", filename);
358                 gtk_window_set_title (GTK_WINDOW (mainwin), tmp);
359                 g_free(tmp);
360                 gtk_tree_store_clear(store_keys);
361                 registry_load_hive(root);
362                 break;
363         default:
364                 break;
365         }
366
367         gtk_widget_destroy(openfilewin);
368 }
369
370 static void on_open_gconf_activate(GtkMenuItem *menuitem, gpointer user_data)
371 {
372         struct registry_key *root;
373         WERROR error = reg_open_hive(NULL, "gconf", NULL, NULL, &root);
374         if(!W_ERROR_IS_OK(error)) {
375                 gtk_show_werror(mainwin, "Error while opening GConf", error);
376                 return;
377         }
378
379         gtk_window_set_title (GTK_WINDOW (mainwin), "Registry Editor - GConf");
380
381         gtk_tree_store_clear(store_keys);
382         registry_load_hive(root);
383 }
384
385 static void on_open_local_activate(GtkMenuItem *menuitem, gpointer user_data)
386 {
387         WERROR error = reg_open_local(&registry);
388         if(!W_ERROR_IS_OK(error)) {
389                 gtk_show_werror(mainwin, "Error while opening local registry", error);
390                 return;
391         }
392         registry_load_root();
393 }
394
395 static void on_open_remote_activate(GtkMenuItem *menuitem, gpointer user_data)
396 {
397         char *tmp;
398         GtkWidget *rpcwin = GTK_WIDGET(gtk_rpc_binding_dialog_new(NULL));
399         gint result = gtk_dialog_run(GTK_DIALOG(rpcwin));
400         WERROR error;
401         struct cli_credentials *creds;
402         
403         if(result != GTK_RESPONSE_ACCEPT)
404         {
405                 gtk_widget_destroy(rpcwin);
406                 return;
407         }
408
409         creds = cli_credentials_init(mem_ctx);
410         cli_credentials_guess(creds);
411         cli_credentials_set_gtk_callbacks(creds);
412
413         error = reg_open_remote(&registry, 
414                                 creds,
415                                 gtk_rpc_binding_dialog_get_binding_string(GTK_RPC_BINDING_DIALOG(rpcwin), mem_ctx),
416                                 NULL);
417
418         if(!W_ERROR_IS_OK(error)) {
419                 gtk_show_werror(mainwin, "Error while opening remote registry", error);
420                 gtk_widget_destroy(rpcwin);
421                 return;
422         }
423
424         tmp = g_strdup_printf("Registry Editor - Remote Registry at %s", gtk_rpc_binding_dialog_get_host(GTK_RPC_BINDING_DIALOG(rpcwin)));
425         gtk_window_set_title (GTK_WINDOW (mainwin), tmp);
426         g_free(tmp);
427
428         registry_load_root();
429
430
431         gtk_widget_destroy(rpcwin);
432 }
433
434
435 static void on_save_as_activate(GtkMenuItem *menuitem, gpointer user_data)
436 {
437         gint result;
438         WERROR error;
439         GtkWidget *savefilewin = create_savefilewin();
440         result = gtk_dialog_run(GTK_DIALOG(savefilewin));
441         switch(result) {
442         case GTK_RESPONSE_OK:
443         /* FIXME:               error = reg_dump(registry, gtk_file_selection_get_filename(GTK_FILE_SELECTION(savefilewin))); */
444                 if(!W_ERROR_IS_OK(error)) {
445                         gtk_show_werror(mainwin, "Error while saving as", error);
446                 }
447                 break;
448
449         default:
450                 break;
451
452         }
453         gtk_widget_destroy(savefilewin);
454 }
455
456
457 static void on_quit_activate(GtkMenuItem *menuitem, gpointer user_data)
458 {
459         gtk_main_quit();
460 }
461
462
463 static void on_delete_value_activate(GtkMenuItem *menuitem, gpointer user_data)
464 {
465         WERROR error;
466         GtkTreeIter iter;
467         const char *value;
468
469         if (!gtk_tree_selection_get_selected (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_vals)), NULL, &iter)) {
470                 return;
471         }
472
473         gtk_tree_model_get(GTK_TREE_MODEL(store_vals), &iter, 0, &value, -1);
474         
475         error = reg_del_value(current_key, value);
476
477         if (!W_ERROR_IS_OK(error)) {
478                 gtk_show_werror(NULL, "Error while deleting value", error);
479                 return;
480         }
481 }
482
483 static void on_delete_key_activate(GtkMenuItem *menuitem, gpointer user_data)
484 {
485         WERROR error;
486         GtkTreeIter iter, parentiter;
487         struct registry_key *parent_key;
488
489         if (!gtk_tree_selection_get_selected (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_keys)), NULL, &iter)) {
490                 return;
491         }
492
493         if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(store_keys), &parentiter, &iter)) {
494                 return;
495         }
496         
497         gtk_tree_model_get(GTK_TREE_MODEL(store_keys), &parentiter, 1, &parent_key, -1);
498         
499         error = reg_key_del(parent_key, current_key->name);
500
501         if (!W_ERROR_IS_OK(error)) {
502                 gtk_show_werror(NULL, "Error while deleting key", error);
503                 return;
504         }
505 }
506
507 static void on_add_key_activate(GtkMenuItem *menuitem, gpointer user_data)
508 {
509         GtkWidget *entry;
510         GtkDialog *addwin = GTK_DIALOG(create_NewKeyDialog(&entry));
511         gint result = gtk_dialog_run(addwin);
512
513         if (result == GTK_RESPONSE_OK)
514         {
515                 struct registry_key *newkey;
516                 WERROR error = reg_key_add_name(mem_ctx, current_key, gtk_entry_get_text(GTK_ENTRY(entry)), 0, NULL, &newkey);
517
518                 if (!W_ERROR_IS_OK(error)) {
519                         gtk_show_werror(NULL, "Error while adding key", error);
520                 }
521         }
522
523         gtk_widget_destroy(GTK_WIDGET(addwin));
524 }
525
526 static void on_value_activate(GtkTreeView *treeview, GtkTreePath *arg1,
527          GtkTreeViewColumn *arg2, gpointer user_data)
528 {
529         GtkWidget *entry_name, *entry_type, *entry_value;
530         GtkDialog *addwin = GTK_DIALOG(create_SetValueDialog(&entry_name, &entry_type, &entry_value));
531         GtkTreeIter iter;
532         struct registry_value *value;
533         gint result;
534
535         gtk_tree_model_get_iter(GTK_TREE_MODEL(store_vals), &iter, arg1);
536
537         gtk_tree_model_get(GTK_TREE_MODEL(store_vals), &iter, 3, &value, -1);
538
539         gtk_widget_set_sensitive(entry_name, FALSE);
540         gtk_entry_set_text(GTK_ENTRY(entry_name), value->name);
541         gtk_entry_set_text(GTK_ENTRY(entry_value), reg_val_data_string(mem_ctx, value->data_type, &value->data));
542         gtk_combo_box_set_active(GTK_COMBO_BOX(entry_type), value->data_type);
543         
544         result = gtk_dialog_run(addwin);
545         if (result == GTK_RESPONSE_OK) 
546         {
547                 WERROR error;
548                 DATA_BLOB data;
549                 uint32_t data_type;
550                 
551                 reg_string_to_val(mem_ctx,str_regtype(gtk_combo_box_get_active(GTK_COMBO_BOX(entry_type))), gtk_entry_get_text(GTK_ENTRY(entry_value)), &data_type, &data);
552                 
553                 error = reg_val_set(current_key, gtk_entry_get_text(GTK_ENTRY(entry_name)), data_type, data);
554
555                 if (!W_ERROR_IS_OK(error)) {
556                         gtk_show_werror(NULL, "Error while setting value", error);
557                 }
558         }
559         gtk_widget_destroy(GTK_WIDGET(addwin));
560 }
561
562 static void on_set_value_activate(GtkMenuItem *menuitem, gpointer user_data)
563 {
564         GtkWidget *entry_name, *entry_type, *entry_value;
565         GtkDialog *addwin = GTK_DIALOG(create_SetValueDialog(&entry_name, &entry_type, &entry_value));
566         gint result = gtk_dialog_run(addwin);
567         if (result == GTK_RESPONSE_OK) 
568         {
569                 WERROR error;
570                 uint32_t data_type;
571                 DATA_BLOB data;
572                 
573                 reg_string_to_val(mem_ctx,str_regtype(gtk_combo_box_get_active(GTK_COMBO_BOX(entry_type))), gtk_entry_get_text(GTK_ENTRY(entry_value)), &data_type, &data);
574                 
575                 error = reg_val_set(current_key, gtk_entry_get_text(GTK_ENTRY(entry_name)), data_type, data);
576
577                 if (!W_ERROR_IS_OK(error)) {
578                         gtk_show_werror(NULL, "Error while setting value", error);
579                 }
580         }
581         gtk_widget_destroy(GTK_WIDGET(addwin));
582 }
583
584 static void on_find_activate(GtkMenuItem *menuitem, gpointer user_data)
585 {
586         GtkDialog *findwin = GTK_DIALOG(create_FindDialog());
587         /*gint result = gtk_dialog_run(findwin);
588         FIXME */
589         gtk_widget_destroy(GTK_WIDGET(findwin));
590 }
591
592 static void on_about_activate (GtkMenuItem *menuitem, gpointer user_data)
593 {
594     GtkDialog *aboutwin = GTK_DIALOG(create_gtk_samba_about_dialog("gregedit"));
595     gtk_dialog_run(aboutwin);
596     gtk_widget_destroy(GTK_WIDGET(aboutwin));
597 }
598
599 static gboolean on_key_activate(GtkTreeSelection *selection,
600                                              GtkTreeModel *model,
601                                              GtkTreePath *path,
602                                              gboolean path_currently_selected,
603                                              gpointer data)
604 {
605         int i;
606         struct registry_key *k;
607         struct registry_value *val;
608         WERROR error;
609         GtkTreeIter parent;
610
611         gtk_widget_set_sensitive(mnu_add_key, !path_currently_selected);
612         gtk_widget_set_sensitive(mnu_set_value, !path_currently_selected);
613         gtk_widget_set_sensitive(mnu_del_key, !path_currently_selected);
614         gtk_widget_set_sensitive(mnu_del_value, !path_currently_selected);
615         gtk_widget_set_sensitive(mnu_find, !path_currently_selected);
616
617         if(path_currently_selected) { 
618                 current_key = NULL; 
619                 return TRUE; 
620         }
621
622         gtk_tree_model_get_iter(GTK_TREE_MODEL(store_keys), &parent, path);
623         gtk_tree_model_get(GTK_TREE_MODEL(store_keys), &parent, 1, &k, -1);
624
625         current_key = k;
626
627         if (!k) return FALSE;
628
629         gtk_list_store_clear(store_vals);
630
631         for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, k, i, &val)); i++) {
632                 GtkTreeIter iter;
633                 gtk_list_store_append(store_vals, &iter);
634                 gtk_list_store_set (store_vals,
635                                             &iter, 
636                                                 0,
637                                                 val->name,
638                                                 1,
639                                                 str_regtype(val->data_type),
640                                                 2,
641                                                 reg_val_data_string(mem_ctx, val->data_type, &val->data),
642                                                 3, 
643                                                 val,
644                                                 -1);
645         }
646
647         if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
648                  gtk_show_werror(mainwin, "Error while enumerating values",  error);
649                  return FALSE;
650         }
651         return TRUE;
652 }
653
654 static GtkWidget* create_mainwindow(void)
655 {
656         GtkWidget *vbox1;
657         GtkWidget *menubar;
658         GtkWidget *menu_file;
659         GtkWidget *menu_file_menu;
660         GtkWidget *open_nt4;
661         GtkWidget *open_ldb;
662         GtkWidget *open_w95;
663         GtkWidget *open_gconf;
664         GtkWidget *open_remote;
665         GtkWidget *open_local;
666         GtkWidget *separatormenuitem1;
667         GtkWidget *quit;
668         GtkWidget *men_key;
669         GtkWidget *men_key_menu;
670         GtkCellRenderer *renderer;
671         GtkTreeViewColumn *curcol;
672         GtkWidget *help;
673         GtkWidget *help_menu;
674         GtkWidget *about;
675         GtkWidget *hbox1;
676         GtkWidget *scrolledwindow1;
677         GtkWidget *scrolledwindow2;
678         GtkWidget *statusbar;
679         GtkAccelGroup *accel_group;
680
681         accel_group = gtk_accel_group_new ();
682
683         mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
684         gtk_window_set_title (GTK_WINDOW (mainwin), "Registry editor");
685         gtk_window_set_default_size (GTK_WINDOW (mainwin), 642, 562);
686
687         vbox1 = gtk_vbox_new (FALSE, 0);
688         gtk_container_add (GTK_CONTAINER (mainwin), vbox1);
689
690         menubar = gtk_menu_bar_new ();
691         gtk_box_pack_start (GTK_BOX (vbox1), menubar, FALSE, FALSE, 0);
692
693         menu_file = gtk_menu_item_new_with_mnemonic ("_File");
694         gtk_container_add (GTK_CONTAINER (menubar), menu_file);
695
696         menu_file_menu = gtk_menu_new ();
697         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_file), menu_file_menu);
698
699         open_local = gtk_menu_item_new_with_mnemonic ("Open _Local");
700         gtk_container_add (GTK_CONTAINER (menu_file_menu), open_local);
701         g_signal_connect ((gpointer) open_local, "activate",
702                                                   G_CALLBACK (on_open_local_activate), NULL);
703
704         if(reg_has_backend("rpc")) {
705                 open_remote = gtk_menu_item_new_with_mnemonic ("Open _Remote");
706                 gtk_container_add (GTK_CONTAINER (menu_file_menu), open_remote);
707
708                 g_signal_connect ((gpointer) open_remote, "activate",
709                                                   G_CALLBACK (on_open_remote_activate),
710                                                   NULL);
711         }
712
713         separatormenuitem1 = gtk_menu_item_new ();
714         gtk_container_add (GTK_CONTAINER (menu_file_menu), separatormenuitem1);
715         gtk_widget_set_sensitive (separatormenuitem1, FALSE);
716
717
718         if(reg_has_backend("nt4")) {
719                 open_nt4 = gtk_image_menu_item_new_with_mnemonic("Open _NT4 file");
720                 gtk_container_add (GTK_CONTAINER (menu_file_menu), open_nt4);
721
722                 g_signal_connect(open_nt4, "activate",
723                                  G_CALLBACK (on_open_file_activate),
724                                  discard_const_p(char, "nt4"));
725         }
726
727         if(reg_has_backend("w95")) {
728                 open_w95 = gtk_image_menu_item_new_with_mnemonic("Open Win_9x file");
729                 gtk_container_add (GTK_CONTAINER (menu_file_menu), open_w95);
730
731                 g_signal_connect (open_w95, "activate",
732                                   G_CALLBACK (on_open_file_activate),
733                                   discard_const_p(char, "w95"));
734         }
735
736         if(reg_has_backend("gconf")) {
737                 open_gconf = gtk_image_menu_item_new_with_mnemonic ("Open _GConf");
738                 gtk_container_add (GTK_CONTAINER (menu_file_menu), open_gconf);
739
740                 g_signal_connect ((gpointer) open_gconf, "activate",
741                                                   G_CALLBACK (on_open_gconf_activate),
742                                                   NULL);
743         }
744
745         if(reg_has_backend("ldb")) {
746                 open_ldb = gtk_image_menu_item_new_with_mnemonic("Open _LDB file");
747                 gtk_container_add (GTK_CONTAINER (menu_file_menu), open_ldb);
748
749                 g_signal_connect(open_ldb, "activate",
750                                  G_CALLBACK (on_open_file_activate),
751                                  discard_const_p(char, "ldb"));
752         }
753
754         separatormenuitem1 = gtk_menu_item_new ();
755         gtk_container_add (GTK_CONTAINER (menu_file_menu), separatormenuitem1);
756         gtk_widget_set_sensitive (separatormenuitem1, FALSE);
757
758         save = gtk_image_menu_item_new_from_stock ("gtk-save", accel_group);
759         gtk_widget_set_sensitive( save, False );
760         gtk_container_add (GTK_CONTAINER (menu_file_menu), save);
761
762         save_as = gtk_image_menu_item_new_from_stock ("gtk-save-as", accel_group);
763         gtk_widget_set_sensitive( save_as, False );
764         gtk_container_add (GTK_CONTAINER (menu_file_menu), save_as);
765
766         separatormenuitem1 = gtk_menu_item_new ();
767         gtk_container_add (GTK_CONTAINER (menu_file_menu), separatormenuitem1);
768         gtk_widget_set_sensitive (separatormenuitem1, FALSE);
769
770         quit = gtk_image_menu_item_new_from_stock ("gtk-quit", accel_group);
771         gtk_container_add (GTK_CONTAINER (menu_file_menu), quit);
772
773         men_key = gtk_menu_item_new_with_mnemonic ("_Key");
774         gtk_container_add (GTK_CONTAINER (menubar), men_key);
775
776         men_key_menu = gtk_menu_new ();
777         gtk_menu_item_set_submenu (GTK_MENU_ITEM (men_key), men_key_menu);
778
779         mnu_add_key = gtk_image_menu_item_new_with_mnemonic("Add _Subkey");
780         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mnu_add_key), gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU));
781
782         gtk_widget_set_sensitive(mnu_add_key, False);
783         gtk_container_add (GTK_CONTAINER (men_key_menu), mnu_add_key);
784
785         mnu_set_value = gtk_image_menu_item_new_with_mnemonic("Set _Value");
786         gtk_widget_set_sensitive(mnu_set_value, False);
787         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mnu_set_value), gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU));
788         gtk_container_add (GTK_CONTAINER (men_key_menu), mnu_set_value);
789
790         mnu_find = gtk_image_menu_item_new_from_stock ("gtk-find", accel_group);
791         gtk_widget_set_sensitive(mnu_find, False);
792         gtk_container_add (GTK_CONTAINER (men_key_menu), mnu_find);
793
794         mnu_del_key = gtk_image_menu_item_new_with_mnemonic ("Delete Key"); 
795         gtk_widget_set_sensitive(mnu_del_key, False);
796         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mnu_del_value), gtk_image_new_from_stock ("gtk-delete", GTK_ICON_SIZE_MENU));
797         gtk_container_add (GTK_CONTAINER (men_key_menu), mnu_del_key);
798
799         mnu_del_value = gtk_image_menu_item_new_with_mnemonic ("Delete Value"); 
800         gtk_widget_set_sensitive(mnu_del_value, False);
801         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mnu_del_value), gtk_image_new_from_stock ("gtk-delete", GTK_ICON_SIZE_MENU));
802         gtk_container_add (GTK_CONTAINER (men_key_menu), mnu_del_value);
803
804
805         help = gtk_menu_item_new_with_mnemonic ("_Help");
806         gtk_container_add (GTK_CONTAINER (menubar), help);
807
808         help_menu = gtk_menu_new ();
809         gtk_menu_item_set_submenu (GTK_MENU_ITEM (help), help_menu);
810
811         about = gtk_menu_item_new_with_mnemonic ("_About");
812         gtk_container_add (GTK_CONTAINER (help_menu), about);
813
814         hbox1 = gtk_hbox_new (FALSE, 0);
815         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
816
817         scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
818         gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0);
819
820         tree_keys = gtk_tree_view_new ();
821
822         /* Column names */
823         curcol = gtk_tree_view_column_new ();
824         gtk_tree_view_column_set_title(curcol, "Name");
825         renderer = gtk_cell_renderer_text_new();
826         gtk_tree_view_column_pack_start(curcol, renderer, True);
827
828         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_keys), curcol);
829
830         gtk_tree_view_column_add_attribute(curcol, renderer, "text", 0);
831         gtk_container_add (GTK_CONTAINER (scrolledwindow1), tree_keys);
832         store_keys = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
833         gtk_tree_view_set_model(GTK_TREE_VIEW(tree_keys), GTK_TREE_MODEL(store_keys));
834         g_object_unref(store_keys);
835
836         gtk_tree_selection_set_select_function (gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_keys)), on_key_activate, NULL, NULL);
837
838         g_signal_connect ((gpointer) tree_keys, "row-expanded",
839                                           G_CALLBACK (expand_key),
840                                           NULL);
841
842
843         scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
844         gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow2, TRUE, TRUE, 0);
845
846         tree_vals = gtk_tree_view_new ();
847         /* Column names */
848
849         curcol = gtk_tree_view_column_new ();
850         gtk_tree_view_column_set_title(curcol, "Name");
851         renderer = gtk_cell_renderer_text_new();
852         gtk_tree_view_column_pack_start(curcol, renderer, True);
853         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_vals), curcol);
854         gtk_tree_view_column_add_attribute(curcol, renderer, "text", 0);
855
856         curcol = gtk_tree_view_column_new ();
857         gtk_tree_view_column_set_title(curcol, "Type");
858         renderer = gtk_cell_renderer_text_new();
859         gtk_tree_view_column_pack_start(curcol, renderer, True);
860         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_vals), curcol);
861         gtk_tree_view_column_add_attribute(curcol, renderer, "text", 1);
862
863         curcol = gtk_tree_view_column_new ();
864         gtk_tree_view_column_set_title(curcol, "Value");
865         renderer = gtk_cell_renderer_text_new();
866         gtk_tree_view_column_pack_start(curcol, renderer, True);
867         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_vals), curcol);
868         gtk_tree_view_column_add_attribute(curcol, renderer, "text", 2);
869
870
871         gtk_container_add (GTK_CONTAINER (scrolledwindow2), tree_vals);
872
873         store_vals = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
874         gtk_tree_view_set_model(GTK_TREE_VIEW(tree_vals), GTK_TREE_MODEL(store_vals));
875         g_object_unref(store_vals);
876
877         statusbar = gtk_statusbar_new ();
878         gtk_box_pack_start (GTK_BOX (vbox1), statusbar, FALSE, FALSE, 0);
879         gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbar), FALSE);
880
881         g_signal_connect ((gpointer) save_as, "activate",
882                                           G_CALLBACK (on_save_as_activate),
883                                           NULL);
884         g_signal_connect ((gpointer) quit, "activate",
885                                           G_CALLBACK (on_quit_activate),
886                                           NULL);
887         g_signal_connect ((gpointer) mnu_add_key, "activate",
888                                           G_CALLBACK (on_add_key_activate),
889                                           NULL);
890         g_signal_connect ((gpointer) mnu_set_value, "activate",
891                                           G_CALLBACK (on_set_value_activate),
892                                           NULL);
893         g_signal_connect ((gpointer) mnu_find, "activate",
894                                           G_CALLBACK (on_find_activate),
895                                           NULL);
896         g_signal_connect ((gpointer) mnu_del_key, "activate",
897                                           G_CALLBACK (on_delete_key_activate),
898                                           NULL);
899         g_signal_connect ((gpointer) mnu_del_value, "activate",
900                                           G_CALLBACK (on_delete_value_activate),
901                                           NULL);
902         g_signal_connect ((gpointer) about, "activate",
903                                           G_CALLBACK (on_about_activate),
904                                           NULL);
905
906         g_signal_connect ((gpointer) tree_vals, "row-activated",
907                                           G_CALLBACK (on_value_activate),
908                                           NULL);
909
910
911         gtk_window_add_accel_group (GTK_WINDOW (mainwin), accel_group);
912
913         return mainwin;
914 }
915
916 static GtkWidget* create_openfilewin (void)
917 {
918         GtkWidget *openfilewin;
919         GtkWidget *ok_button;
920         GtkWidget *cancel_button;
921
922         openfilewin = gtk_file_selection_new ("Select File");
923         gtk_container_set_border_width (GTK_CONTAINER (openfilewin), 10);
924
925         ok_button = GTK_FILE_SELECTION (openfilewin)->ok_button;
926         GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT);
927
928         cancel_button = GTK_FILE_SELECTION (openfilewin)->cancel_button;
929         GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT);
930
931         return openfilewin;
932 }
933
934 static GtkWidget* create_savefilewin (void)
935 {
936         GtkWidget *savefilewin;
937         GtkWidget *ok_button;
938         GtkWidget *cancel_button;
939
940         savefilewin = gtk_file_selection_new ("Select File");
941         gtk_container_set_border_width (GTK_CONTAINER (savefilewin), 10);
942
943         ok_button = GTK_FILE_SELECTION (savefilewin)->ok_button;
944         GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT);
945
946         cancel_button = GTK_FILE_SELECTION (savefilewin)->cancel_button;
947         GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT);
948
949         return savefilewin;
950 }
951
952 static int gregedit_load_defaults(void)
953 {
954         WERROR error = reg_open_local(&registry);
955         if(!W_ERROR_IS_OK(error)) {
956                 gtk_show_werror(mainwin, "Error while loading local registry", error);
957                 return -1;
958         }
959         registry_load_root();
960
961         return 0;
962 }
963
964 int main(int argc, char *argv[])
965 {
966         int ret;
967
968         gregedit_init_subsystems;
969         lp_load();
970         load_interfaces();
971         setup_logging(argv[0], DEBUG_STDERR);
972
973         mem_ctx = talloc_init("gregedit");
974
975         gtk_init(&argc, &argv);
976         mainwin = create_mainwindow();
977         gtk_widget_show_all(mainwin);
978
979         ret = gregedit_load_defaults();
980         if (ret != 0) goto failed;
981
982         ret = gtk_event_loop();
983
984 failed:
985         talloc_free(mem_ctx);
986         return ret;
987 }