aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-08-15 12:17:25 +0000
committerChristian Grothoff <christian@grothoff.org>2011-08-15 12:17:25 +0000
commit3e6963bdcf7ebc28bcae5bce1e2544d19f491657 (patch)
treeb645cb6c94cce4e992416230e644052fee07893d
parentbcf7ddfdbd225608e84b892dd1a970400ba2371e (diff)
downloadgnunet-gtk-3e6963bdcf7ebc28bcae5bce1e2544d19f491657.tar.gz
gnunet-gtk-3e6963bdcf7ebc28bcae5bce1e2544d19f491657.zip
draft for new libgnunetgtk
-rw-r--r--src/include/Makefile.am6
-rw-r--r--src/include/gnunet_gtk.h154
-rw-r--r--src/lib/Makefile.am22
-rw-r--r--src/lib/about.c53
-rw-r--r--src/lib/eventloop.c809
-rw-r--r--src/lib/glade.c85
-rw-r--r--src/lib/nls.c58
-rw-r--r--src/lib/os_installation.c435
8 files changed, 1622 insertions, 0 deletions
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
new file mode 100644
index 00000000..ef58f075
--- /dev/null
+++ b/src/include/Makefile.am
@@ -0,0 +1,6 @@
1SUBDIRS = .
2
3gnunetgtkincludedir = $(includedir)/gnunet
4
5gnunetgtkinclude_HEADERS = \
6 gnunet_gtk.h
diff --git a/src/include/gnunet_gtk.h b/src/include/gnunet_gtk.h
new file mode 100644
index 00000000..4403ab4b
--- /dev/null
+++ b/src/include/gnunet_gtk.h
@@ -0,0 +1,154 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/include/gnunet_gtk.h
23 * @brief Helper library for Gtk user interfaces to GNUnet
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_GTK_H
27#define GNUNET_GTK_H
28
29#ifndef HAVE_USED_CONFIG_H
30#define HAVE_USED_CONFIG_H
31#if HAVE_CONFIG_H
32#include "gnunet_gtk_config.h"
33#endif
34#endif
35
36#include <gnunet/platform.h>
37#include <gnunet/gnunet_util_lib.h>
38#include <gnunet/gnunet_fs_service.h>
39#include <extractor.h>
40#include <gladeui/glade.h>
41#include <gtk/gtk.h>
42
43
44/**
45 * Initialize natural language support.
46 */
47void
48GNUNET_GTK_setup_nls (void);
49
50
51/**
52 * Get the name of the directory where all of our package
53 * data is stored ($PREFIX/share/)
54 *
55 * @return name of the data directory
56 */
57const char *
58GNUNET_GTK_get_data_dir (void);
59
60
61/**
62 * @brief get the path to a specific GNUnet installation directory or,
63 * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
64 * @author Milan
65 * @return a pointer to the dir path (to be freed by the caller)
66 */
67char *
68GNUNET_GTK_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind);
69
70
71/**
72 * Create an initialize a new builder based on the GNUnet-GTK glade
73 * file.
74 *
75 * @param filename name of the resource file to load
76 * @return NULL on error
77 */
78GtkBuilder *
79GNUNET_GTK_get_new_builder (const char *filename);
80
81
82/**
83 * This displays an about dialog.
84 *
85 * @param dialogfile name of the glade file containing the dialog
86 * @param dialogname name of the about dialog in the file
87 */
88void
89GNUNET_GTK_display_about (const char *dialogfile,
90 const char *dialogname);
91
92
93/**
94 * Handle for our main loop.
95 */
96struct GNUNET_GTK_MainLoop;
97
98
99/**
100 * Initialize the main loop.
101 *
102 * @param binary_name binary name
103 * @param binary_help help text for the binary
104 * @param argc number of command line options
105 * @param argv command line options
106 * @param options allowed command line options
107 * @param main_window_file glade file for the main window
108 * @param main_task first task to run, closure will be set to the 'struct GNUNET_GTK_MainLoop'
109 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. bad command-line options, etc)
110 */
111int
112GNUNET_GTK_main_loop_start (const char *binary_name,
113 const char *binary_help,
114 int argc,
115 char *const*argv,
116 struct GNUNET_GETOPT_CommandLineOption *options,
117 const char *main_window_file,
118 GNUNET_SCHEDULER_Task main_task);
119
120
121/**
122 * Get an object from the main window.
123 *
124 * @param ml handle to the main loop
125 * @param name name of the object
126 * @return NULL on error, otherwise the object
127 */
128GObject *
129GNUNET_GTK_main_loop_get_object (struct GNUNET_GTK_MainLoop *ml,
130 const char *name);
131
132
133/**
134 * Get the configuration.
135 *
136 * @param ml handle to the main loop
137 * @return handle to the configuration, never NULL
138 */
139const struct GNUNET_CONFIGURATION_Handle *
140GNUNET_GTK_main_loop_get_configuration (struct GNUNET_GTK_MainLoop *ml);
141
142
143/**
144 * Trigger shutdown of the GUI and exit the main loop.
145 *
146 * @param ml handle to the main loop
147 */
148void
149GNUNET_GTK_main_loop_quit (struct GNUNET_GTK_MainLoop *ml);
150
151
152
153#endif
154/* end of gnunet_gtk.h */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644
index 00000000..6a87dc4e
--- /dev/null
+++ b/src/lib/Makefile.am
@@ -0,0 +1,22 @@
1INCLUDES = \
2 -I$(top_srcdir)/ \
3 -I$(top_srcdir)/src/include \
4 @GTK_CFLAGS@ \
5 @GNUNET_CFLAGS@ \
6 @GLADE_CFLAGS@
7
8if MINGW
9 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
10endif
11
12lib_LTLIBRARIES = libgnunetgtk.la
13
14libgnunetgtk_la_SOURCES = \
15 eventloop.c \
16 glade.c \
17 os_installation.c \
18 nls.c \
19 about.c
20libgnunetgtk_la_LIBADD = \
21 -lgnunetutil $(XLIB)
22
diff --git a/src/lib/about.c b/src/lib/about.c
new file mode 100644
index 00000000..e75e11dc
--- /dev/null
+++ b/src/lib/about.c
@@ -0,0 +1,53 @@
1/*
2 This file is part of GNUnet
3 (C) 2005, 2006, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/lib/about.c
23 * @brief code to display an about dialog
24 * @author Christian Grothoff
25 * @author Igor Wronsky
26 */
27#include "gnunet_gtk.h"
28
29/**
30 * This displays an about dialog.
31 *
32 * @param dialogfile name of the glade file containing the dialog
33 * @param dialogname name of the about dialog in the file
34 */
35void
36GNUNET_GTK_display_about (const char *dialogfile,
37 const char *dialogname)
38{
39 GtkBuilder *builder;
40 GtkWidget *ad;
41
42 builder = GNUNET_GTK_get_new_builder (dialogfile);
43 if (builder == NULL)
44 return;
45 ad = GTK_WIDGET (gtk_builder_get_object (builder,
46 dialogname));
47 gtk_dialog_run (GTK_DIALOG (ad));
48 gtk_widget_destroy (ad);
49 g_object_unref (G_OBJECT (builder));
50}
51
52
53/* end of about.c */
diff --git a/src/lib/eventloop.c b/src/lib/eventloop.c
new file mode 100644
index 00000000..7eb7e060
--- /dev/null
+++ b/src/lib/eventloop.c
@@ -0,0 +1,809 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/lib/eventloop.c
23 * @brief code for merging GNUnet scheduler and Gtk Main Loop event loops
24 * @author Christian Grothoff
25 */
26#include "gnunet_gtk.h"
27
28
29/**
30 * Main context for our event loop.
31 */
32struct GNUNET_GTK_MainLoop
33{
34
35 /**
36 * Our configuration.
37 */
38 const struct GNUNET_CONFIGURATION_Handle *cfg;
39
40 /**
41 * Name of the glade file for the main window
42 */
43 const char *main_window_file;
44
45 /**
46 * Initial task to run to setup the system.
47 */
48 GNUNET_SCHEDULER_Task main_task;
49
50 /**
51 * Builder for the main window.
52 */
53 GtkBuilder *builder;
54
55 /**
56 * Gib's Main loop.
57 */
58 GMainLoop *gml;
59
60 /**
61 * GTK's main context.
62 */
63 GMainContext *gmc;
64
65 /**
66 * Read set.
67 */
68 struct GNUNET_NETWORK_FDSet *rs;
69
70 /**
71 * Write set.
72 */
73 struct GNUNET_NETWORK_FDSet *ws;
74
75 /**
76 * Recycled array of polling descriptors.
77 */
78 GPollFD *cached_poll_array;
79
80 /**
81 * Size of the 'cached_poll_array'.
82 */
83 guint cached_poll_array_size;
84
85 /**
86 * Return value from last g_main_context_query call.
87 */
88 guint poll_array_active;
89
90 /**
91 * Maximum GTK priority.
92 */
93 gint max_priority;
94
95
96#if WINDOWS
97 /**
98 * Array to hold pipe handles during a select() call
99 */
100 struct GNUNET_DISK_FileHandle **read_array;
101
102 /**
103 * Allocated length of read_array
104 */
105 int read_array_length;
106
107 /**
108 * Event to fire when a socket is ready for reading
109 */
110 HANDLE hEventRead;
111
112 /**
113 * Event to fire when a socket is ready for writing
114 */
115 HANDLE hEventWrite;
116
117 /**
118 * Event to fire when a socket had an error
119 */
120 HANDLE hEventException;
121
122 /**
123 * Event that is permanently enabled and is used to signal a pipe
124 * that is ready for writing (asynchronous pipes are always writable)
125 */
126 HANDLE hEventPipeWrite;
127
128 /**
129 * Event that is permanently enabled and is used to signal a pipe
130 * that is ready for reading (used to wake up early on a pipe that
131 * is known to be readable)
132 */
133 HANDLE hEventReadReady;
134
135 /**
136 * A list to hold file handles that are ready for reading
137 */
138 struct GNUNET_CONTAINER_SList *handles_read;
139
140 /**
141 * A list to hold file handles that are ready for writing
142 */
143 struct GNUNET_CONTAINER_SList *handles_write;
144
145 /**
146 * A list to hold file handles that are broken
147 */
148 struct GNUNET_CONTAINER_SList *handles_except;
149#endif
150
151};
152
153
154/**
155 * Get the configuration.
156 *
157 * @param ml handle to the main loop
158 * @return handle to the configuration, never NULL
159 */
160const struct GNUNET_CONFIGURATION_Handle *
161GNUNET_GTK_main_loop_get_configuration (struct GNUNET_GTK_MainLoop *ml)
162{
163 return ml->cfg;
164}
165
166
167/**
168 * Trigger shutdown of the GUI and exit the main loop.
169 *
170 * @param ml handle to the main loop
171 */
172void
173GNUNET_GTK_main_loop_quit (struct GNUNET_GTK_MainLoop *ml)
174{
175 g_main_loop_quit (ml->gml);
176}
177
178
179/**
180 * Get an object from the main window.
181 *
182 * @param ml handle to the main loop
183 * @param name name of the object
184 * @return NULL on error, otherwise the object
185 */
186GObject *
187GNUNET_GTK_main_loop_get_object (struct GNUNET_GTK_MainLoop *ml,
188 const char *name)
189{
190 return gtk_builder_get_object (ml->builder, name);
191}
192
193
194/**
195 * Task to run Gtk events (within a GNUnet scheduler task).
196 *
197 * @param cls the main loop handle
198 * @param tc scheduler context
199 */
200static void
201gnunet_gtk_dispatch_task (void *cls,
202 const struct GNUNET_SCHEDULER_TaskContext *tc)
203{
204 struct GNUNET_GTK_MainLoop *ml = cls;
205 g_main_context_dispatch (ml->gmc);
206}
207
208
209#ifndef FD_COPY
210#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
211#endif
212
213/**
214 * Replacement for the GNUnet scheduler's "select" that integrates the
215 * Gtk event loop. We merge Gtk's events with those from GNUnet's
216 * scheduler and then use 'g_poll' on both. Then we process the Gtk
217 * events (by adding a task to do so to the GNUnet scheduler), and, if
218 * applicable, return the GNUnet-scheduler events back to GNUnet.
219 *
220 * @param cls the 'struct GNUNET_GTK_MainLoop'
221 * @param rfds set of sockets to be checked for readability
222 * @param wfds set of sockets to be checked for writability
223 * @param efds set of sockets to be checked for exceptions
224 * @param timeout relative value when to return
225 * @return number of selected sockets, GNUNET_SYSERR on error
226 */
227static int
228gnunet_gtk_select (void *cls,
229 struct GNUNET_NETWORK_FDSet *rfds,
230 struct GNUNET_NETWORK_FDSet *wfds,
231 struct GNUNET_NETWORK_FDSet *efds,
232 const struct GNUNET_TIME_Relative timeout)
233{
234 struct GNUNET_GTK_MainLoop *ml = cls;
235 int max_nfds;
236 gint poll_result;
237
238 GPollFD *gfds;
239 gint delay;
240
241 guint i;
242 guint fd_counter = 0;
243
244 guint allocated_nfds, need_gfds;
245
246 fd_set aread, awrite, aexcept;
247 int pre_ret = 0;
248 int result = 0;
249 int socks = 0;
250 int sock_read = 0, sock_write = 0, sock_err = 0;
251
252#if WINDOWS
253 int always_ready_write_fd = -1;
254
255 int select_ret = 0;
256
257 int read_handles = 0;
258 DWORD waitstatus;
259#endif
260
261 if (TRUE != g_main_loop_is_running (ml->gml))
262 return GNUNET_NETWORK_socket_select (rfds, wfds, efds, timeout);
263
264 FD_ZERO (&aread);
265 FD_ZERO (&awrite);
266 FD_ZERO (&aexcept);
267 if (rfds)
268 FD_COPY (&rfds->sds, &aread);
269 if (wfds)
270 FD_COPY (&wfds->sds, &awrite);
271 if (efds)
272 FD_COPY (&efds->sds, &aexcept);
273
274#if WINDOWS
275 ResetEvent (ml->hEventRead);
276 ResetEvent (ml->hEventWrite);
277 ResetEvent (ml->hEventException);
278
279 GNUNET_CONTAINER_slist_clear (ml->handles_read);
280 GNUNET_CONTAINER_slist_clear (ml->handles_write);
281 GNUNET_CONTAINER_slist_clear (ml->handles_except);
282#endif
283
284
285 if (rfds != NULL)
286 max_nfds = rfds->nsds;
287 else
288 max_nfds = -1;
289 if (wfds != NULL && max_nfds < wfds->nsds)
290 max_nfds = wfds->nsds;
291 if (efds != NULL && max_nfds < efds->nsds)
292 max_nfds = efds->nsds;
293
294 allocated_nfds = ml->cached_poll_array_size;
295 gfds = ml->cached_poll_array;
296 if (allocated_nfds == 0)
297 {
298 /* TODO: get some statistics, find the maximum number of fds ever
299 * polled during normal gnunet-gtk operation, and set this to that number.
300 */
301 ml->cached_poll_array = gfds = g_new (GPollFD, 30);
302 ml->cached_poll_array_size = allocated_nfds = 30;
303 }
304
305 while (1)
306 {
307 fd_counter = 0;
308#if !WINDOWS
309 gboolean need_realloc = FALSE;
310 for (i = 0; !need_realloc && i < max_nfds; i += 1)
311 {
312 int isset[3];
313
314 isset[0] = (rfds == NULL) ? 0 : FD_ISSET (i, &rfds->sds);
315 isset[1] = (wfds == NULL) ? 0 : FD_ISSET (i, &wfds->sds);
316 isset[2] = (efds == NULL) ? 0 : FD_ISSET (i, &efds->sds);
317 if (!isset[0] && !isset[1] && !isset[2])
318 continue;
319 if (fd_counter >= allocated_nfds)
320 {
321 need_realloc = TRUE;
322 break;
323 }
324 gfds[fd_counter].fd = i;
325 gfds[fd_counter].events = (isset[0] ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0)
326 | (isset[1] ? G_IO_OUT | G_IO_ERR : 0) | (isset[2] ? G_IO_ERR : 0);
327 fd_counter += 1;
328 }
329 if (need_realloc)
330 {
331 ml->cached_poll_array = gfds = g_renew (GPollFD, gfds, ml->cached_poll_array_size * 2);
332 ml->cached_poll_array_size = allocated_nfds = ml->cached_poll_array_size * 2;
333 fd_counter = 0;
334 need_realloc = FALSE;
335 }
336 else
337 break;
338#else
339 struct GNUNET_CONTAINER_SList_Iterator *t;
340 /* We might overshoot a little, but that won't hurt very much */
341 int need_nfds = (rfds->sds.fd_count + rfds->sds.fd_count + rfds->sds.fd_count > 0 ? 3 : 0)
342 + (rfds == NULL ? 0 : GNUNET_CONTAINER_slist_count (rfds->handles))
343 + (wfds == NULL ? 0 : 1)
344 + 1;
345 if (need_nfds >= allocated_nfds)
346 {
347 /* Since there are also gmainloop's own fds, just need_nfds won't be
348 * enough, so make it twice as long.
349 */
350 ml->cached_poll_array = gfds = g_renew (GPollFD, gfds, need_nfds * 2);
351 ml->cached_poll_array_size = allocated_nfds = need_nfds * 2;
352 }
353 if (ml->read_array_length < GNUNET_CONTAINER_slist_count (rfds->handles))
354 {
355 ml->read_array = GNUNET_realloc (ml->read_array, GNUNET_CONTAINER_slist_count (rfds->handles) * sizeof (struct GNUNET_DISK_FileHandle *));
356 ml->read_array_length = GNUNET_CONTAINER_slist_count (rfds->handles);
357 }
358 if (rfds != NULL)
359 {
360 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles), i = 0;
361 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
362 GNUNET_CONTAINER_slist_next (t), i += 1)
363 {
364 struct GNUNET_DISK_FileHandle *fh;
365 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
366 if (fh->type == GNUNET_PIPE)
367 {
368 if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
369 {
370 DWORD error_code = GetLastError();
371 if (error_code == ERROR_IO_PENDING)
372 {
373#if DEBUG_NETWORK
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the pipe's 0x%x overlapped event to the array as %d\n", fh->h, nhandles);
375#endif
376 gfds[fd_counter].fd = (intptr_t) fh->oOverlapRead->hEvent;
377 /* On W32 .events makes no sense - g_poll will just OR its
378 * contents into .revents when the .fd event fires.
379 * So we'll use it in the way that suits us the best.
380 */
381 gfds[fd_counter].events = G_IO_IN;
382 fd_counter += 1;
383 ml->read_array[read_handles] = fh;
384 read_handles += 1;
385 }
386 else
387 {
388 gfds[fd_counter].fd = (intptr_t) ml->hEventReadReady;
389 gfds[fd_counter].events = G_IO_HUP;
390 fd_counter += 1;
391 ml->read_array[read_handles] = fh;
392 read_handles += 1;
393 }
394 }
395 else
396 {
397#if DEBUG_NETWORK
398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the read ready event to the array as %d\n", nhandles);
399#endif
400 gfds[fd_counter].fd = (intptr_t) ml->hEventReadReady;
401 gfds[fd_counter].events = G_IO_IN;
402 fd_counter += 1;
403 ml->read_array[read_handles] = fh;
404 read_handles += 1;
405 }
406 }
407 else
408 {
409 GNUNET_CONTAINER_slist_add (ml->handles_read,
410 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
411 fh, sizeof (struct GNUNET_DISK_FileHandle));
412 pre_ret += 1;
413 }
414 }
415 }
416 if (wfds != NULL && GNUNET_CONTAINER_slist_count (wfds->handles) > 0)
417 {
418 gfds[fd_counter].fd = (intptr_t) ml->hEventPipeWrite;
419 gfds[fd_counter].events = G_IO_OUT;
420 always_ready_write_fd = fd_counter;
421 fd_counter += 1;
422 }
423 if (efds != NULL)
424 {
425 for (t = GNUNET_CONTAINER_slist_begin (efds->handles), i = 0;
426 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
427 GNUNET_CONTAINER_slist_next (t), i += 1)
428 {
429 struct GNUNET_DISK_FileHandle *fh;
430 DWORD dwBytes;
431 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
432 if (fh->type == GNUNET_PIPE)
433 {
434 if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
435 {
436 GNUNET_CONTAINER_slist_add (ml->handles_except,
437 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
438 fh, sizeof (struct GNUNET_DISK_FileHandle));
439 pre_ret += 1;
440 }
441 }
442 }
443 }
444 GNUNET_CONTAINER_slist_iter_destroy (t);
445
446 if (rfds != NULL && rfds->sds.fd_count > 0)
447 {
448#if DEBUG_NETWORK
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket read event to the array as %d\n", fd_counter);
450#endif
451 gfds[fd_counter].fd = (intptr_t) ml->hEventRead;
452 gfds[fd_counter].events = G_IO_IN;
453 for (i = 0; i < rfds->sds.fd_count; i++)
454 WSAEventSelect (rfds->sds.fd_array[i], ml->hEventRead, FD_ACCEPT | FD_READ | FD_CLOSE);
455 fd_counter += 1;
456 sock_read = rfds->sds.fd_count;
457 }
458 if (wfds != NULL && wfds->sds.fd_count > 0)
459 {
460 int wakeup = 0;
461#if DEBUG_NETWORK
462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket write event to the array as %d\n", fd_counter);
463#endif
464 gfds[fd_counter].fd = (intptr_t) ml->hEventWrite;
465 gfds[fd_counter].events = G_IO_OUT;
466 for (i = 0; i < wfds->sds.fd_count; i++)
467 {
468 DWORD error;
469 int status;
470 status = send (wfds->sds.fd_array[i], NULL, 0, 0);
471 error = GetLastError ();
472#if DEBUG_NETWORK
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pre-send to the socket %d returned %d (%u)\n", i, status, error);
474#endif
475 if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN))
476 wakeup = 1;
477 WSAEventSelect (wfds->sds.fd_array[i], ml->hEventWrite, FD_WRITE | FD_CONNECT | FD_CLOSE);
478 }
479 if (wakeup)
480 SetEvent (ml->hEventWrite);
481 fd_counter += 1;
482 sock_write = wfds->sds.fd_count;
483 }
484 if (efds != NULL && efds->sds.fd_count > 0)
485 {
486#if DEBUG_NETWORK
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket error event to the array as %d\n", fd_counter);
488#endif
489 gfds[fd_counter].fd = (intptr_t) ml->hEventException;
490 gfds[fd_counter].events = G_IO_ERR;
491 for (i = 0; i < efds->sds.fd_count; i++)
492 WSAEventSelect (efds->sds.fd_array[i], ml->hEventException, FD_OOB | FD_CLOSE);
493 fd_counter += 1;
494 sock_err = efds->sds.fd_count;
495 }
496 break;
497#endif
498 }
499 socks = sock_read + sock_write + sock_err;
500
501 g_main_context_prepare (ml->gmc, &ml->max_priority);
502 while (allocated_nfds < (need_gfds = g_main_context_query (ml->gmc,
503 ml->max_priority, &delay, &gfds[fd_counter], allocated_nfds - fd_counter)))
504 {
505 ml->cached_poll_array = gfds = g_renew (GPollFD, gfds, allocated_nfds - fd_counter + need_gfds);
506 ml->cached_poll_array_size = allocated_nfds = allocated_nfds - fd_counter + need_gfds;
507 }
508 ml->poll_array_active = fd_counter + need_gfds;
509
510 if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
511 {
512 if (delay >= 0)
513 delay = MIN(timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value, delay);
514 else
515 delay = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value;
516 }
517
518 if (pre_ret > 0)
519 {
520#if DEBUG_NETWORK
521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pre_ret is %d, setting delay to 0\n", pre_ret);
522#endif
523 delay = 0;
524 }
525
526#if DEBUG_NETWORK
527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "We have %d of our FDs and %d of GMC ones, going to wait %6dms\n", fd_counter, need_gfds, delay);
528#endif
529
530 poll_result = g_poll (gfds, fd_counter + need_gfds, delay);
531
532#if DEBUG_NETWORK
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "g_poll returned : %d\n", poll_result);
534#endif
535
536 /* Take care of GUI events.
537 * Dispatching the events here will eventually crash the scheduler, must do this
538 * from within a task (currently we're not in a task, but in a select() call, remember)
539 * Startup reason is used to pass the scheduler sanity check.
540 */
541 if (TRUE == g_main_context_check (ml->gmc, ml->max_priority, &gfds[fd_counter], need_gfds))
542 GNUNET_SCHEDULER_add_continuation (gnunet_gtk_dispatch_task, ml,
543 GNUNET_SCHEDULER_REASON_STARTUP);
544
545#if !WINDOWS
546 if (rfds)
547 GNUNET_NETWORK_fdset_zero (rfds);
548 if (wfds)
549 GNUNET_NETWORK_fdset_zero (wfds);
550 if (efds)
551 GNUNET_NETWORK_fdset_zero (efds);
552 for (i = 0; i < fd_counter; i++)
553 {
554 int set[3];
555 if ((set[0] = FD_ISSET (gfds[i].fd, &aread)))
556 FD_SET (gfds[i].fd, &rfds->sds);
557 if ((set[1] = FD_ISSET (gfds[i].fd, &awrite)))
558 FD_SET (gfds[i].fd, &wfds->sds);
559 if ((set[2] = FD_ISSET (gfds[i].fd, &aexcept)))
560 FD_SET (gfds[i].fd, &efds->sds);
561 if (set[0] || set[1] || set[2])
562 result += 1;
563 }
564#else
565 if (socks > 0)
566 {
567 struct timeval tvslice;
568 tvslice.tv_sec = 0;
569 tvslice.tv_usec = 0;
570 select_ret = select (max_nfds, &aread, &awrite, &aexcept, &tvslice);
571 if (select_ret == -1)
572 select_ret = 0;
573#if DEBUG_NETWORK
574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "select() returned %d\n", select_ret);
575#endif
576 }
577 if (always_ready_write_fd >= 0 && gfds[always_ready_write_fd].revents & G_IO_OUT)
578 {
579 GNUNET_CONTAINER_slist_append (ml->handles_write, wfds->handles);
580 result += GNUNET_CONTAINER_slist_count (ml->handles_write);
581#if DEBUG_NETWORK
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n");
583#endif
584 }
585 for (i = 0; i < read_handles; i++)
586 {
587 DWORD error;
588 BOOL bret;
589 if (!(gfds[i].revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)))
590 continue;
591 SetLastError (0);
592 waitstatus = 0;
593 bret = PeekNamedPipe (ml->read_array[i]->h, NULL, 0, NULL, &waitstatus, NULL);
594 error = GetLastError ();
595#if DEBUG_NETWORK
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n", i, ml->read_array[i]->h, bret, waitstatus, error);
597#endif
598 if (bret == 0 || (gfds[i].revents & G_IO_ERR))
599 {
600 if (efds != NULL)
601 {
602 struct GNUNET_CONTAINER_SList_Iterator *t;
603 for (t = GNUNET_CONTAINER_slist_begin (efds->handles), i = 0;
604 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
605 GNUNET_CONTAINER_slist_next (t), i += 1)
606 {
607 struct GNUNET_DISK_FileHandle *fh;
608 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
609 if (fh == ml->read_array[i])
610 {
611 GNUNET_CONTAINER_slist_add (ml->handles_except,
612 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
613 fh, sizeof (struct GNUNET_DISK_FileHandle));
614 break;
615 }
616 }
617 GNUNET_CONTAINER_slist_iter_destroy (t);
618 }
619 }
620 else if (waitstatus <= 0)
621 continue;
622 GNUNET_CONTAINER_slist_add (ml->handles_read,
623 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
624 ml->read_array[i], sizeof (struct GNUNET_DISK_FileHandle));
625 result += 1;
626#if DEBUG_NETWORK
627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n", ml->read_array[i], ml->read_array[i]->h);
628#endif
629 }
630 waitstatus = WaitForSingleObject (ml->hEventWrite, 0);
631#if DEBUG_NETWORK
632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wait for the write event returned %d\n", waitstatus);
633#endif
634 if (waitstatus == WAIT_OBJECT_0)
635 {
636 for (i = 0; i < wfds->sds.fd_count; i++)
637 {
638 DWORD error;
639 int status;
640 int so_error = 0;
641 int sizeof_so_error = sizeof (so_error);
642 int gso_result = getsockopt (wfds->sds.fd_array[i], SOL_SOCKET, SO_ERROR, (char *) &so_error, &sizeof_so_error);
643 status = send (wfds->sds.fd_array[i], NULL, 0, 0);
644 error = GetLastError ();
645#if DEBUG_NETWORK
646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send to the socket %d returned %d (%u)\n", i, status, error);
647#endif
648 if (status == 0
649 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN)
650 || (status == -1 && gso_result == 0 && error == WSAENOTCONN && so_error == WSAECONNREFUSED))
651 {
652 FD_SET (wfds->sds.fd_array[i], &awrite);
653 result += 1;
654 }
655 }
656 }
657 if (rfds)
658 {
659 struct GNUNET_CONTAINER_SList_Iterator *t;
660 for (i = 0; i < rfds->sds.fd_count; i++)
661 WSAEventSelect (rfds->sds.fd_array[i], ml->hEventRead, 0);
662 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
663 GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
664 GNUNET_CONTAINER_slist_next (t))
665 {
666 struct GNUNET_DISK_FileHandle *fh;
667 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL);
668 if (fh->type == GNUNET_PIPE)
669 CancelIo (fh->h);
670 }
671 GNUNET_CONTAINER_slist_iter_destroy (t);
672 GNUNET_NETWORK_fdset_zero (rfds);
673 if (select_ret != -1 && socks > 0)
674 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, select_ret);
675 GNUNET_CONTAINER_slist_append (rfds->handles, ml->handles_read);
676 }
677 if (wfds)
678 {
679 for (i = 0; i < wfds->sds.fd_count; i++)
680 WSAEventSelect (wfds->sds.fd_array[i], ml->hEventWrite, 0);
681 GNUNET_NETWORK_fdset_zero (wfds);
682 if (select_ret != -1 && socks > 0)
683 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, select_ret);
684 GNUNET_CONTAINER_slist_append (wfds->handles, ml->handles_write);
685 }
686 if (efds)
687 {
688 for (i = 0; i < efds->sds.fd_count; i++)
689 WSAEventSelect (efds->sds.fd_array[i], ml->hEventException, 0);
690 GNUNET_NETWORK_fdset_zero (efds);
691 if (select_ret != -1 && socks > 0)
692 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, select_ret);
693 GNUNET_CONTAINER_slist_append (efds->handles, ml->handles_except);
694 result += GNUNET_CONTAINER_slist_count (ml->handles_except);
695 }
696 if (fd_counter > 0)
697 /* This is not accurate (select_ret counts write-ready sockets,
698 * and result does as well. Anything out there actually cares
699 * about this?
700 */
701 return select_ret + result;
702 else
703 return 0;
704#endif
705 return result;
706}
707
708
709/**
710 * Actual main function run right after GNUnet's scheduler
711 * is initialized. Initializes up GTK and Glade and starts the
712 * combined event loop.
713 *
714 * @param cls the 'struct GNUNET_GTK_MainLoop'
715 * @param args leftover command line arguments (go to gtk)
716 * @param cfgfile name of the configuration file
717 * @param cfg handle to the configuration
718 */
719static void
720run_main_loop (void *cls,
721 char *const *args,
722 const char *cfgfile,
723 const struct GNUNET_CONFIGURATION_Handle *cfg)
724{
725 struct GNUNET_GTK_MainLoop *ml = cls;
726 int argc;
727
728 /* command-line processing for Gtk arguments */
729 argc = 0;
730 while (args[argc] != NULL) argc++;
731 gtk_init (&argc, (char ***) &args);
732
733 /* setup main context */
734 ml->builder = GNUNET_GTK_get_new_builder (ml->main_window_file);
735 if (ml->builder == NULL)
736 return;
737 ml->rs = GNUNET_NETWORK_fdset_create ();
738 ml->ws = GNUNET_NETWORK_fdset_create ();
739 ml->gml = g_main_loop_new (NULL, TRUE);
740 ml->gmc = g_main_loop_get_context (ml->gml);
741 ml->cfg = cfg;
742#if WINDOWS
743 ml->hEventRead = CreateEvent (NULL, TRUE, FALSE, NULL);
744 ml->hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
745 ml->hEventWrite = CreateEvent (NULL, TRUE, FALSE, NULL);
746 ml->hEventException = CreateEvent (NULL, TRUE, FALSE, NULL);
747 ml->hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
748 ml->handles_read = GNUNET_CONTAINER_slist_create ();
749 ml->handles_write = GNUNET_CONTAINER_slist_create ();
750 ml->handles_except = GNUNET_CONTAINER_slist_create ();
751 ml->read_array = NULL;
752 ml->read_array_length = 0;
753#endif
754
755 /* run main task of the application */
756 GNUNET_SCHEDULER_add_continuation (ml->main_task, ml,
757 GNUNET_SCHEDULER_REASON_STARTUP);
758
759 /* start the Gtk event loop */
760 GNUNET_assert (TRUE == g_main_context_acquire (ml->gmc));
761 GNUNET_SCHEDULER_set_select (&gnunet_gtk_select, ml);
762}
763
764
765/**
766 * Initialize the main loop.
767 *
768 * @param binary_name binary name
769 * @param binary_help help text for the binary
770 * @param argc number of command line options
771 * @param argv command line options
772 * @param options allowed command line options
773 * @param main_window_file glade file for the main window
774 * @param main_task first task to run, closure will be set to the 'struct GNUNET_GTK_MainLoop'
775 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. bad command-line options, etc)
776 */
777int
778GNUNET_GTK_main_loop_start (const char *binary_name,
779 const char *binary_help,
780 int argc,
781 char *const*argv,
782 struct GNUNET_GETOPT_CommandLineOption *options,
783 const char *main_window_file,
784 GNUNET_SCHEDULER_Task main_task)
785{
786 struct GNUNET_GTK_MainLoop ml;
787 int ret;
788
789 ml.main_window_file = main_window_file;
790 ret = GNUNET_PROGRAM_run (argc, argv,
791 binary_name,
792 "GTK GUI for GNUnet",
793 options,
794 &run_main_loop, &ml);
795 if (NULL != ml.cached_poll_array)
796 g_free (ml.cached_poll_array);
797 if (NULL != ml.rs)
798 GNUNET_NETWORK_fdset_destroy (ml.rs);
799 if (NULL != ml.ws)
800 GNUNET_NETWORK_fdset_destroy (ml.ws);
801 if (NULL != ml.builder)
802 g_object_unref (G_OBJECT (ml.builder));
803 if (NULL != ml.gml)
804 g_main_loop_unref (ml.gml);
805 return ret;
806}
807
808
809/* end of eventloop.c */
diff --git a/src/lib/glade.c b/src/lib/glade.c
new file mode 100644
index 00000000..386a676b
--- /dev/null
+++ b/src/lib/glade.c
@@ -0,0 +1,85 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/lib/glade.c
23 * @brief code for integration with glade
24 * @author Christian Grothoff
25 */
26#include "gnunet_gtk_config.h"
27#include "gnunet_gtk.h"
28
29
30/**
31 * Get the name of the directory where all of our package
32 * data is stored ($PREFIX/share/)
33 *
34 * @return name of the data directory
35 */
36const char *
37GNUNET_GTK_get_data_dir ()
38{
39 static char *dd;
40
41 if (dd == NULL)
42 dd = GNUNET_GTK_installation_get_path (GNUNET_OS_IPK_DATADIR);
43 return dd;
44}
45
46
47/**
48 * Create an initialize a new builder based on the
49 * GNUnet-GTK glade file.
50 *
51 * @param filename name of the resource file to load
52 * @return NULL on error
53 */
54GtkBuilder *
55GNUNET_GTK_get_new_builder (const char *filename)
56{
57 char *glade_path;
58 GtkBuilder *ret;
59 GError *error;
60
61 ret = gtk_builder_new ();
62 gtk_builder_set_translation_domain (ret, "gnunet-gtk");
63 GNUNET_asprintf (&glade_path,
64 "%s%s",
65 GNUNET_GTK_get_data_dir (),
66 filename);
67 error = NULL;
68 if (0 == gtk_builder_add_from_file (ret, glade_path, &error))
69 {
70 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
71 _("Failed to load `%s': %s\n"),
72 glade_path,
73 error->message);
74 g_error_free (error);
75 GNUNET_free (glade_path);
76 return NULL;
77 }
78 gtk_builder_connect_signals (ret, NULL);
79 GNUNET_free (glade_path);
80 return ret;
81}
82
83
84
85/* end of glade.c */
diff --git a/src/lib/nls.c b/src/lib/nls.c
new file mode 100644
index 00000000..96e44a99
--- /dev/null
+++ b/src/lib/nls.c
@@ -0,0 +1,58 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/lib/nls.c
23 * @brief natural language support
24 * @author Christian Grothoff
25 */
26#include "gnunet_gtk.h"
27
28#if ENABLE_NLS
29#include <locale.h>
30#endif
31
32
33/**
34 * Initialize GNU gettext for message translation.
35 */
36void
37GNUNET_GTK_setup_nls ()
38{
39#if ENABLE_NLS
40 char *path;
41
42 setlocale (LC_ALL, "");
43 GNUNET_asprintf (&path,
44 "%s/%s/locale/",
45 GNUNET_GTK_get_data_dir (),
46 PACKAGE_NAME);
47 bindtextdomain ("gnunet-gtk", path);
48 textdomain ("gnunet-gtk");
49 bind_textdomain_codeset ("GNUnet", "UTF-8");
50 bind_textdomain_codeset ("gnunet-gtk", "UTF-8");
51 GNUNET_free (path);
52#else
53 fprintf (stderr,
54 "WARNING: gnunet-gtk was compiled without i18n support (did CFLAGS contain -Werror?).\n");
55#endif
56}
57
58/* end of nls.c */
diff --git a/src/lib/os_installation.c b/src/lib/os_installation.c
new file mode 100644
index 00000000..9a884f27
--- /dev/null
+++ b/src/lib/os_installation.c
@@ -0,0 +1,435 @@
1/*
2 This file is part of GNUnet.
3 (C) 2006, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/lib/os_installation.c
23 * @brief get paths used by the program; this code is almost the
24 * same as src/util/os_installation.c in libgnunetutil; however,
25 * it contains sublte changes to detect the installation path
26 * of gnunet-gtk (which may be different from the path for
27 * GNUnet itself) and also needs to be replicated anyway since
28 * some of the methods try to find the location of the binary
29 * of the test-code itself, which would never yield the
30 * correct result for gnunet-gtk if the code lives in libgnunetutil.
31 * @author Milan
32 * @author Christian Grothoff
33 */
34#include "gnunet_gtk.h"
35#if DARWIN
36#include <mach-o/ldsyms.h>
37#include <mach-o/dyld.h>
38#endif
39
40#if LINUX
41/**
42 * Try to determine path by reading /proc/PID/exe
43 */
44static char *
45get_path_from_proc_maps ()
46{
47 char fn[64];
48 char line[1024];
49 char dir[1024];
50 FILE *f;
51 char *lgu;
52
53 GNUNET_snprintf (fn,
54 sizeof(fn),
55 "/proc/%u/maps",
56 getpid ());
57 f = fopen (fn, "r");
58 if (f == NULL)
59 return NULL;
60 while (NULL != fgets (line, sizeof(line), f))
61 {
62 if ((1 == sscanf (line,
63 "%*x-%*x %*c%*c%*c%*c %*x %*2u:%*2u %*u%*[ ]%s",
64 dir)) &&
65 (NULL != (lgu = strstr (dir, "gnunet-gtk"))))
66 {
67 lgu[0] = '\0';
68 fclose (f);
69 return GNUNET_strdup (dir);
70 }
71 }
72 fclose (f);
73 return NULL;
74}
75
76/**
77 * Try to determine path by reading /proc/PID/exe
78 */
79static char *
80get_path_from_proc_exe ()
81{
82 char fn[64];
83 char lnk[1024];
84 ssize_t size;
85
86 GNUNET_snprintf (fn,
87 sizeof(fn), "/proc/%u/exe", getpid ());
88 size = readlink (fn, lnk, sizeof (lnk)-1);
89 if (size <= 0)
90 {
91 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
92 return NULL;
93 }
94 GNUNET_assert (size < sizeof (lnk));
95 lnk[size] = '\0';
96 while ((lnk[size] != '/') && (size > 0))
97 size--;
98 if ((size < 4) || (lnk[size - 4] != '/'))
99 {
100 /* not installed in "/bin/" -- binary path probably useless */
101 return NULL;
102 }
103 lnk[size] = '\0';
104 return GNUNET_strdup (lnk);
105}
106#endif
107
108#if WINDOWS
109/**
110 * Try to determine path with win32-specific function
111 */
112static char *
113get_path_from_module_filename ()
114{
115 char path[4097];
116 char *idx;
117
118 GetModuleFileName (NULL, path, sizeof(path)-1);
119 idx = path + strlen (path);
120 while ((idx > path) && (*idx != '\\') && (*idx != '/'))
121 idx--;
122 *idx = '\0';
123 return GNUNET_strdup (path);
124}
125#endif
126
127#if DARWIN
128typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
129
130static char *
131get_path_from_NSGetExecutablePath ()
132{
133 static char zero = '\0';
134 char *path;
135 size_t len;
136 MyNSGetExecutablePathProto func;
137 int ret;
138
139 path = NULL;
140 func =
141 (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath");
142 if (!func)
143 return NULL;
144 path = &zero;
145 len = 0;
146 /* get the path len, including the trailing \0 */
147 func (path, &len);
148 if (len == 0)
149 return NULL;
150 path = GNUNET_malloc (len);
151 ret = func (path, &len);
152 if (ret != 0)
153 {
154 GNUNET_free (path);
155 return NULL;
156 }
157 len = strlen (path);
158 while ((path[len] != '/') && (len > 0))
159 len--;
160 path[len] = '\0';
161 return path;
162}
163
164static char *
165get_path_from_dyld_image ()
166{
167 const char *path;
168 char *p, *s;
169 int i;
170 int c;
171
172 p = NULL;
173 c = _dyld_image_count ();
174 for (i = 0; i < c; i++)
175 {
176 if (_dyld_get_image_header (i) == &_mh_dylib_header)
177 {
178 path = _dyld_get_image_name (i);
179 if (path != NULL && strlen (path) > 0)
180 {
181 p = strdup (path);
182 s = p + strlen (p);
183 while ((s > p) && (*s != '/'))
184 s--;
185 s++;
186 *s = '\0';
187 }
188 break;
189 }
190 }
191 return p;
192}
193#endif
194
195static char *
196get_path_from_PATH ()
197{
198 char *path;
199 char *pos;
200 char *end;
201 char *buf;
202 const char *p;
203
204 p = getenv ("PATH");
205 if (p == NULL)
206 return NULL;
207 path = GNUNET_strdup (p); /* because we write on it */
208 buf = GNUNET_malloc (strlen (path) + 20);
209 pos = path;
210
211 while (NULL != (end = strchr (pos, ':')))
212 {
213 *end = '\0';
214 sprintf (buf, "%s/%s", pos, "gnunet-gtk");
215 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
216 {
217 pos = GNUNET_strdup (pos);
218 GNUNET_free (buf);
219 GNUNET_free (path);
220 return pos;
221 }
222 pos = end + 1;
223 }
224 sprintf (buf, "%s/%s", pos, "gnunet-gtk");
225 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
226 {
227 pos = GNUNET_strdup (pos);
228 GNUNET_free (buf);
229 GNUNET_free (path);
230 return pos;
231 }
232 GNUNET_free (buf);
233 GNUNET_free (path);
234 return NULL;
235}
236
237static char *
238get_path_from_GNUNET_PREFIX ()
239{
240 const char *p;
241
242 p = getenv ("GNUNET_GTK_PREFIX");
243 if (p != NULL)
244 return GNUNET_strdup (p);
245 p = getenv ("GNUNET_PREFIX");
246 if (p != NULL)
247 return GNUNET_strdup (p);
248 return NULL;
249}
250
251/*
252 * @brief get the path to GNUnet bin/ or lib/, prefering the lib/ path
253 * @author Milan
254 *
255 * @return a pointer to the executable path, or NULL on error
256 */
257static char *
258os_get_gnunet_path ()
259{
260 char *ret;
261
262 ret = get_path_from_GNUNET_PREFIX ();
263 if (ret != NULL)
264 return ret;
265#if LINUX
266 ret = get_path_from_proc_maps ();
267 if (ret != NULL)
268 return ret;
269 ret = get_path_from_proc_exe ();
270 if (ret != NULL)
271 return ret;
272#endif
273#if WINDOWS
274 ret = get_path_from_module_filename ();
275 if (ret != NULL)
276 return ret;
277#endif
278#if DARWIN
279 ret = get_path_from_dyld_image ();
280 if (ret != NULL)
281 return ret;
282 ret = get_path_from_NSGetExecutablePath ();
283 if (ret != NULL)
284 return ret;
285#endif
286 ret = get_path_from_PATH ();
287 if (ret != NULL)
288 return ret;
289 /* other attempts here */
290 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
291 _
292 ("Could not determine installation path for %s. Set `%s' environment variable.\n"),
293 "gnunet-gtk",
294 "GNUNET_GTK_PREFIX");
295 return NULL;
296}
297
298/*
299 * @brief get the path to current app's bin/
300 * @author Milan
301 *
302 * @return a pointer to the executable path, or NULL on error
303 */
304static char *
305os_get_exec_path ()
306{
307 char *ret;
308
309 ret = NULL;
310#if LINUX
311 ret = get_path_from_proc_exe ();
312 if (ret != NULL)
313 return ret;
314#endif
315#if WINDOWS
316 ret = get_path_from_module_filename ();
317 if (ret != NULL)
318 return ret;
319#endif
320#if DARWIN
321 ret = get_path_from_NSGetExecutablePath ();
322 if (ret != NULL)
323 return ret;
324#endif
325 /* other attempts here */
326 return ret;
327}
328
329
330
331/**
332 * @brief get the path to a specific GNUnet installation directory or,
333 * with GNUNET_IPK_SELF_PREFIX, the current running apps installation directory
334 * @author Milan
335 * @return a pointer to the dir path (to be freed by the caller)
336 */
337char *
338GNUNET_GTK_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
339{
340 size_t n;
341 const char *dirname;
342 char *execpath = NULL;
343 char *tmp;
344 int isbasedir;
345
346 /* if wanted, try to get the current app's bin/ */
347 if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
348 execpath = os_get_exec_path ();
349
350 /* try to get GNUnet's bin/ or lib/, or if previous was unsuccessful some
351 * guess for the current app */
352 if (execpath == NULL)
353 execpath = os_get_gnunet_path ();
354
355 if (execpath == NULL)
356 return NULL;
357
358 n = strlen (execpath);
359 if (n == 0)
360 {
361 /* should never happen, but better safe than sorry */
362 GNUNET_free (execpath);
363 return NULL;
364 }
365 /* remove filename itself */
366 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
367 execpath[--n] = '\0';
368
369 isbasedir = 1;
370 if ((n > 5) &&
371 ((0 == strcasecmp (&execpath[n - 5], "lib32")) ||
372 (0 == strcasecmp (&execpath[n - 5], "lib64"))))
373 {
374 if (dirkind != GNUNET_OS_IPK_LIBDIR)
375 {
376 /* strip '/lib32' or '/lib64' */
377 execpath[n - 5] = '\0';
378 n -= 5;
379 }
380 else
381 isbasedir = 0;
382 }
383 else if ((n > 3) &&
384 ((0 == strcasecmp (&execpath[n - 3], "bin")) ||
385 (0 == strcasecmp (&execpath[n - 3], "lib"))))
386 {
387 /* strip '/bin' or '/lib' */
388 execpath[n - 3] = '\0';
389 n -= 3;
390 }
391 /* in case this was a directory named foo-bin, remove "foo-" */
392 while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
393 execpath[--n] = '\0';
394 switch (dirkind)
395 {
396 case GNUNET_OS_IPK_PREFIX:
397 case GNUNET_OS_IPK_SELF_PREFIX:
398 dirname = DIR_SEPARATOR_STR;
399 break;
400 case GNUNET_OS_IPK_BINDIR:
401 dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
402 break;
403 case GNUNET_OS_IPK_LIBDIR:
404 if (isbasedir)
405 dirname =
406 DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR "gnunet-gtk"
407 DIR_SEPARATOR_STR;
408 else
409 dirname = DIR_SEPARATOR_STR "gnunet-gtk" DIR_SEPARATOR_STR;
410 break;
411 case GNUNET_OS_IPK_DATADIR:
412 dirname =
413 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "gnunet-gtk"
414 DIR_SEPARATOR_STR;
415 break;
416 case GNUNET_OS_IPK_ICONDIR:
417 dirname =
418 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
419 break;
420 case GNUNET_OS_IPK_LOCALEDIR:
421 dirname =
422 DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale"
423 DIR_SEPARATOR_STR;
424 break;
425 default:
426 GNUNET_free (execpath);
427 return NULL;
428 }
429 tmp = GNUNET_malloc (strlen (execpath) + strlen (dirname) + 1);
430 sprintf (tmp, "%s%s", execpath, dirname);
431 GNUNET_free (execpath);
432 return tmp;
433}
434
435/* end of os_installation.c */