Merged older cs.po file with newest pot file.
[gliv/czech_localization.git] / src / ipc.c
blob296c205ca14401cd33e5582941aba9dd91cdc2f7
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@yahoo.fr>
21 /************************************************
22 * IPC between gliv processes to reuse a window *
23 ************************************************/
25 #include <unistd.h> /* unlink(), close(), write() */
26 #include <sys/types.h> /* struct sockaddr */
27 #include <sys/socket.h> /* socket(), ... */
28 #include <sys/un.h> /* AF_LOCAL */
29 #include <string.h> /* strncpy() */
30 #include <stdio.h> /* perror(), fread(), stdin */
31 #include <sys/stat.h>
33 #include "gliv.h"
34 #include "ipc.h"
35 #include "files_list.h"
36 #include "next_image.h"
38 extern GlivImage *current_image;
40 /* The current server. */
41 static guint watch_id;
42 static GIOChannel *server = NULL;
44 /* Transform a file descriptor into a GIOChannel. */
45 static GIOChannel *make_channel(gint fd)
47 GIOChannel *channel;
48 GError *err = NULL;
50 channel = g_io_channel_unix_new(fd);
51 g_io_channel_set_close_on_unref(channel, TRUE);
52 g_io_channel_set_encoding(channel, NULL, &err);
53 if (err != NULL) {
54 g_printerr("%s\n", err->message);
55 g_error_free(err);
56 g_io_channel_unref(channel);
57 channel = NULL;
60 return channel;
63 /*** Where do we keep this socket? ***/
65 static gchar *get_socket_name(void)
67 gchar *user_name, *repl, *res;
69 repl = user_name = g_strdup(g_get_user_name());
71 /* Do people have '/' in their user names? */
72 while ((repl = strchr(repl, '/')) != NULL)
73 *repl = '_';
75 res = g_strdup_printf("%s/.19830128gliv_%s", g_get_tmp_dir(), user_name);
76 g_free(user_name);
78 return res;
81 /*** State encoding by the client for the server. ***/
83 static gboolean should_clear_list(gchar command)
85 return command == 'c';
88 static gchar make_command(gboolean clear_list)
90 return clear_list ? 'c' : 'C';
94 * We send the working directory in order to deal with relative filenames.
96 static gboolean write_param(GIOChannel * channel, gboolean clear_list)
98 gchar *current_dir;
99 gint length;
100 gboolean res = TRUE;
101 gsize bytes = 0;
102 GError *err = NULL;
103 gchar command = make_command(clear_list);
105 g_io_channel_write_chars(channel, &command, 1, &bytes, &err);
106 if (bytes != 1) {
107 if (err != NULL) {
108 g_printerr("%s\n", err->message);
109 g_error_free(err);
111 return FALSE;
114 current_dir = g_get_current_dir();
115 length = strlen(current_dir) + 1;
117 g_io_channel_write_chars(channel, current_dir, length, &bytes, &err);
118 if (bytes != length) {
119 res = FALSE;
120 if (err != NULL) {
121 g_printerr("%s\n", err->message);
122 g_error_free(err);
126 g_free(current_dir);
128 return res;
132 * We read what the function above sent. If the server and the client are
133 * running in the same directory we put NULL in *client_dir.
135 static gboolean read_param(GIOChannel * channel, gchar ** client_dir,
136 gboolean * clear_list)
138 size_t size = 0;
139 gchar *server_dir;
140 struct stat client_stat, server_stat;
141 GError *err = NULL;
142 gchar command;
144 g_io_channel_read_chars(channel, &command, 1, &size, &err);
145 if (size != 1) {
146 if (err != NULL) {
147 g_printerr("%s\n", err->message);
148 g_error_free(err);
150 return FALSE;
152 *clear_list = should_clear_list(command);
154 *client_dir = NULL;
155 g_io_channel_read_line(channel, client_dir, &size, NULL, &err);
156 if (err != NULL) {
157 g_printerr("%s\n", err->message);
158 g_error_free(err);
159 return FALSE;
162 server_dir = g_get_current_dir();
163 if (stat(*client_dir, &client_stat) < 0 ||
164 stat(server_dir, &server_stat) < 0) {
166 g_free(server_dir);
167 g_free(*client_dir);
168 return FALSE;
171 if (client_stat.st_dev == server_stat.st_dev &&
172 client_stat.st_ino == server_stat.st_ino) {
174 * The client and server are in the same directory, we can use relative
175 * filenames without problems.
177 g_free(*client_dir);
178 *client_dir = NULL;
181 g_free(server_dir);
182 return TRUE;
185 /*** Server ***/
187 static gint create_server_socket(void)
189 struct sockaddr_un name;
190 gint sock;
191 gchar *filename;
192 size_t size;
194 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
195 if (sock < 0) {
196 perror("socket");
197 return -1;
200 name.sun_family = AF_LOCAL;
202 filename = get_socket_name();
203 strncpy(name.sun_path, filename, sizeof(name.sun_path) - 1);
204 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
206 /* The latest launched gliv is the server. */
207 unlink(filename);
209 g_free(filename);
210 size = SUN_LEN(&name);
212 if (bind(sock, (struct sockaddr *) &name, size) < 0) {
213 perror("bind");
214 close(sock);
215 sock = -1;
216 } else if (listen(sock, 5) < 0) {
217 perror("listen");
218 close(sock);
219 sock = -1;
222 return sock;
225 /* Put the '\0' separated strings in an array. */
226 static gchar **rebuild_args_array(gchar * data, gint length, gint * count,
227 gchar * client_dir)
229 gint i;
230 gchar *last = data + length, *ptr = data;
231 gchar **tab;
233 /* How many strings? */
234 *count = 0;
235 while (ptr < last) {
236 ptr += strlen(ptr) + 1;
237 (*count)++;
240 /* Cut them. */
241 tab = g_new(gchar *, *count);
242 for (i = 0; i < *count; i++) {
243 if (client_dir == NULL || data[0] == '/')
244 tab[i] = g_strdup(data);
245 else
246 tab[i] = g_build_filename(client_dir, data, NULL);
248 data += strlen(data) + 1;
251 return tab;
254 /* Add the filenames and open the next image. */
255 static void process_data(gchar * data, gint length, gchar * client_dir,
256 gboolean clear_list)
258 gint i, count, nb_inserted;
259 gchar **tab;
260 GList *before_inserted = NULL;
261 GList *after_inserted = NULL;
263 tab = rebuild_args_array(data, length, &count, client_dir);
265 if (clear_list) {
266 before_inserted = current_image ? current_image->node : get_list_head();
267 after_inserted = before_inserted ? before_inserted->next : NULL;
270 nb_inserted = insert_after_current(tab, count, TRUE, FALSE);
271 while (before_inserted) {
272 add_obsolete_node(before_inserted);
273 before_inserted = before_inserted->prev;
276 while (after_inserted) {
277 add_obsolete_node(after_inserted);
278 after_inserted = after_inserted->next;
280 new_images(nb_inserted);
282 for (i = 0; i < count; i++)
283 g_free(tab[i]);
285 g_free(tab);
288 /* Called when there is something to read. */
289 static gboolean handle_connect(GIOChannel * source, GIOCondition unused1,
290 gpointer unused2)
292 gchar *data;
293 gsize length = 0;
294 gint fd;
295 GError *err = NULL;
296 GIOChannel *channel;
297 gchar *client_dir;
298 gboolean clear_list;
300 fd = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
301 if (fd < 0) {
302 perror("accept");
303 return TRUE;
306 channel = make_channel(fd);
307 if (channel == NULL)
308 return TRUE;
310 /* Fill the param. */
311 if (!read_param(channel, &client_dir, &clear_list)) {
312 g_io_channel_unref(channel);
313 return TRUE;
316 /* Read the filenames. */
317 g_io_channel_read_to_end(channel, &data, &length, &err);
318 if (err != NULL) {
319 g_printerr("%s\n", err->message);
320 g_error_free(err);
321 g_io_channel_unref(channel);
322 return TRUE;
325 process_data(data, length, client_dir, clear_list);
326 g_io_channel_unref(channel);
327 return TRUE;
330 gboolean start_server(void)
332 gint socket;
333 GIOChannel *channel;
335 socket = create_server_socket();
336 if (socket < 0)
337 return FALSE;
339 channel = make_channel(socket);
340 if (channel == NULL)
341 return FALSE;
343 /* Remove the previous wait. */
344 if (server != NULL) {
345 g_source_remove(watch_id);
346 g_io_channel_unref(server);
349 /* Let GTK+ inform us about clients. */
350 server = channel;
351 watch_id = g_io_add_watch(channel, G_IO_IN, (GIOFunc) handle_connect, NULL);
353 return FALSE;
356 /*** Client ***/
358 static gint create_client_socket(void)
360 struct sockaddr_un name;
361 gint sock;
362 gchar *filename;
363 size_t size;
365 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
366 if (sock < 0) {
367 perror("socket");
368 return -1;
371 name.sun_family = AF_LOCAL;
373 filename = get_socket_name();
374 strncpy(name.sun_path, filename, sizeof(name.sun_path) - 1);
375 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
376 g_free(filename);
378 size = SUN_LEN(&name);
379 if (connect(sock, (struct sockaddr *) &name, size) < 0) {
380 perror("connect");
381 close(sock);
382 sock = -1;
385 return sock;
388 gboolean connect_server(gboolean clear_list)
390 gboolean ret = TRUE;
391 gint fd;
392 GIOChannel *channel;
393 GList *list;
395 fd = create_client_socket();
396 if (fd < 0)
397 return FALSE;
399 channel = make_channel(fd);
400 if (channel == NULL)
401 goto out;
403 /* Send our current directory. */
404 if (!write_param(channel, clear_list)) {
405 g_io_channel_unref(channel);
406 ret = FALSE;
407 goto out;
410 /* Send all the filenames with '\0' between them. */
411 for (list = get_list_head(); list != NULL; list = list->next) {
412 gsize size;
413 gint length = strlen(list->data) + 1;
414 GError *err = NULL;
416 g_io_channel_write_chars(channel, list->data, length, &size, &err);
417 if (err != NULL) {
418 g_printerr("%s\n", err->message);
419 g_error_free(err);
420 g_io_channel_unref(channel);
421 goto out;
425 g_io_channel_unref(channel);
427 out:
428 return ret;