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 */
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
)
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
);
54 g_printerr("%s\n", err
->message
);
56 g_io_channel_unref(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
)
75 res
= g_strdup_printf("%s/.19830128gliv_%s", g_get_tmp_dir(), user_name
);
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
)
103 gchar command
= make_command(clear_list
);
105 g_io_channel_write_chars(channel
, &command
, 1, &bytes
, &err
);
108 g_printerr("%s\n", err
->message
);
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
) {
121 g_printerr("%s\n", err
->message
);
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
)
140 struct stat client_stat
, server_stat
;
144 g_io_channel_read_chars(channel
, &command
, 1, &size
, &err
);
147 g_printerr("%s\n", err
->message
);
152 *clear_list
= should_clear_list(command
);
155 g_io_channel_read_line(channel
, client_dir
, &size
, NULL
, &err
);
157 g_printerr("%s\n", err
->message
);
162 server_dir
= g_get_current_dir();
163 if (stat(*client_dir
, &client_stat
) < 0 ||
164 stat(server_dir
, &server_stat
) < 0) {
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.
187 static gint
create_server_socket(void)
189 struct sockaddr_un name
;
194 sock
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
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. */
210 size
= SUN_LEN(&name
);
212 if (bind(sock
, (struct sockaddr
*) &name
, size
) < 0) {
216 } else if (listen(sock
, 5) < 0) {
225 /* Put the '\0' separated strings in an array. */
226 static gchar
**rebuild_args_array(gchar
* data
, gint length
, gint
* count
,
230 gchar
*last
= data
+ length
, *ptr
= data
;
233 /* How many strings? */
236 ptr
+= strlen(ptr
) + 1;
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
);
246 tab
[i
] = g_build_filename(client_dir
, data
, NULL
);
248 data
+= strlen(data
) + 1;
254 /* Add the filenames and open the next image. */
255 static void process_data(gchar
* data
, gint length
, gchar
* client_dir
,
258 gint i
, count
, nb_inserted
;
260 GList
*before_inserted
= NULL
;
261 GList
*after_inserted
= NULL
;
263 tab
= rebuild_args_array(data
, length
, &count
, client_dir
);
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
++)
288 /* Called when there is something to read. */
289 static gboolean
handle_connect(GIOChannel
* source
, GIOCondition unused1
,
300 fd
= accept(g_io_channel_unix_get_fd(source
), NULL
, NULL
);
306 channel
= make_channel(fd
);
310 /* Fill the param. */
311 if (!read_param(channel
, &client_dir
, &clear_list
)) {
312 g_io_channel_unref(channel
);
316 /* Read the filenames. */
317 g_io_channel_read_to_end(channel
, &data
, &length
, &err
);
319 g_printerr("%s\n", err
->message
);
321 g_io_channel_unref(channel
);
325 process_data(data
, length
, client_dir
, clear_list
);
326 g_io_channel_unref(channel
);
330 gboolean
start_server(void)
335 socket
= create_server_socket();
339 channel
= make_channel(socket
);
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. */
351 watch_id
= g_io_add_watch(channel
, G_IO_IN
, (GIOFunc
) handle_connect
, NULL
);
358 static gint
create_client_socket(void)
360 struct sockaddr_un name
;
365 sock
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
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';
378 size
= SUN_LEN(&name
);
379 if (connect(sock
, (struct sockaddr
*) &name
, size
) < 0) {
388 gboolean
connect_server(gboolean clear_list
)
395 fd
= create_client_socket();
399 channel
= make_channel(fd
);
403 /* Send our current directory. */
404 if (!write_param(channel
, clear_list
)) {
405 g_io_channel_unref(channel
);
410 /* Send all the filenames with '\0' between them. */
411 for (list
= get_list_head(); list
!= NULL
; list
= list
->next
) {
413 gint length
= strlen(list
->data
) + 1;
416 g_io_channel_write_chars(channel
, list
->data
, length
, &size
, &err
);
418 g_printerr("%s\n", err
->message
);
420 g_io_channel_unref(channel
);
425 g_io_channel_unref(channel
);