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>
35 #include <sys/socket.h>
48 #include "gaim-socket.h"
55 static gint UI_fd
= -1;
59 GSList
*groups
= NULL
;
61 static guchar
*UI_build(guint32
*len
, guchar type
, guchar subtype
, va_list args
)
68 *len
= sizeof(guchar
) * 2 + 4;
69 buffer
= g_malloc(*len
);
72 memcpy(buffer
+ pos
, &type
, sizeof(type
)); pos
+= sizeof(type
);
73 memcpy(buffer
+ pos
, &subtype
, sizeof(subtype
)); pos
+= sizeof(subtype
);
75 /* we come back and do size last */
78 size
= va_arg(args
, int);
81 buffer
= g_realloc(buffer
, *len
);
83 data
= va_arg(args
, void *);
84 memcpy(buffer
+ pos
, data
, size
);
87 size
= va_arg(args
, int);
90 pos
-= sizeof(guchar
) * 2 + 4;
93 memcpy(buffer
+ sizeof(guchar
) * 2, &pos
, 4);
98 gint
UI_write(struct UI
*ui
, guchar
*data
, gint len
)
101 /* we'll let the write silently fail because the read will pick it up as dead */
102 g_io_channel_write(ui
->channel
, data
, len
, &sent
);
106 void UI_build_write(struct UI
*ui
, guchar type
, guchar subtype
, ...)
112 va_start(ap
, subtype
);
113 data
= UI_build(&len
, type
, subtype
, ap
);
116 UI_write(ui
, data
, len
);
121 void UI_broadcast(guchar
*data
, gint len
)
125 struct UI
*ui
= u
->data
;
126 UI_write(ui
, data
, len
);
131 void UI_build_broadcast(guchar type
, guchar subtype
, ...)
140 va_start(ap
, subtype
);
141 data
= UI_build(&len
, type
, subtype
, ap
);
144 UI_broadcast(data
, len
);
150 static void meta_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
152 struct gaim_cui_packet
*p
;
159 uis
= g_slist_remove(uis
, ui
);
160 g_io_channel_close(ui
->channel
);
161 g_source_remove(ui
->inpa
);
166 case CUI_META_DETACH
:
167 uis
= g_slist_remove(uis
, ui
);
168 g_io_channel_close(ui
->channel
);
169 g_source_remove(ui
->inpa
);
173 p
= cui_packet_new(CUI_TYPE_META
, CUI_META_ACK
);
174 cui_send_packet(g_io_channel_unix_get_fd(ui
->channel
), p
);
178 debug_printf("unhandled meta subtype %d\n", subtype
);
183 static void plugin_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
187 struct gaim_plugin
*p
;
191 case CUI_PLUGIN_LIST:
194 case CUI_PLUGIN_LOAD
:
195 p
= load_plugin(data
);
196 /* XXX need to broadcast to UIs that plugin has been loaded */
198 case CUI_PLUGIN_UNLOAD
:
199 memcpy(&id
, data
, sizeof(id
));
200 p
= g_list_nth_data(plugins
, id
);
203 /* XXX need to broadcast to UIs that plugin has been unloaded */
207 debug_printf("unhandled plugin subtype %d\n", subtype
);
213 static void user_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
224 case CUI_USER_REMOVE:
226 case CUI_USER_MODIFY:
229 case CUI_USER_SIGNON
:
232 memcpy(&id
, data
, sizeof(id
));
233 u
= g_slist_nth_data(aim_users
, id
);
236 /* don't need to do anything here because the UI will get updates from other handlers */
239 debug_printf("unhandled user subtype %d\n", subtype
);
244 static void message_handler(struct UI
*ui
, guchar subtype
, guchar
*data
)
247 case CUI_MESSAGE_LIST
:
249 case CUI_MESSAGE_SEND
:
254 struct gaim_connection
*gc
;
260 memcpy(&id
, data
+ pos
, sizeof(id
));
262 gc
= g_slist_nth_data(connections
, id
);
266 memcpy(&len
, data
+ pos
, sizeof(len
));
268 who
= g_strndup(data
+ pos
, len
+ 1);
271 memcpy(&len
, data
+ pos
, sizeof(len
));
273 msg
= g_strndup(data
+ pos
, len
+ 1);
276 memcpy(&flags
, data
+ pos
, sizeof(flags
));
277 serv_send_im(gc
, who
, msg
, -1, flags
);
283 case CUI_MESSAGE_RECV
:
286 debug_printf("unhandled message subtype %d\n", subtype
);
291 static gint
gaim_recv(GIOChannel
*source
, guchar
*buf
, gint len
)
296 while (total
< len
) {
297 if (g_io_channel_read(source
, buf
+ total
, len
- total
, &cur
) != G_IO_ERROR_NONE
)
307 static void remote_handler(struct UI
*ui
, guchar subtype
, guchar
*data
, int len
)
312 case CUI_REMOTE_CONNECTIONS
:
315 send
= g_malloc(len
+ 1);
316 memcpy(send
, data
, len
);
318 resp
= handle_uri(send
);
323 debug_printf("Unhandled remote subtype %d\n", subtype
);
328 static gboolean
UI_readable(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
330 struct UI
*ui
= data
;
338 /* no byte order worries! this'll change if we go to TCP */
339 if (gaim_recv(source
, &type
, sizeof(type
)) != sizeof(type
)) {
340 debug_printf("UI has abandoned us!\n");
341 uis
= g_slist_remove(uis
, ui
);
342 g_io_channel_close(ui
->channel
);
343 g_source_remove(ui
->inpa
);
348 if (gaim_recv(source
, &subtype
, sizeof(subtype
)) != sizeof(subtype
)) {
349 debug_printf("UI has abandoned us!\n");
350 uis
= g_slist_remove(uis
, ui
);
351 g_io_channel_close(ui
->channel
);
352 g_source_remove(ui
->inpa
);
357 if (gaim_recv(source
, (guchar
*)&len
, sizeof(len
)) != sizeof(len
)) {
358 debug_printf("UI has abandoned us!\n");
359 uis
= g_slist_remove(uis
, ui
);
360 g_io_channel_close(ui
->channel
);
361 g_source_remove(ui
->inpa
);
367 in
= g_new0(guchar
, len
);
368 if (gaim_recv(source
, in
, len
) != len
) {
369 debug_printf("UI has abandoned us!\n");
370 uis
= g_slist_remove(uis
, ui
);
371 g_io_channel_close(ui
->channel
);
372 g_source_remove(ui
->inpa
);
381 meta_handler(ui
, subtype
, in
);
383 case CUI_TYPE_PLUGIN
:
384 plugin_handler(ui
, subtype
, in
);
387 user_handler(ui
, subtype
, in
);
391 conn_handler(ui, subtype, in);
394 buddy_handler(ui, subtype, in);
397 case CUI_TYPE_MESSAGE
:
398 message_handler(ui
, subtype
, in
);
402 chat_handler(ui, subtype, in);
405 case CUI_TYPE_REMOTE
:
406 remote_handler(ui
, subtype
, in
, len
);
409 debug_printf("unhandled type %d\n", type
);
418 static gboolean
socket_readable(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
420 struct sockaddr_un saddr
;
421 gint len
= sizeof(saddr
);
426 if ((fd
= accept(UI_fd
, (struct sockaddr
*)&saddr
, &len
)) == -1)
429 ui
= g_new0(struct UI
, 1);
430 uis
= g_slist_append(uis
, ui
);
432 ui
->channel
= g_io_channel_unix_new(fd
);
433 ui
->inpa
= g_io_add_watch(ui
->channel
, G_IO_IN
| G_IO_HUP
| G_IO_ERR
, UI_readable
, ui
);
434 g_io_channel_unref(ui
->channel
);
436 debug_printf("got one\n");
440 static gint
open_socket()
442 struct sockaddr_un saddr
;
445 while (gaim_session_exists(gaim_session
))
448 debug_printf("session: %d\n", gaim_session
);
450 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) != -1) {
451 mode_t m
= umask(0177);
452 saddr
.sun_family
= AF_UNIX
;
454 g_snprintf(saddr
.sun_path
, sizeof(saddr
.sun_path
), "%s" G_DIR_SEPARATOR_S
"gaim_%s.%d",
455 g_get_tmp_dir(), g_get_user_name(), gaim_session
);
456 if (bind(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) != -1)
459 g_log(NULL
, G_LOG_LEVEL_CRITICAL
,
460 "Failed to assign %s to a socket (Error: %s)",
461 saddr
.sun_path
, strerror(errno
));
466 g_log(NULL
, G_LOG_LEVEL_CRITICAL
, "Unable to open socket: %s", strerror(errno
));
480 UI_fd
= open_socket();
484 channel
= g_io_channel_unix_new(UI_fd
);
485 g_io_add_watch(channel
, G_IO_IN
, socket_readable
, NULL
);
486 g_io_channel_unref(channel
);
490 loop = g_main_new(TRUE);
501 /* don't save prefs after plugins are gone... */
506 sprintf(buf
, "%s" G_DIR_SEPARATOR_S
"gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), gaim_session
);
508 debug_printf("Removed core\n");