4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
30 #include <sys/socket.h>
42 static gint UI_fd
= -1;
45 static guchar
*UI_build(guint32
*len
, guchar type
, guchar subtype
, va_list args
)
52 *len
= sizeof(guchar
) * 2 + 4;
53 buffer
= g_malloc(*len
);
56 memcpy(buffer
+ pos
, &type
, sizeof(type
)); pos
+= sizeof(type
);
57 memcpy(buffer
+ pos
, &subtype
, sizeof(subtype
)); pos
+= sizeof(subtype
);
59 /* we come back and do size last */
62 size
= va_arg(args
, int);
65 buffer
= g_realloc(buffer
, *len
);
67 data
= va_arg(args
, void *);
68 memcpy(buffer
+ pos
, data
, size
);
71 size
= va_arg(args
, int);
74 pos
-= sizeof(guchar
) * 2 + 4;
77 memcpy(buffer
+ sizeof(guchar
) * 2, &pos
, 4);
82 gint
UI_write(struct UI
*ui
, guchar
*data
, gint len
)
85 /* we'll let the write silently fail because the read will pick it up as dead */
86 g_io_channel_write(ui
->channel
, data
, len
, &sent
);
90 void UI_build_write(struct UI
*ui
, guchar type
, guchar subtype
, ...)
96 va_start(ap
, subtype
);
97 data
= UI_build(&len
, type
, subtype
, ap
);
100 UI_write(ui
, data
, len
);
105 void UI_broadcast(guchar
*data
, gint len
)
109 struct UI
*ui
= u
->data
;
110 UI_write(ui
, data
, len
);
115 void UI_build_broadcast(guchar type
, guchar subtype
, ...)
124 va_start(ap
, subtype
);
125 data
= UI_build(&len
, type
, subtype
, ap
);
128 UI_broadcast(data
, len
);
133 static void meta_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
141 uis
= g_slist_remove(uis
, ui
);
142 g_io_channel_close(ui
->channel
);
143 g_source_remove(ui
->inpa
);
148 case CUI_META_DETACH
:
149 uis
= g_slist_remove(uis
, ui
);
150 g_io_channel_close(ui
->channel
);
151 g_source_remove(ui
->inpa
);
155 debug_printf("unhandled meta subtype %d\n", subtype
);
160 static void plugin_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
164 struct gaim_plugin
*p
;
168 case CUI_PLUGIN_LIST:
171 case CUI_PLUGIN_LOAD
:
172 p
= load_plugin(data
);
173 /* XXX need to broadcast to UIs that plugin has been loaded */
175 case CUI_PLUGIN_UNLOAD
:
176 memcpy(&id
, data
, sizeof(id
));
177 p
= g_list_nth_data(plugins
, id
);
180 /* XXX need to broadcast to UIs that plugin has been unloaded */
183 case CUI_PLUGIN_RELOAD
:
184 memcpy(&id
, data
, sizeof(id
));
185 p
= g_list_nth_data(plugins
, id
);
187 p
= reload_plugin(p
);
188 /* XXX need to broadcast to UIs that plugin has been reloaded */
192 debug_printf("unhandled plugin subtype %d\n", subtype
);
198 static void user_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
209 case CUI_USER_REMOVE:
211 case CUI_USER_MODIFY:
214 case CUI_USER_SIGNON
:
217 memcpy(&id
, data
, sizeof(id
));
218 u
= g_slist_nth_data(aim_users
, id
);
221 /* don't need to do anything here because the UI will get updates from other handlers */
224 debug_printf("unhandled user subtype %d\n", subtype
);
229 static void message_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
232 case CUI_MESSAGE_LIST
:
234 case CUI_MESSAGE_SEND
:
239 struct gaim_connection
*gc
;
245 memcpy(&id
, data
+ pos
, sizeof(id
));
247 gc
= g_slist_nth_data(connections
, id
);
251 memcpy(&len
, data
+ pos
, sizeof(len
));
253 who
= g_strndup(data
+ pos
, len
+ 1);
256 memcpy(&len
, data
+ pos
, sizeof(len
));
258 msg
= g_strndup(data
+ pos
, len
+ 1);
261 memcpy(&flags
, data
+ pos
, sizeof(flags
));
262 serv_send_im(gc
, who
, msg
, -1, flags
);
268 case CUI_MESSAGE_RECV
:
271 debug_printf("unhandled message subtype %d\n", subtype
);
276 static gint
gaim_recv(GIOChannel
*source
, guchar
*buf
, gint len
)
281 while (total
< len
) {
282 if (g_io_channel_read(source
, buf
+ total
, len
- total
, &cur
) != G_IO_ERROR_NONE
)
292 static gboolean
UI_readable(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
294 struct UI
*ui
= data
;
302 /* no byte order worries! this'll change if we go to TCP */
303 if (gaim_recv(source
, &type
, sizeof(type
)) != sizeof(type
)) {
304 debug_printf("UI has abandoned us!\n");
305 uis
= g_slist_remove(uis
, ui
);
306 g_io_channel_close(ui
->channel
);
307 g_source_remove(ui
->inpa
);
312 if (gaim_recv(source
, &subtype
, sizeof(subtype
)) != sizeof(subtype
)) {
313 debug_printf("UI has abandoned us!\n");
314 uis
= g_slist_remove(uis
, ui
);
315 g_io_channel_close(ui
->channel
);
316 g_source_remove(ui
->inpa
);
321 if (gaim_recv(source
, (guchar
*)&len
, sizeof(len
)) != sizeof(len
)) {
322 debug_printf("UI has abandoned us!\n");
323 uis
= g_slist_remove(uis
, ui
);
324 g_io_channel_close(ui
->channel
);
325 g_source_remove(ui
->inpa
);
331 in
= g_new0(guchar
, len
);
332 if (gaim_recv(source
, in
, len
) != len
) {
333 debug_printf("UI has abandoned us!\n");
334 uis
= g_slist_remove(uis
, ui
);
335 g_io_channel_close(ui
->channel
);
336 g_source_remove(ui
->inpa
);
345 meta_handler(ui
, subtype
, in
);
347 case CUI_TYPE_PLUGIN
:
348 plugin_handler(ui
, subtype
, in
);
351 user_handler(ui
, subtype
, in
);
355 conn_handler(ui, subtype, in);
358 buddy_handler(ui, subtype, in);
361 case CUI_TYPE_MESSAGE
:
362 message_handler(ui
, subtype
, in
);
366 chat_handler(ui, subtype, in);
370 debug_printf("unhandled type %d\n", type
);
379 static gboolean
socket_readable(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
381 struct sockaddr_un saddr
;
387 if ((fd
= accept(UI_fd
, (struct sockaddr
*)&saddr
, &len
)) == -1)
390 ui
= g_new0(struct UI
, 1);
391 uis
= g_slist_append(uis
, ui
);
393 ui
->channel
= g_io_channel_unix_new(fd
);
394 ui
->inpa
= g_io_add_watch(ui
->channel
, G_IO_IN
| G_IO_HUP
| G_IO_ERR
, UI_readable
, ui
);
395 g_io_channel_unref(ui
->channel
);
397 debug_printf("got one\n");
401 static gint
open_socket()
403 struct sockaddr_un saddr
;
406 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) != -1) {
407 mode_t m
= umask(0177);
408 saddr
.sun_family
= AF_UNIX
;
409 g_snprintf(saddr
.sun_path
, 108, "%s/gaim_%s.%d",
410 g_get_tmp_dir(), g_get_user_name(), getpid());
411 if (bind(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) != -1)
414 g_log(NULL
, G_LOG_LEVEL_CRITICAL
,
415 "Failed to assign %s to a socket (Error: %s)",
416 saddr
.sun_path
, strerror(errno
));
419 g_log(NULL
, G_LOG_LEVEL_CRITICAL
, "Unable to open socket: %s", strerror(errno
));
431 UI_fd
= open_socket();
435 channel
= g_io_channel_unix_new(UI_fd
);
436 g_io_add_watch(channel
, G_IO_IN
, socket_readable
, NULL
);
437 g_io_channel_unref(channel
);
440 loop = g_main_new(TRUE);
451 sprintf(buf
, "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), getpid());
453 debug_printf("Removed core\n");