comparison src/core.c @ 5859:022786c7ab53

[gaim-migrate @ 6290] CUI is gone, long live gaim-remote! The old CUI functionality, which was for remote-controlling gaim, is now a Core Plugin, so any future UI (including the current, normal gaim gtk UI) can be remote-controlled. Applications will soon be able to link against the library and header files and provide their own remote-control of gaim, but why bother? :) If you use gaim-remote, make sure to load the new plugin. It won't auto-load. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Sat, 14 Jun 2003 06:06:40 +0000
parents 86456ec3ca25
children 059d95c67cda
comparison
equal deleted inserted replaced
5858:96e5b32e75ad 5859:022786c7ab53
1 /* 1 /*
2 * gaim 2 * gaim
3 * 3 *
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
5 * 4 *
6 * This program is free software; you can redistribute it and/or modify 5 * 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 6 * 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 7 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version. 8 * (at your option) any later version.
26 #include <glib.h> 25 #include <glib.h>
27 #include <stdio.h> 26 #include <stdio.h>
28 #include <stdlib.h> 27 #include <stdlib.h>
29 #include <sys/types.h> 28 #include <sys/types.h>
30 29
31 #ifdef _WIN32
32 #include <winsock.h>
33 #include <io.h>
34 #else
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 #include <unistd.h>
38 #endif
39 30
40 #include <sys/stat.h>
41 #include <errno.h>
42 #include <signal.h>
43 #include <getopt.h>
44 #include <stdarg.h>
45 #include <string.h>
46
47 #include "gaim.h"
48 #include "gaim-socket.h"
49
50 #ifdef _WIN32
51 #include "win32dep.h"
52 #endif
53
54 #ifndef _WIN32
55 static gint UI_fd = -1;
56 #endif
57 int gaim_session = 0;
58 GSList *uis = NULL;
59
60 static guchar *UI_build(guint32 *len, guchar type, guchar subtype, va_list args)
61 {
62 guchar *buffer;
63 guint32 pos;
64 int size;
65 void *data;
66
67 *len = sizeof(guchar) * 2 + 4;
68 buffer = g_malloc(*len);
69 pos = 0;
70
71 memcpy(buffer + pos, &type, sizeof(type)); pos += sizeof(type);
72 memcpy(buffer + pos, &subtype, sizeof(subtype)); pos += sizeof(subtype);
73
74 /* we come back and do size last */
75 pos += 4;
76
77 size = va_arg(args, int);
78 while (size != -1) {
79 *len += size;
80 buffer = g_realloc(buffer, *len);
81
82 data = va_arg(args, void *);
83 memcpy(buffer + pos, data, size);
84 pos += size;
85
86 size = va_arg(args, int);
87 }
88
89 pos -= sizeof(guchar) * 2 + 4;
90
91 /* now we do size */
92 memcpy(buffer + sizeof(guchar) * 2, &pos, 4);
93
94 return buffer;
95 }
96
97 gint UI_write(struct UI *ui, guchar *data, gint len)
98 {
99 GError *error = NULL;
100 gint sent;
101 /* we'll let the write silently fail because the read will pick it up as dead */
102 g_io_channel_write_chars(ui->channel, data, len, &sent, &error);
103 if (error)
104 g_error_free(error);
105 return sent;
106 }
107
108 void UI_build_write(struct UI *ui, guchar type, guchar subtype, ...)
109 {
110 va_list ap;
111 gchar *data;
112 guint32 len;
113
114 va_start(ap, subtype);
115 data = UI_build(&len, type, subtype, ap);
116 va_end(ap);
117
118 UI_write(ui, data, len);
119
120 g_free(data);
121 }
122
123 void UI_broadcast(guchar *data, gint len)
124 {
125 GSList *u = uis;
126 while (u) {
127 struct UI *ui = u->data;
128 UI_write(ui, data, len);
129 u = u->next;
130 }
131 }
132
133 void UI_build_broadcast(guchar type, guchar subtype, ...)
134 {
135 va_list ap;
136 gchar *data;
137 guint32 len;
138
139 if (!uis)
140 return;
141
142 va_start(ap, subtype);
143 data = UI_build(&len, type, subtype, ap);
144 va_end(ap);
145
146 UI_broadcast(data, len);
147
148 g_free(data);
149 }
150
151 #ifndef _WIN32
152 static void meta_handler(struct UI *ui, guchar subtype, guchar *data)
153 {
154 struct gaim_cui_packet *p;
155 GError *error = NULL;
156 switch (subtype) {
157 case CUI_META_LIST:
158 break;
159 case CUI_META_QUIT:
160 while (uis) {
161 ui = uis->data;
162 uis = g_slist_remove(uis, ui);
163 g_io_channel_shutdown(ui->channel, TRUE, &error);
164 g_source_remove(ui->inpa);
165 g_free(ui);
166 }
167 do_quit();
168 break;
169 case CUI_META_DETACH:
170 uis = g_slist_remove(uis, ui);
171 g_io_channel_shutdown(ui->channel, TRUE, &error);
172 g_source_remove(ui->inpa);
173 g_free(ui);
174 break;
175 case CUI_META_PING:
176 p = cui_packet_new(CUI_TYPE_META, CUI_META_ACK);
177 cui_send_packet(g_io_channel_unix_get_fd(ui->channel), p);
178 cui_packet_free(p);
179 break;
180 default:
181 gaim_debug(GAIM_DEBUG_WARNING, "cui",
182 "Unhandled meta subtype %d\n", subtype);
183 break;
184 }
185
186 if(error)
187 g_error_free(error);
188 }
189
190 static void plugin_handler(struct UI *ui, guchar subtype, guchar *data)
191 {
192 #ifdef GAIM_PLUGINS
193 guint id;
194 GaimPlugin *p;
195
196 switch (subtype) {
197 /*
198 case CUI_PLUGIN_LIST:
199 break;
200 */
201 case CUI_PLUGIN_LOAD:
202 gaim_plugin_load(gaim_plugin_probe(data));
203 break;
204 case CUI_PLUGIN_UNLOAD:
205 memcpy(&id, data, sizeof(id));
206 p = g_list_nth_data(gaim_plugins_get_loaded(), id);
207 if (p) {
208 gaim_plugin_unload(p);
209 }
210 break;
211 default:
212 gaim_debug(GAIM_DEBUG_WARNING, "cui",
213 "Unhandled plugin subtype %d\n", subtype);
214 break;
215 }
216 #endif
217 }
218
219 static void user_handler(struct UI *ui, guchar subtype, guchar *data)
220 {
221 guint id;
222 GaimAccount *account;
223
224 switch (subtype) {
225 /*
226 case CUI_USER_LIST:
227 break;
228 case CUI_USER_ADD:
229 break;
230 case CUI_USER_REMOVE:
231 break;
232 case CUI_USER_MODIFY:
233 break;
234 */
235 case CUI_USER_SIGNON:
236 if (!data)
237 return;
238 memcpy(&id, data, sizeof(id));
239 account = g_list_nth_data(gaim_accounts_get_all(), id);
240 if (account)
241 serv_login(account);
242 /* don't need to do anything here because the UI will get updates from other handlers */
243 break;
244 default:
245 gaim_debug(GAIM_DEBUG_WARNING, "cui",
246 "Unhandled user subtype %d\n", subtype);
247 break;
248 }
249 }
250
251 static void message_handler(struct UI *ui, guchar subtype, guchar *data)
252 {
253 switch (subtype) {
254 case CUI_MESSAGE_LIST:
255 break;
256 case CUI_MESSAGE_SEND:
257 if (!data)
258 return;
259 {
260 guint id;
261 GaimConnection *gc;
262 guint len;
263 char *who, *msg;
264 gint flags;
265 int pos = 0;
266
267 memcpy(&id, data + pos, sizeof(id));
268 pos += sizeof(id);
269 gc = g_list_nth_data(gaim_connections_get_all(), id);
270 if (!gc)
271 return;
272
273 memcpy(&len, data + pos, sizeof(len));
274 pos += sizeof(len);
275 who = g_strndup(data + pos, len + 1);
276 pos += len;
277
278 memcpy(&len, data + pos, sizeof(len));
279 pos += sizeof(len);
280 msg = g_strndup(data + pos, len + 1);
281 pos += len;
282
283 memcpy(&flags, data + pos, sizeof(flags));
284 serv_send_im(gc, who, msg, -1, flags);
285
286 g_free(who);
287 g_free(msg);
288 }
289 break;
290 case CUI_MESSAGE_RECV:
291 break;
292 default:
293 gaim_debug(GAIM_DEBUG_WARNING, "cui",
294 "Unhandled message subtype %d\n", subtype);
295 break;
296 }
297 }
298
299 static gint gaim_recv(GIOChannel *source, guchar *buf, gint len)
300 {
301 gint total = 0;
302 gint cur;
303
304 GError *error = NULL;
305
306 while (total < len) {
307 if (g_io_channel_read_chars(source, buf + total, len - total, &cur, &error) != G_IO_STATUS_NORMAL) {
308 if (error)
309 g_error_free(error);
310 return -1;
311 }
312 if (cur == 0)
313 return total;
314 total += cur;
315 }
316
317 return total;
318 }
319
320 static void remote_handler(struct UI *ui, guchar subtype, guchar *data, int len)
321 {
322 const char *resp;
323 char *send;
324 switch (subtype) {
325 case CUI_REMOTE_CONNECTIONS:
326 break;
327 case CUI_REMOTE_URI:
328 send = g_malloc(len + 1);
329 memcpy(send, data, len);
330 send[len] = 0;
331 resp = handle_uri(send);
332 g_free(send);
333 /* report error */
334 break;
335 default:
336 gaim_debug(GAIM_DEBUG_WARNING, "cui",
337 "Unhandled remote subtype %d\n", subtype);
338 break;
339 }
340 }
341
342 static gboolean UI_readable(GIOChannel *source, GIOCondition cond, gpointer data)
343 {
344 struct UI *ui = data;
345
346 guchar type;
347 guchar subtype;
348 guint32 len;
349
350 GError *error = NULL;
351
352 guchar *in;
353
354 /* no byte order worries! this'll change if we go to TCP */
355 if (gaim_recv(source, &type, sizeof(type)) != sizeof(type)) {
356 gaim_debug(GAIM_DEBUG_ERROR, "cui", "UI has abandoned us!\n");
357 uis = g_slist_remove(uis, ui);
358 g_io_channel_shutdown(ui->channel, TRUE, &error);
359 if(error) {
360 g_error_free(error);
361 error = NULL;
362 }
363 g_source_remove(ui->inpa);
364 g_free(ui);
365 return FALSE;
366 }
367
368 if (gaim_recv(source, &subtype, sizeof(subtype)) != sizeof(subtype)) {
369 gaim_debug(GAIM_DEBUG_ERROR, "cui", "UI has abandoned us!\n");
370 uis = g_slist_remove(uis, ui);
371 g_io_channel_shutdown(ui->channel, TRUE, &error);
372 if(error) {
373 g_error_free(error);
374 error = NULL;
375 }
376 g_source_remove(ui->inpa);
377 g_free(ui);
378 return FALSE;
379 }
380
381 if (gaim_recv(source, (guchar *)&len, sizeof(len)) != sizeof(len)) {
382 gaim_debug(GAIM_DEBUG_ERROR, "cui", "UI has abandoned us!\n");
383 uis = g_slist_remove(uis, ui);
384 g_io_channel_shutdown(ui->channel, TRUE, &error);
385 if(error) {
386 g_error_free(error);
387 error = NULL;
388 }
389 g_source_remove(ui->inpa);
390 g_free(ui);
391 return FALSE;
392 }
393
394 if (len) {
395 in = g_new0(guchar, len);
396 if (gaim_recv(source, in, len) != len) {
397 gaim_debug(GAIM_DEBUG_ERROR, "cui", "UI has abandoned us!\n");
398 uis = g_slist_remove(uis, ui);
399 g_io_channel_shutdown(ui->channel, TRUE, &error);
400 if(error) {
401 g_error_free(error);
402 error = NULL;
403 }
404 g_source_remove(ui->inpa);
405 g_free(ui);
406 return FALSE;
407 }
408 } else
409 in = NULL;
410
411 switch (type) {
412 case CUI_TYPE_META:
413 meta_handler(ui, subtype, in);
414 break;
415 case CUI_TYPE_PLUGIN:
416 plugin_handler(ui, subtype, in);
417 break;
418 case CUI_TYPE_USER:
419 user_handler(ui, subtype, in);
420 break;
421 /*
422 case CUI_TYPE_CONN:
423 conn_handler(ui, subtype, in);
424 break;
425 case CUI_TYPE_BUDDY:
426 buddy_handler(ui, subtype, in);
427 break;
428 */
429 case CUI_TYPE_MESSAGE:
430 message_handler(ui, subtype, in);
431 break;
432 /*
433 case CUI_TYPE_CHAT:
434 chat_handler(ui, subtype, in);
435 break;
436 */
437 case CUI_TYPE_REMOTE:
438 remote_handler(ui, subtype, in, len);
439 break;
440 default:
441 gaim_debug(GAIM_DEBUG_WARNING, "cui",
442 "Unhandled type %d\n", type);
443 break;
444 }
445
446 if (in)
447 g_free(in);
448 return TRUE;
449 }
450
451 static gboolean socket_readable(GIOChannel *source, GIOCondition cond, gpointer data)
452 {
453 struct sockaddr_un saddr;
454 gint len = sizeof(saddr);
455 gint fd;
456
457 struct UI *ui;
458
459 if ((fd = accept(UI_fd, (struct sockaddr *)&saddr, &len)) == -1)
460 return FALSE;
461
462 ui = g_new0(struct UI, 1);
463 uis = g_slist_append(uis, ui);
464
465 ui->channel = g_io_channel_unix_new(fd);
466 ui->inpa = g_io_add_watch(ui->channel, G_IO_IN | G_IO_HUP | G_IO_ERR, UI_readable, ui);
467 g_io_channel_unref(ui->channel);
468
469 gaim_debug(GAIM_DEBUG_MISC, "cui", "Got one\n");
470 return TRUE;
471 }
472
473 static gint open_socket()
474 {
475 struct sockaddr_un saddr;
476 gint fd;
477
478 while (gaim_session_exists(gaim_session))
479 gaim_session++;
480
481 gaim_debug(GAIM_DEBUG_MISC, "cui", "Session: %d\n", gaim_session);
482
483 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) {
484 mode_t m = umask(0177);
485 saddr.sun_family = AF_UNIX;
486
487 g_snprintf(saddr.sun_path, sizeof(saddr.sun_path), "%s" G_DIR_SEPARATOR_S "gaim_%s.%d",
488 g_get_tmp_dir(), g_get_user_name(), gaim_session);
489 if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) != -1)
490 listen(fd, 100);
491 else {
492 g_log(NULL, G_LOG_LEVEL_CRITICAL,
493 "Failed to assign %s to a socket (Error: %s)",
494 saddr.sun_path, strerror(errno));
495 return -1;
496 }
497 umask(m);
498 } else
499 g_log(NULL, G_LOG_LEVEL_CRITICAL, "Unable to open socket: %s", strerror(errno));
500 return fd;
501 }
502 #endif /*! _WIN32*/
503
504 int core_main()
505 {
506 /*
507 GMainLoop *loop;
508 */
509 #ifndef _WIN32
510 GIOChannel *channel;
511 #endif
512
513 gaim_set_blist(gaim_blist_new());
514 gaim_blist_load();
515
516 #ifndef _WIN32
517
518 UI_fd = open_socket();
519 if (UI_fd < 0)
520 return 1;
521
522 channel = g_io_channel_unix_new(UI_fd);
523 g_io_add_watch(channel, G_IO_IN, socket_readable, NULL);
524 g_io_channel_unref(channel);
525 #endif
526
527 /*
528 loop = g_main_new(TRUE);
529 g_main_run(loop);
530 */
531
532 return 0;
533 }
534
535 void core_quit()
536 {
537 /* don't save prefs after plugins are gone... */
538 #ifndef _WIN32
539 char buf[1024];
540 close(UI_fd);
541 snprintf(buf, 1024, "%s" G_DIR_SEPARATOR_S "gaim_%s.%d",
542 g_get_tmp_dir(), g_get_user_name(), gaim_session);
543
544 unlink(buf);
545
546 gaim_debug(GAIM_DEBUG_MISC, "core", "Removed core\n");
547 #endif
548 }