about.c: cosmetix
[k8lowj.git] / src / remote.c
blob69fac253687952598017420800f78764d314d5ed
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 /* remote code written after reading xmms remote code.
8 * Copyright (C) 1998-2002 Peter Alm, Mikael Alm, Olle Hallnas,
9 * Thomas Nilsson and 4Front Technologies
10 * Copyright (C) 1999-2002 Haavard Kvaalen
13 #include "gtk-all.h"
14 #ifndef G_OS_WIN32
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #endif
22 #include "marshalers.h"
24 #include "conf.h"
25 #include "remote.h"
27 /*** remote protocol structure ***/
28 #define REMOTE_PROTOCOL_ACK 'A'
29 #define REMOTE_PROTOCOL_PRESENT 'P'
30 #define REMOTE_PROTOCOL_CHANGE_USER 'U'
32 typedef struct {
33 char username[50];
34 gboolean login;
35 } RemoteChangeLJUser;
38 /*** LogJamRemote object ***/
39 struct _LogJamRemote {
40 GObject parent;
42 int fd;
45 struct _LogJamRemoteClass {
46 GObjectClass parent_class;
47 void (*present)(LogJamRemote *remote);
48 gboolean (*change_user)(LogJamRemote *remote,
49 char* username, gboolean skip, GError **err);
52 enum {
53 PRESENT,
54 CHANGE_USER,
55 LAST_SIGNAL
58 static guint signals[LAST_SIGNAL] = { 0 };
60 static void
61 logjam_remote_finalize(GObject *object) {
62 GObjectClass *parent_class;
64 logjam_remote_stop_listening((LogJamRemote*)object, NULL);
66 parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
67 parent_class->finalize(object);
70 static void
71 logjam_remote_class_init(gpointer klass, gpointer class_data) {
72 GObjectClass *gclass = G_OBJECT_CLASS(klass);
74 gclass->finalize = logjam_remote_finalize;
76 signals[PRESENT] = g_signal_new("present",
77 G_OBJECT_CLASS_TYPE(gclass),
78 G_SIGNAL_RUN_LAST,
79 G_STRUCT_OFFSET(LogJamRemoteClass, present),
80 NULL, NULL,
81 g_cclosure_marshal_VOID__VOID,
82 G_TYPE_NONE, 0);
84 signals[CHANGE_USER] = g_signal_new("change_user",
85 G_OBJECT_CLASS_TYPE(gclass),
86 G_SIGNAL_RUN_LAST,
87 G_STRUCT_OFFSET(LogJamRemoteClass, change_user),
88 NULL, NULL,
89 logjam_marshal_BOOLEAN__STRING_POINTER,
90 G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_POINTER);
93 static void
94 logjam_remote_init(GTypeInstance *inst, gpointer g_class) {
95 LogJamRemote *remote = (LogJamRemote*)inst;
96 remote->fd = -1;
99 GType
100 logjam_remote_get_type() {
101 static GType remote_type = 0;
102 if (!remote_type) {
103 static const GTypeInfo remote_info = {
104 sizeof(LogJamRemoteClass),
105 NULL,
106 NULL,
107 logjam_remote_class_init,
108 NULL,
109 NULL,
110 sizeof(LogJamRemote),
112 logjam_remote_init
114 remote_type = g_type_register_static(G_TYPE_OBJECT, "LogJamRemote",
115 &remote_info, 0);
117 return remote_type;
120 LogJamRemote*
121 logjam_remote_new(void) {
122 return g_object_new(logjam_remote_get_type(), NULL);
125 GQuark
126 remote_error_quark(void) {
127 static GQuark quark = 0;
128 if (quark == 0)
129 quark = g_quark_from_static_string("remote-error-quark");
130 return quark;
133 #ifndef G_OS_WIN32
134 static void
135 make_remote_path(char *buf, int len) {
136 g_snprintf(buf, len, "%s/remote", app.conf_dir);
139 static int
140 remote_connect(GError **err) {
141 int fd;
142 struct sockaddr_un saddr;
144 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
145 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
146 "socket: %s", g_strerror(errno));
147 return -1;
150 saddr.sun_family = AF_UNIX;
151 make_remote_path(saddr.sun_path, 100);
152 if (connect(fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
153 close(fd);
154 if (errno != ENOENT && errno != ECONNREFUSED) {
155 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
156 "connect: %s", g_strerror(errno));
158 /* ENOENT is not a real error; there was just nobody there. */
159 return -1;
162 return fd;
165 static gboolean
166 remote_send(char command, gpointer data, int datalen, GError **err) {
167 int fd, len;
168 char response;
170 if ((fd = remote_connect(err)) < 0)
171 return FALSE;
173 len = write(fd, &command, 1);
174 if (len < 0) {
175 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
176 "write: %s", g_strerror(errno));
177 return FALSE;
179 if (datalen > 0) {
180 len = write(fd, data, datalen);
181 if (len < 0) {
182 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
183 "write: %s", g_strerror(errno));
184 return FALSE;
188 len = read(fd, &response, 1);
189 if (len < 0) {
190 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
191 "read: %s", g_strerror(errno));
192 return FALSE;
194 if (len < 1)
195 return FALSE;
197 if (response == REMOTE_PROTOCOL_ACK)
198 return TRUE;
199 return FALSE;
201 #endif /* G_OS_WIN32 */
203 gboolean
204 remote_send_user(const char *username, GError **err) {
205 #ifdef G_OS_WIN32
206 return FALSE;
207 #else
208 if (username) {
209 RemoteChangeLJUser user;
210 strcpy(user.username, username);
211 user.login = TRUE;
212 return remote_send(REMOTE_PROTOCOL_CHANGE_USER,
213 &user, sizeof(RemoteChangeLJUser), err);
214 } else {
215 return remote_send(REMOTE_PROTOCOL_PRESENT, NULL, 0, err);
217 #endif /* G_OS_WIN32 */
220 #ifndef G_OS_WIN32
221 static gboolean
222 remote_recieve_change_user(LogJamRemote *remote, int fd) {
223 RemoteChangeLJUser user;
224 int readret;
225 gboolean signalret;
226 GError *err = NULL;
228 readret = read(fd, &user, sizeof(RemoteChangeLJUser));
229 if (readret < 0) {
230 /*jam_warning(win, _("Accepting remote command: %s: %s."),
231 "read", g_strerror(errno));*/
232 close(fd);
233 return FALSE;
236 g_signal_emit_by_name(remote, "change_user",
237 user.username, &err, &signalret);
238 return TRUE;
241 static gboolean
242 io_cb(GIOChannel *channel, GIOCondition cond, gpointer data) {
243 LogJamRemote *remote = (LogJamRemote*)data;
244 char command;
245 int fd, ret;
246 struct sockaddr_un saddr;
247 socklen_t addrlen = sizeof(struct sockaddr_un);
249 if (cond == G_IO_IN) {
250 fd = accept(remote->fd, (struct sockaddr*)&saddr, &addrlen);
251 if (fd < 0) {
252 /*jam_warning(win, _("Accepting remote command: %s: %s."),
253 "accept", g_strerror(errno));*/
254 return TRUE;
257 ret = read(fd, &command, 1);
258 if (ret < 0) {
259 /*jam_warning(win, _("Accepting remote command: %s: %s."),
260 "read", g_strerror(errno));*/
261 close(fd);
262 return TRUE;
265 switch (command) {
266 case REMOTE_PROTOCOL_PRESENT:
267 g_signal_emit_by_name(remote, "present");
268 break;
269 case REMOTE_PROTOCOL_CHANGE_USER:
270 if (!remote_recieve_change_user(remote, fd))
271 return TRUE;
272 break;
273 default:
274 //jam_warning(win, _("Unknown remote command (%c)."), command);
275 close(fd);
276 return TRUE;
279 command = REMOTE_PROTOCOL_ACK;
280 write(fd, &command, 1);
281 close(fd);
284 return TRUE;
286 #endif /* G_OS_WIN32 */
288 gboolean
289 logjam_remote_listen(LogJamRemote *remote, GError **err) {
290 #ifdef G_OS_WIN32
291 return FALSE;
292 #else
293 struct sockaddr_un saddr;
294 GIOChannel *channel;
296 if (remote->fd > 0)
297 return TRUE;
299 if ((remote->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
300 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
301 "socket: %s", g_strerror(errno));
302 return FALSE;
305 saddr.sun_family = AF_UNIX;
306 make_remote_path(saddr.sun_path, 100);
307 unlink(saddr.sun_path);
308 conf_verify_dir();
309 if (bind(remote->fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) {
310 close(remote->fd);
311 remote->fd = -1;
312 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
313 "bind: %s", g_strerror(errno));
314 return FALSE;
317 if (listen(remote->fd, 1) < 0) {
318 close(remote->fd);
319 remote->fd = -1;
320 g_set_error(err, REMOTE_ERROR, REMOTE_ERROR_SYSTEM,
321 "listen: %s", g_strerror(errno));
322 return FALSE;
325 channel = g_io_channel_unix_new(remote->fd);
326 g_io_channel_set_encoding(channel, NULL, NULL);
327 g_io_channel_set_buffered(channel, FALSE);
328 g_io_add_watch(channel, G_IO_IN|G_IO_ERR,
329 io_cb, remote);
330 g_io_channel_unref(channel);
332 return TRUE;
333 #endif /* G_OS_WIN32 */
336 gboolean
337 logjam_remote_stop_listening(LogJamRemote *remote, GError **err) {
338 #ifdef G_OS_WIN32
339 return FALSE;
340 #else
341 char buf[128];
343 if (remote->fd <= 0)
344 return TRUE;
346 close(remote->fd);
347 remote->fd = -1;
349 make_remote_path(buf, 128);
350 unlink(buf);
352 return TRUE;
353 #endif /* G_OS_WIN32 */