~ubuntu-branches/ubuntu/hardy/irssi/hardy-updates

« back to all changes in this revision

Viewing changes to src/core/session.c

  • Committer: Bazaar Package Importer
  • Author(s): David Pashley
  • Date: 2005-12-10 21:25:51 UTC
  • Revision ID: james.westby@ubuntu.com-20051210212551-5qwm108g7inyu2f2
Tags: upstream-0.8.10
ImportĀ upstreamĀ versionĀ 0.8.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 session.c : irssi
 
3
 
 
4
    Copyright (C) 2001 Timo Sirainen
 
5
 
 
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.
 
10
 
 
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.
 
15
 
 
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
 
19
*/
 
20
 
 
21
#include "module.h"
 
22
#include "signals.h"
 
23
#include "commands.h"
 
24
#include "args.h"
 
25
#include "net-sendbuffer.h"
 
26
#include "pidwait.h"
 
27
#include "lib-config/iconfig.h"
 
28
 
 
29
#include "chat-protocols.h"
 
30
#include "servers.h"
 
31
#include "servers-setup.h"
 
32
#include "channels.h"
 
33
#include "nicklist.h"
 
34
 
 
35
static char *session_file;
 
36
char *irssi_binary = NULL;
 
37
 
 
38
static char **session_args;
 
39
 
 
40
void session_set_binary(const char *path)
 
41
{
 
42
        const char *envpath;
 
43
        char **paths, **tmp;
 
44
        char *str;
 
45
 
 
46
        g_free_and_null(irssi_binary);
 
47
 
 
48
        if (g_path_is_absolute(path)) {
 
49
                /* full path - easy */
 
50
                irssi_binary = g_strdup(path);
 
51
                return;
 
52
        }
 
53
 
 
54
        if (strchr(path, G_DIR_SEPARATOR) != NULL) {
 
55
                /* relative path */
 
56
                str = g_get_current_dir();
 
57
                irssi_binary = g_strconcat(str, G_DIR_SEPARATOR_S, path, NULL);
 
58
                g_free(str);
 
59
                return;
 
60
        }
 
61
 
 
62
        /* we'll need to find it from path. */
 
63
        envpath = g_getenv("PATH");
 
64
        if (envpath == NULL) return;
 
65
 
 
66
        paths = g_strsplit(envpath, ":", -1);
 
67
        for (tmp = paths; *tmp != NULL; tmp++) {
 
68
                str = g_strconcat(*tmp, G_DIR_SEPARATOR_S, path, NULL);
 
69
                if (access(str, X_OK) == 0) {
 
70
                        irssi_binary = str;
 
71
                        break;
 
72
                }
 
73
                g_free(str);
 
74
        }
 
75
        g_strfreev(paths);
 
76
}
 
77
 
 
78
void session_upgrade(void)
 
79
{
 
80
        if (session_args == NULL)
 
81
                return;
 
82
 
 
83
        execvp(session_args[0], session_args);
 
84
        fprintf(stderr, "exec failed: %s: %s\n",
 
85
                session_args[0], g_strerror(errno));
 
86
}
 
87
 
 
88
/* SYNTAX: UPGRADE [<irssi binary path>] */
 
89
static void cmd_upgrade(const char *data)
 
90
{
 
91
        CONFIG_REC *session;
 
92
        char *session_file, *str;
 
93
 
 
94
        if (*data == '\0')
 
95
                data = irssi_binary;
 
96
        if (data == NULL)
 
97
                cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
 
98
 
 
99
        /* save the session */
 
100
        session_file = g_strdup_printf("%s/session", get_irssi_dir());
 
101
        session = config_open(session_file, 0600);
 
102
        unlink(session_file);
 
103
 
 
104
        signal_emit("session save", 1, session);
 
105
        config_write(session, NULL, -1);
 
106
        config_close(session);
 
107
 
 
108
        /* data may contain some other program as well, like
 
109
           /UPGRADE /usr/bin/screen irssi */
 
110
        str = g_strdup_printf("%s --noconnect --session=%s --home=%s --config=%s",
 
111
                              data, session_file, get_irssi_dir(), get_irssi_config());
 
112
        session_args = g_strsplit(str, " ", -1);
 
113
        g_free(str);
 
114
 
 
115
        signal_emit("gui exit", 0);
 
116
}
 
117
 
 
118
static void session_save_nick(CHANNEL_REC *channel, NICK_REC *nick,
 
119
                              CONFIG_REC *config, CONFIG_NODE *node)
 
120
{
 
121
        static char other[2];
 
122
        node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
 
123
 
 
124
        config_node_set_str(config, node, "nick", nick->nick);
 
125
        config_node_set_bool(config, node, "op", nick->op);
 
126
        config_node_set_bool(config, node, "halfop", nick->halfop);
 
127
        config_node_set_bool(config, node, "voice", nick->voice);
 
128
        
 
129
        other[0] = nick->other;
 
130
        other[1] = '\0';
 
131
        config_node_set_str(config, node, "other", other);
 
132
 
 
133
        signal_emit("session save nick", 4, channel, nick, config, node);
 
134
}
 
135
 
 
136
static void session_save_channel_nicks(CHANNEL_REC *channel, CONFIG_REC *config,
 
137
                                       CONFIG_NODE *node)
 
138
{
 
139
        GSList *tmp, *nicks;
 
140
 
 
141
        node = config_node_section(node, "nicks", NODE_TYPE_LIST);
 
142
        nicks = nicklist_getnicks(channel);
 
143
        for (tmp = nicks; tmp != NULL; tmp = tmp->next)
 
144
                session_save_nick(channel, tmp->data, config, node);
 
145
        g_slist_free(nicks);
 
146
}
 
147
 
 
148
static void session_save_channel(CHANNEL_REC *channel, CONFIG_REC *config,
 
149
                                 CONFIG_NODE *node)
 
150
{
 
151
        node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
 
152
 
 
153
        config_node_set_str(config, node, "name", channel->name);
 
154
        config_node_set_str(config, node, "visible_name", channel->visible_name);
 
155
        config_node_set_str(config, node, "topic", channel->topic);
 
156
        config_node_set_str(config, node, "topic_by", channel->topic_by);
 
157
        config_node_set_int(config, node, "topic_time", channel->topic_time);
 
158
        config_node_set_str(config, node, "key", channel->key);
 
159
 
 
160
        signal_emit("session save channel", 3, channel, config, node);
 
161
}
 
162
 
 
163
static void session_save_server_channels(SERVER_REC *server,
 
164
                                         CONFIG_REC *config,
 
165
                                         CONFIG_NODE *node)
 
166
{
 
167
        GSList *tmp;
 
168
 
 
169
        /* save channels */
 
170
        node = config_node_section(node, "channels", NODE_TYPE_LIST);
 
171
        for (tmp = server->channels; tmp != NULL; tmp = tmp->next)
 
172
                session_save_channel(tmp->data, config, node);
 
173
}
 
174
 
 
175
static void session_save_server(SERVER_REC *server, CONFIG_REC *config,
 
176
                                CONFIG_NODE *node)
 
177
{
 
178
        int handle;
 
179
 
 
180
        node = config_node_section(node, NULL, NODE_TYPE_BLOCK);
 
181
 
 
182
        config_node_set_str(config, node, "chat_type",
 
183
                            chat_protocol_find_id(server->chat_type)->name);
 
184
        config_node_set_str(config, node, "address", server->connrec->address);
 
185
        config_node_set_int(config, node, "port", server->connrec->port);
 
186
        config_node_set_str(config, node, "chatnet", server->connrec->chatnet);
 
187
        config_node_set_str(config, node, "password", server->connrec->password);
 
188
        config_node_set_str(config, node, "nick", server->nick);
 
189
        config_node_set_str(config, node, "version", server->version);
 
190
 
 
191
        config_node_set_bool(config, node, "use_ssl", server->connrec->use_ssl);
 
192
        config_node_set_str(config, node, "ssl_cert", server->connrec->ssl_cert);
 
193
        config_node_set_str(config, node, "ssl_pkey", server->connrec->ssl_pkey);
 
194
        config_node_set_bool(config, node, "ssl_verify", server->connrec->ssl_verify);
 
195
        config_node_set_str(config, node, "ssl_cafile", server->connrec->ssl_cafile);
 
196
        config_node_set_str(config, node, "ssl_capath", server->connrec->ssl_capath);
 
197
 
 
198
        handle = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
 
199
        config_node_set_int(config, node, "handle", handle);
 
200
 
 
201
        signal_emit("session save server", 3, server, config, node);
 
202
 
 
203
        /* fake the server disconnection */
 
204
        g_io_channel_unref(net_sendbuffer_handle(server->handle));
 
205
        net_sendbuffer_destroy(server->handle, FALSE);
 
206
        server->handle = NULL;
 
207
 
 
208
        server->connection_lost = TRUE;
 
209
        server->no_reconnect = TRUE;
 
210
        server_disconnect(server);
 
211
}
 
212
 
 
213
static void session_restore_channel_nicks(CHANNEL_REC *channel,
 
214
                                          CONFIG_NODE *node)
 
215
{
 
216
        GSList *tmp;
 
217
 
 
218
        /* restore nicks */
 
219
        node = config_node_section(node, "nicks", -1);
 
220
        if (node != NULL && node->type == NODE_TYPE_LIST) {
 
221
                tmp = config_node_first(node->value);
 
222
                for (; tmp != NULL; tmp = config_node_next(tmp)) {
 
223
                        signal_emit("session restore nick", 2,
 
224
                                    channel, tmp->data);
 
225
                }
 
226
        }
 
227
}
 
228
 
 
229
static void session_restore_channel(SERVER_REC *server, CONFIG_NODE *node)
 
230
{
 
231
        CHANNEL_REC *channel;
 
232
        const char *name, *visible_name;
 
233
 
 
234
        name = config_node_get_str(node, "name", NULL);
 
235
        if (name == NULL)
 
236
                return;
 
237
 
 
238
        visible_name = config_node_get_str(node, "visible_name", NULL);
 
239
        channel = CHAT_PROTOCOL(server)->channel_create(server, name, visible_name, TRUE);
 
240
        channel->topic = g_strdup(config_node_get_str(node, "topic", NULL));
 
241
        channel->topic_by = g_strdup(config_node_get_str(node, "topic_by", NULL));
 
242
        channel->topic_time = config_node_get_int(node, "topic_time", 0);
 
243
        channel->key = g_strdup(config_node_get_str(node, "key", NULL));
 
244
        channel->session_rejoin = TRUE;
 
245
 
 
246
        signal_emit("session restore channel", 2, channel, node);
 
247
}
 
248
 
 
249
static void session_restore_server_channels(SERVER_REC *server,
 
250
                                            CONFIG_NODE *node)
 
251
{
 
252
        GSList *tmp;
 
253
 
 
254
        /* restore channels */
 
255
        node = config_node_section(node, "channels", -1);
 
256
        if (node != NULL && node->type == NODE_TYPE_LIST) {
 
257
                tmp = config_node_first(node->value);
 
258
                for (; tmp != NULL; tmp = config_node_next(tmp))
 
259
                        session_restore_channel(server, tmp->data);
 
260
        }
 
261
}
 
262
 
 
263
static void session_restore_server(CONFIG_NODE *node)
 
264
{
 
265
        CHAT_PROTOCOL_REC *proto;
 
266
        SERVER_CONNECT_REC *conn;
 
267
        SERVER_REC *server;
 
268
        const char *chat_type, *address, *chatnet, *password, *nick;
 
269
        int port, handle;
 
270
 
 
271
        chat_type = config_node_get_str(node, "chat_type", NULL);
 
272
        address = config_node_get_str(node, "address", NULL);
 
273
        port = config_node_get_int(node, "port", 0);
 
274
        chatnet = config_node_get_str(node, "chatnet", NULL);
 
275
        password = config_node_get_str(node, "password", NULL);
 
276
        nick = config_node_get_str(node, "nick", NULL);
 
277
        handle = config_node_get_int(node, "handle", -1);
 
278
 
 
279
        if (chat_type == NULL || address == NULL || nick == NULL || handle < 0)
 
280
                return;
 
281
 
 
282
        proto = chat_protocol_find(chat_type);
 
283
        if (proto == NULL || proto->not_initialized) {
 
284
                if (handle < 0) close(handle);
 
285
                return;
 
286
        }
 
287
 
 
288
        conn = server_create_conn(proto->id, address, port,
 
289
                                  chatnet, password, nick);
 
290
        if (conn != NULL) {
 
291
                conn->reconnection = TRUE;
 
292
                conn->connect_handle = g_io_channel_unix_new(handle);
 
293
 
 
294
                server = proto->server_init_connect(conn);
 
295
                server->version = g_strdup(config_node_get_str(node, "version", NULL));         
 
296
                server->session_reconnect = TRUE;
 
297
                signal_emit("session restore server", 2, server, node);
 
298
 
 
299
                proto->server_connect(server);
 
300
        }
 
301
}
 
302
 
 
303
static void sig_session_save(CONFIG_REC *config)
 
304
{
 
305
        CONFIG_NODE *node;
 
306
        GSList *tmp;
 
307
        GString *str;
 
308
 
 
309
        /* save servers */
 
310
        node = config_node_traverse(config, "(servers", TRUE);
 
311
        while (servers != NULL)
 
312
                session_save_server(servers->data, config, node);
 
313
 
 
314
        /* save pids */
 
315
        str = g_string_new(NULL);
 
316
        for (tmp = pidwait_get_pids(); tmp != NULL; tmp = tmp->next)
 
317
                g_string_sprintfa(str, "%d ", GPOINTER_TO_INT(tmp->data));
 
318
        config_node_set_str(config, config->mainnode, "pids", str->str);
 
319
        g_string_free(str, TRUE);
 
320
}
 
321
 
 
322
static void sig_session_restore(CONFIG_REC *config)
 
323
{
 
324
        CONFIG_NODE *node;
 
325
        GSList *tmp;
 
326
        char **pids, **pid;
 
327
 
 
328
        /* restore servers */
 
329
        node = config_node_traverse(config, "(servers", FALSE);
 
330
        if (node != NULL) {
 
331
                tmp = config_node_first(node->value);
 
332
                for (; tmp != NULL; tmp = config_node_next(tmp))
 
333
                        session_restore_server(tmp->data);
 
334
        }
 
335
 
 
336
        /* restore pids (so we don't leave zombies) */
 
337
        pids = g_strsplit(config_node_get_str(config->mainnode, "pids", ""), " ", -1);
 
338
        for (pid = pids; *pid != NULL; pid++)
 
339
                pidwait_add(atoi(*pid));
 
340
        g_strfreev(pids);
 
341
}
 
342
 
 
343
static void sig_init_finished(void)
 
344
{
 
345
        CONFIG_REC *session;
 
346
 
 
347
        if (session_file == NULL)
 
348
                return;
 
349
 
 
350
        session = config_open(session_file, -1);
 
351
        if (session == NULL)
 
352
                return;
 
353
 
 
354
        config_parse(session);
 
355
        signal_emit("session restore", 1, session);
 
356
        config_close(session);
 
357
 
 
358
        unlink(session_file);
 
359
        session_file = NULL;
 
360
}
 
361
 
 
362
void session_init(void)
 
363
{
 
364
        static struct poptOption options[] = {
 
365
                { "session", 0, POPT_ARG_STRING, &session_file, 0, "Used by /UPGRADE command", "PATH" },
 
366
                { NULL, '\0', 0, NULL }
 
367
        };
 
368
 
 
369
        session_file = NULL;
 
370
        args_register(options);
 
371
 
 
372
        command_bind("upgrade", NULL, (SIGNAL_FUNC) cmd_upgrade);
 
373
 
 
374
        signal_add("session save", (SIGNAL_FUNC) sig_session_save);
 
375
        signal_add("session restore", (SIGNAL_FUNC) sig_session_restore);
 
376
        signal_add("session save server", (SIGNAL_FUNC) session_save_server_channels);
 
377
        signal_add("session restore server", (SIGNAL_FUNC) session_restore_server_channels);
 
378
        signal_add("session save channel", (SIGNAL_FUNC) session_save_channel_nicks);
 
379
        signal_add("session restore channel", (SIGNAL_FUNC) session_restore_channel_nicks);
 
380
        signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
 
381
}
 
382
 
 
383
void session_deinit(void)
 
384
{
 
385
        g_free_not_null(irssi_binary);
 
386
 
 
387
        command_unbind("upgrade", (SIGNAL_FUNC) cmd_upgrade);
 
388
 
 
389
        signal_remove("session save", (SIGNAL_FUNC) sig_session_save);
 
390
        signal_remove("session restore", (SIGNAL_FUNC) sig_session_restore);
 
391
        signal_remove("session save server", (SIGNAL_FUNC) session_save_server_channels);
 
392
        signal_remove("session restore server", (SIGNAL_FUNC) session_restore_server_channels);
 
393
        signal_remove("session save channel", (SIGNAL_FUNC) session_save_channel_nicks);
 
394
        signal_remove("session restore channel", (SIGNAL_FUNC) session_restore_channel_nicks);
 
395
        signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
 
396
}