1 #include <cstdio>
2 #include <unistd.h>
3 #include <signal.h>
4 #include <stdexcept>
5 
6 #include <glib.h>
7 #include <gconf/gconf.h>
8 #include <gconf/gconf-client.h>
9 
10 using namespace std;
11 
12 static GMainLoop* loop = NULL;
13 
print_value(const GConfValue * value,const char * suffix)14 static int print_value(const GConfValue *value, const char *suffix) {
15 	int count = 0;
16 	GSList* cursor = NULL;
17 
18 	if (!value) return 0;
19 
20 	switch (value->type) {
21 	case GCONF_VALUE_STRING:
22 		return printf("%s%s", gconf_value_get_string(value), suffix);
23 	case GCONF_VALUE_INT:
24 		return printf("%d%s", gconf_value_get_int(value), suffix);
25 	case GCONF_VALUE_FLOAT:
26 		return printf("%f%s", gconf_value_get_float(value), suffix);
27 	case GCONF_VALUE_BOOL:
28 		if (gconf_value_get_bool(value))
29 			return printf("true%s", suffix);
30 		return printf("false%s", suffix);
31 	case GCONF_VALUE_LIST:
32 		cursor = gconf_value_get_list(value);
33 		if (g_slist_length (cursor) == 0)
34 			count += printf("%s", suffix);
35 		else for ( ; cursor ; cursor = g_slist_next(cursor))
36 			count += print_value((const GConfValue *) cursor->data, cursor->next ? "," : suffix);
37 		return count;
38 	case GCONF_VALUE_PAIR:
39 		return  print_value(gconf_value_get_car(value), ",") +
40 			print_value(gconf_value_get_cdr(value), suffix);
41 	default:
42 		throw exception();
43 	}
44 
45 
46 	return 0;
47 }
48 
on_value_change(GConfClient *,guint,GConfEntry * entry,void *)49 static void on_value_change(GConfClient* /*client*/, guint /*cnxn_id*/, GConfEntry* entry, void* /*user_data*/) {
50 	printf("%s\t", gconf_entry_get_key(entry));
51 	print_value(gconf_entry_get_value(entry), "\n");
52 }
53 
on_sig(int)54 static void on_sig(int /*signal*/) {
55 	g_main_loop_quit(loop);
56 }
57 
err(GIOChannel *,GIOCondition,gpointer)58 static gboolean err(GIOChannel* /*source*/, GIOCondition /*condition*/, gpointer /*data*/) {
59 	g_main_loop_quit(loop);
60 	return false;
61 }
62 
set_key(const char * key,const char * val)63 static gboolean set_key(const char *key, const char *val) {
64 	gboolean error = false;
65 	GConfClient *client = gconf_client_get_default();
66 	GConfValue  *value  = gconf_client_get(client, key, NULL);
67 	GConfValueType type = value ? value->type : GCONF_VALUE_STRING;
68 	gconf_value_free(value);
69 
70 	switch (type) {
71 		case GCONF_VALUE_STRING:
72 			error = !gconf_client_set_string(client, key, val, NULL);
73 			break;
74 		case GCONF_VALUE_INT:
75 			int ival;
76 			error = sscanf(val, "%d", &ival) != 1;
77 			error = error || !gconf_client_set_int(client, key, ival, NULL);
78 			break;
79 		case GCONF_VALUE_FLOAT:
80 			float fval;
81 			error = sscanf(val, "%f", &fval) != 1;
82 			error = error || !gconf_client_set_float(client, key, fval, NULL);
83 			break;
84 		case GCONF_VALUE_BOOL:
85 			error = !gconf_client_set_float(client, key, !g_strcmp0(val, "true"), NULL);
86 			break;
87 		case GCONF_VALUE_LIST:
88 		case GCONF_VALUE_PAIR:
89 		default:
90 			g_critical("Invalid value type!");
91 			error = true;
92 	}
93 
94 	g_object_unref(client);
95 	return !error;
96 }
97 
in(GIOChannel * source,GIOCondition condition,gpointer data)98 static gboolean in(GIOChannel *source, GIOCondition condition, gpointer data) {
99 	gchar *key, *val;
100 	GIOStatus st = g_io_channel_read_line(source, &key, NULL, NULL, NULL);
101 
102 	// Remove the trailing '\n'
103 	for (int i=0 ; key && key[i] ; i++)
104 		if (key[i] == '\n')
105 			key[i] = '\0';
106 
107 	// If we were successful
108 	if (key && st == G_IO_STATUS_NORMAL) {
109 		if (!g_strrstr(key, "\t"))
110 			goto exit;
111 
112 		val = g_strrstr(key, "\t") + 1;
113 		*(val-1) = '\0';
114 
115 		if (!set_key(key, val))
116 			goto exit;
117 
118 		g_free(key);
119 		return true;
120 	}
121 	else if (key && st == G_IO_STATUS_AGAIN) {
122 		g_free(key);
123 		return in(source, condition, data);
124 	}
125 
126 exit:
127 	g_free(key);
128 	return err(source, condition, data);
129 }
130 
main(int argc,char ** argv)131 int main(int argc, char **argv) {
132 	if (argc < 2) return 1;
133 
134 	// Register sighup handler
135 	if (signal(SIGHUP, on_sig) == SIG_ERR || signal(SIGPIPE, on_sig) == SIG_ERR || signal(SIGABRT, on_sig) == SIG_ERR) {
136 		fprintf(stderr, "Unable to trap signals!");
137 		return 2;
138 	}
139 
140 	// Switch stdout to line buffering
141 	if (setvbuf(stdout, NULL, _IOLBF, 0)) {
142 		fprintf(stderr, "Unable to switch stdout to line buffering!");
143 		return 3;
144 	}
145 
146 	// Switch stdin to line buffering
147 	if (setvbuf(stdin, NULL, _IOLBF, 0)) {
148 		fprintf(stderr, "Unable to switch stdin to line buffering!");
149 		return 4;
150 	}
151 
152 	// Init
153 	g_type_init();
154 
155 	// Get the main loop
156 	loop = g_main_loop_new(NULL, false);
157 
158 	// Setup our GIO Channels
159 	GIOChannel* inchan  = g_io_channel_unix_new(fileno(stdin));
160 	GIOChannel* outchan = g_io_channel_unix_new(fileno(stdout));
161 	g_io_add_watch(inchan,  G_IO_IN,  in, NULL);
162 	g_io_add_watch(inchan,  G_IO_PRI, in, NULL);
163 	g_io_add_watch(inchan,  G_IO_ERR, err, NULL);
164 	g_io_add_watch(inchan,  G_IO_HUP, err, NULL);
165 	g_io_add_watch(outchan, G_IO_ERR, err, NULL);
166 	g_io_add_watch(outchan, G_IO_HUP, err, NULL);
167 
168 	// Get GConf client
169 	GConfClient* client = gconf_client_get_default();
170 
171 	// Add server notifications for all keys
172 	for (int i=1 ; i < argc ; i++) {
173 		GConfValue *value;
174 		gconf_client_add_dir(client, argv[i], GCONF_CLIENT_PRELOAD_NONE, NULL);
175 		gconf_client_notify_add(client, argv[i], on_value_change, NULL, NULL, NULL);
176 		value = gconf_client_get(client, argv[i], NULL);
177 		if (value) {
178 			gconf_value_free (value);
179 			gconf_client_notify(client, argv[i]);
180 		} else {
181 			printf("%s\n", argv[i]);
182 		}
183 	}
184 
185 	g_main_loop_run(loop);
186 
187 	// Cleanup
188 	g_object_unref(client);
189 	g_io_channel_shutdown(inchan,  FALSE, NULL);
190 	g_io_channel_shutdown(outchan, FALSE, NULL);
191 	g_io_channel_unref(inchan);
192 	g_io_channel_unref(outchan);
193 	g_main_loop_unref(loop);
194 }
195