1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
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
15 #include <sys/types.h>
16 #include <sys/socket.h>
22 #include "marshalers.h"
27 /*** remote protocol structure ***/
28 #define REMOTE_PROTOCOL_ACK 'A'
29 #define REMOTE_PROTOCOL_PRESENT 'P'
30 #define REMOTE_PROTOCOL_CHANGE_USER 'U'
38 /*** LogJamRemote object ***/
39 struct _LogJamRemote
{
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
);
58 static guint signals
[LAST_SIGNAL
] = { 0 };
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
);
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
),
79 G_STRUCT_OFFSET(LogJamRemoteClass
, present
),
81 g_cclosure_marshal_VOID__VOID
,
84 signals
[CHANGE_USER
] = g_signal_new("change_user",
85 G_OBJECT_CLASS_TYPE(gclass
),
87 G_STRUCT_OFFSET(LogJamRemoteClass
, change_user
),
89 logjam_marshal_BOOLEAN__STRING_POINTER
,
90 G_TYPE_BOOLEAN
, 2, G_TYPE_STRING
, G_TYPE_POINTER
);
94 logjam_remote_init(GTypeInstance
*inst
, gpointer g_class
) {
95 LogJamRemote
*remote
= (LogJamRemote
*)inst
;
100 logjam_remote_get_type() {
101 static GType remote_type
= 0;
103 static const GTypeInfo remote_info
= {
104 sizeof(LogJamRemoteClass
),
107 logjam_remote_class_init
,
110 sizeof(LogJamRemote
),
114 remote_type
= g_type_register_static(G_TYPE_OBJECT
, "LogJamRemote",
121 logjam_remote_new(void) {
122 return g_object_new(logjam_remote_get_type(), NULL
);
126 remote_error_quark(void) {
127 static GQuark quark
= 0;
129 quark
= g_quark_from_static_string("remote-error-quark");
135 make_remote_path(char *buf
, int len
) {
136 g_snprintf(buf
, len
, "%s/remote", app
.conf_dir
);
140 remote_connect(GError
**err
) {
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
));
150 saddr
.sun_family
= AF_UNIX
;
151 make_remote_path(saddr
.sun_path
, 100);
152 if (connect(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0) {
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. */
166 remote_send(char command
, gpointer data
, int datalen
, GError
**err
) {
170 if ((fd
= remote_connect(err
)) < 0)
173 len
= write(fd
, &command
, 1);
175 g_set_error(err
, REMOTE_ERROR
, REMOTE_ERROR_SYSTEM
,
176 "write: %s", g_strerror(errno
));
180 len
= write(fd
, data
, datalen
);
182 g_set_error(err
, REMOTE_ERROR
, REMOTE_ERROR_SYSTEM
,
183 "write: %s", g_strerror(errno
));
188 len
= read(fd
, &response
, 1);
190 g_set_error(err
, REMOTE_ERROR
, REMOTE_ERROR_SYSTEM
,
191 "read: %s", g_strerror(errno
));
197 if (response
== REMOTE_PROTOCOL_ACK
)
201 #endif /* G_OS_WIN32 */
204 remote_send_user(const char *username
, GError
**err
) {
209 RemoteChangeLJUser user
;
210 strcpy(user
.username
, username
);
212 return remote_send(REMOTE_PROTOCOL_CHANGE_USER
,
213 &user
, sizeof(RemoteChangeLJUser
), err
);
215 return remote_send(REMOTE_PROTOCOL_PRESENT
, NULL
, 0, err
);
217 #endif /* G_OS_WIN32 */
222 remote_recieve_change_user(LogJamRemote
*remote
, int fd
) {
223 RemoteChangeLJUser user
;
228 readret
= read(fd
, &user
, sizeof(RemoteChangeLJUser
));
230 /*jam_warning(win, _("Accepting remote command: %s: %s."),
231 "read", g_strerror(errno));*/
236 g_signal_emit_by_name(remote
, "change_user",
237 user
.username
, &err
, &signalret
);
242 io_cb(GIOChannel
*channel
, GIOCondition cond
, gpointer data
) {
243 LogJamRemote
*remote
= (LogJamRemote
*)data
;
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
);
252 /*jam_warning(win, _("Accepting remote command: %s: %s."),
253 "accept", g_strerror(errno));*/
257 ret
= read(fd
, &command
, 1);
259 /*jam_warning(win, _("Accepting remote command: %s: %s."),
260 "read", g_strerror(errno));*/
266 case REMOTE_PROTOCOL_PRESENT
:
267 g_signal_emit_by_name(remote
, "present");
269 case REMOTE_PROTOCOL_CHANGE_USER
:
270 if (!remote_recieve_change_user(remote
, fd
))
274 //jam_warning(win, _("Unknown remote command (%c)."), command);
279 command
= REMOTE_PROTOCOL_ACK
;
280 write(fd
, &command
, 1);
286 #endif /* G_OS_WIN32 */
289 logjam_remote_listen(LogJamRemote
*remote
, GError
**err
) {
293 struct sockaddr_un saddr
;
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
));
305 saddr
.sun_family
= AF_UNIX
;
306 make_remote_path(saddr
.sun_path
, 100);
307 unlink(saddr
.sun_path
);
309 if (bind(remote
->fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) < 0) {
312 g_set_error(err
, REMOTE_ERROR
, REMOTE_ERROR_SYSTEM
,
313 "bind: %s", g_strerror(errno
));
317 if (listen(remote
->fd
, 1) < 0) {
320 g_set_error(err
, REMOTE_ERROR
, REMOTE_ERROR_SYSTEM
,
321 "listen: %s", g_strerror(errno
));
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
,
330 g_io_channel_unref(channel
);
333 #endif /* G_OS_WIN32 */
337 logjam_remote_stop_listening(LogJamRemote
*remote
, GError
**err
) {
349 make_remote_path(buf
, 128);
353 #endif /* G_OS_WIN32 */