/* * Copyright (c) 2003-2006 by FlashCode * See README for License detail, AUTHORS for developers list. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* session.c: save/restore session data */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #ifdef HAVE_GNUTLS #include #endif #include "weechat.h" #include "session.h" #include "log.h" #include "../irc/irc.h" #include "../gui/gui.h" /* current server/channel (used when loading session) */ t_irc_server *session_current_server = NULL; t_irc_channel *session_current_channel = NULL; t_gui_buffer *session_current_buffer = NULL; long session_last_read_pos = 0; int session_last_read_length = 0; /* * session_write_id: write object ID to file */ int session_write_id (FILE *file, int id) { return (fwrite ((void *)(&id), sizeof (int), 1, file) > 0); } /* * session_write_int: write an integer to file */ int session_write_int (FILE *file, int id, int value) { char type; if (id >= 0) { if (!session_write_id (file, id)) return 0; } type = SESSION_TYPE_INT; if (fwrite ((void *)(&type), sizeof (char), 1, file) == 0) return 0; return (fwrite ((void *)(&value), sizeof (int), 1, file) > 0); } /* * session_write_str: write a string to file */ int session_write_str (FILE *file, int id, char *string) { char type; int length; if (id >= 0) { if (!session_write_id (file, id)) return 0; } type = SESSION_TYPE_STR; if (fwrite ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (string && string[0]) { length = strlen (string); if (fwrite ((void *)(&length), sizeof (int), 1, file) == 0) return 0; return (fwrite ((void *)string, length, 1, file) > 0); } else { length = 0; return (fwrite ((void *)(&length), sizeof (int), 1, file) > 0); } } /* * session_write_buf: write a buffer to file */ int session_write_buf (FILE *file, int id, void *buffer, int size) { char type; if (id >= 0) { if (!session_write_id (file, id)) return 0; } type = SESSION_TYPE_BUF; if (fwrite ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (fwrite ((void *)(&size), sizeof (int), 1, file) == 0) return 0; return (fwrite (buffer, size, 1, file) > 0); } /* * session_save_nick: save a nick into session file */ int session_save_nick (FILE *file, t_irc_nick *nick) { int rc; rc = 1; rc = rc && (session_write_id (file, SESSION_OBJ_NICK)); rc = rc && (session_write_str (file, SESSION_NICK_NICK, nick->nick)); rc = rc && (session_write_int (file, SESSION_NICK_FLAGS, nick->flags)); rc = rc && (session_write_int (file, SESSION_NICK_COLOR, nick->color)); rc = rc && (session_write_str (file, SESSION_NICK_HOST, nick->host)); rc = rc && (session_write_id (file, SESSION_NICK_END)); return rc; } /* * session_save_channel: save a channel into session file */ int session_save_channel (FILE *file, t_irc_channel *channel) { int rc; t_irc_nick *ptr_nick; rc = 1; rc = rc && (session_write_id (file, SESSION_OBJ_CHANNEL)); rc = rc && (session_write_int (file, SESSION_CHAN_TYPE, channel->type)); rc = rc && (session_write_str (file, SESSION_CHAN_NAME, channel->name)); rc = rc && (session_write_str (file, SESSION_CHAN_TOPIC, channel->topic)); rc = rc && (session_write_str (file, SESSION_CHAN_MODES, channel->modes)); rc = rc && (session_write_int (file, SESSION_CHAN_LIMIT, channel->limit)); rc = rc && (session_write_str (file, SESSION_CHAN_KEY, channel->key)); rc = rc && (session_write_int (file, SESSION_CHAN_NICKS_COUNT, channel->nicks_count)); rc = rc && (session_write_int (file, SESSION_CHAN_CHECKING_AWAY, channel->checking_away)); rc = rc && (session_write_str (file, SESSION_CHAN_AWAY_MESSAGE, channel->away_message)); rc = rc && (session_write_int (file, SESSION_CHAN_CYCLE, channel->cycle)); rc = rc && (session_write_int (file, SESSION_CHAN_CLOSE, channel->close)); rc = rc && (session_write_id (file, SESSION_CHAN_END)); if (!rc) return 0; for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick) { if (!session_save_nick (file, ptr_nick)) return 0; } return 1; } /* * session_save_servers: save all servers into session file */ int session_save_servers (FILE *file) { int rc; #ifdef HAVE_GNUTLS void *session_data; size_t session_size; #endif t_irc_server *ptr_server; t_irc_channel *ptr_channel; rc = 1; for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) { rc = rc && (session_write_id (file, SESSION_OBJ_SERVER)); rc = rc && (session_write_str (file, SESSION_SERV_NAME, ptr_server->name)); rc = rc && (session_write_int (file, SESSION_SERV_AUTOCONNECT, ptr_server->autoconnect)); rc = rc && (session_write_int (file, SESSION_SERV_AUTORECONNECT, ptr_server->autoreconnect)); rc = rc && (session_write_int (file, SESSION_SERV_AUTORECONNECT_DELAY, ptr_server->autoreconnect_delay)); rc = rc && (session_write_int (file, SESSION_SERV_COMMAND_LINE, ptr_server->command_line)); rc = rc && (session_write_str (file, SESSION_SERV_ADDRESS, ptr_server->address)); rc = rc && (session_write_int (file, SESSION_SERV_PORT, ptr_server->port)); rc = rc && (session_write_int (file, SESSION_SERV_IPV6, ptr_server->ipv6)); rc = rc && (session_write_int (file, SESSION_SERV_SSL, ptr_server->ssl)); rc = rc && (session_write_str (file, SESSION_SERV_PASSWORD, ptr_server->password)); rc = rc && (session_write_str (file, SESSION_SERV_NICK1, ptr_server->nick1)); rc = rc && (session_write_str (file, SESSION_SERV_NICK2, ptr_server->nick2)); rc = rc && (session_write_str (file, SESSION_SERV_NICK3, ptr_server->nick3)); rc = rc && (session_write_str (file, SESSION_SERV_USERNAME, ptr_server->username)); rc = rc && (session_write_str (file, SESSION_SERV_REALNAME, ptr_server->realname)); rc = rc && (session_write_str (file, SESSION_SERV_HOSTNAME, ptr_server->hostname)); rc = rc && (session_write_str (file, SESSION_SERV_COMMAND, ptr_server->command)); rc = rc && (session_write_int (file, SESSION_SERV_COMMAND_DELAY, ptr_server->command_delay)); rc = rc && (session_write_str (file, SESSION_SERV_AUTOJOIN, ptr_server->autojoin)); rc = rc && (session_write_int (file, SESSION_SERV_AUTOREJOIN, ptr_server->autorejoin)); rc = rc && (session_write_str (file, SESSION_SERV_NOTIFY_LEVELS, ptr_server->notify_levels)); rc = rc && (session_write_int (file, SESSION_SERV_CHILD_PID, ptr_server->child_pid)); rc = rc && (session_write_int (file, SESSION_SERV_CHILD_READ, ptr_server->child_read)); rc = rc && (session_write_int (file, SESSION_SERV_CHILD_WRITE, ptr_server->child_write)); rc = rc && (session_write_int (file, SESSION_SERV_SOCK, ptr_server->sock)); rc = rc && (session_write_int (file, SESSION_SERV_IS_CONNECTED, ptr_server->is_connected)); rc = rc && (session_write_int (file, SESSION_SERV_SSL_CONNECTED, ptr_server->ssl_connected)); #ifdef HAVE_GNUTLS if (ptr_server->is_connected && ptr_server->ssl_connected) { gnutls_session_get_data (ptr_server->gnutls_sess, NULL, &session_size); if (session_size > 0) { session_data = malloc (session_size); gnutls_session_get_data (ptr_server->gnutls_sess, session_data, &session_size); rc = rc && (session_write_buf (file, SESSION_SERV_GNUTLS_SESS, &(session_data), session_size)); free (session_data); } } #endif rc = rc && (session_write_str (file, SESSION_SERV_UNTERMINATED_MESSAGE, ptr_server->unterminated_message)); rc = rc && (session_write_str (file, SESSION_SERV_NICK, ptr_server->nick)); rc = rc && (session_write_str (file, SESSION_SERV_NICK_MODES, ptr_server->nick_modes)); rc = rc && (session_write_buf (file, SESSION_SERV_RECONNECT_START, &(ptr_server->reconnect_start), sizeof (time_t))); rc = rc && (session_write_int (file, SESSION_SERV_RECONNECT_JOIN, ptr_server->reconnect_join)); rc = rc && (session_write_int (file, SESSION_SERV_IS_AWAY, ptr_server->is_away)); rc = rc && (session_write_buf (file, SESSION_SERV_AWAY_TIME, &(ptr_server->away_time), sizeof (time_t))); rc = rc && (session_write_int (file, SESSION_SERV_LAG, ptr_server->lag)); rc = rc && (session_write_buf (file, SESSION_SERV_LAG_CHECK_TIME, &(ptr_server->lag_check_time), sizeof (struct timeval))); rc = rc && (session_write_buf (file, SESSION_SERV_LAG_NEXT_CHECK, &(ptr_server->lag_next_check), sizeof (time_t))); rc = rc && (session_write_str (file, SESSION_SERV_CHARSET_DECODE_ISO, ptr_server->charset_decode_iso)); rc = rc && (session_write_str (file, SESSION_SERV_CHARSET_DECODE_UTF, ptr_server->charset_decode_utf)); rc = rc && (session_write_str (file, SESSION_SERV_CHARSET_ENCODE, ptr_server->charset_encode)); rc = rc && (session_write_id (file, SESSION_SERV_END)); if (!rc) return 0; for (ptr_channel = ptr_server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { if (!session_save_channel (file, ptr_channel)) return 0; } } return 1; } /* * session_save_dcc: save all DCC into session file */ int session_save_dcc (FILE *file) { int rc; t_irc_dcc *ptr_dcc; rc = 1; for (ptr_dcc = dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc) { rc = rc && (session_write_id (file, SESSION_OBJ_DCC)); rc = rc && (session_write_str (file, SESSION_DCC_SERVER, (ptr_dcc->server) ? ptr_dcc->server->name : NULL)); rc = rc && (session_write_str (file, SESSION_DCC_CHANNEL, (ptr_dcc->channel) ? ptr_dcc->channel->name : NULL)); rc = rc && (session_write_int (file, SESSION_DCC_TYPE, ptr_dcc->type)); rc = rc && (session_write_int (file, SESSION_DCC_STATUS, ptr_dcc->status)); rc = rc && (session_write_buf (file, SESSION_DCC_START_TIME, &(ptr_dcc->start_time), sizeof (time_t))); rc = rc && (session_write_buf (file, SESSION_DCC_START_TRANSFER, &(ptr_dcc->start_transfer), sizeof (time_t))); rc = rc && (session_write_buf (file, SESSION_DCC_ADDR, &(ptr_dcc->addr), sizeof (unsigned long))); rc = rc && (session_write_int (file, SESSION_DCC_PORT, ptr_dcc->port)); rc = rc && (session_write_str (file, SESSION_DCC_NICK, ptr_dcc->nick)); rc = rc && (session_write_int (file, SESSION_DCC_SOCK, ptr_dcc->sock)); rc = rc && (session_write_str (file, SESSION_DCC_UNTERMINATED_MESSAGE, ptr_dcc->unterminated_message)); rc = rc && (session_write_int (file, SESSION_DCC_FILE, ptr_dcc->file)); rc = rc && (session_write_str (file, SESSION_DCC_FILENAME, ptr_dcc->filename)); rc = rc && (session_write_str (file, SESSION_DCC_LOCAL_FILENAME, ptr_dcc->local_filename)); rc = rc && (session_write_int (file, SESSION_DCC_FILENAME_SUFFIX, ptr_dcc->filename_suffix)); rc = rc && (session_write_buf (file, SESSION_DCC_SIZE, &(ptr_dcc->size), sizeof (unsigned long))); rc = rc && (session_write_buf (file, SESSION_DCC_POS, &(ptr_dcc->pos), sizeof (unsigned long))); rc = rc && (session_write_buf (file, SESSION_DCC_ACK, &(ptr_dcc->ack), sizeof (unsigned long))); rc = rc && (session_write_buf (file, SESSION_DCC_START_RESUME, &(ptr_dcc->start_resume), sizeof (unsigned long))); rc = rc && (session_write_buf (file, SESSION_DCC_LAST_CHECK_TIME, &(ptr_dcc->last_check_time), sizeof (time_t))); rc = rc && (session_write_buf (file, SESSION_DCC_LAST_CHECK_POS, &(ptr_dcc->last_check_pos), sizeof (unsigned long))); rc = rc && (session_write_buf (file, SESSION_DCC_LAST_ACTIVITY, &(ptr_dcc->last_activity), sizeof (time_t))); rc = rc && (session_write_buf (file, SESSION_DCC_BYTES_PER_SEC, &(ptr_dcc->bytes_per_sec), sizeof (unsigned long))); rc = rc && (session_write_buf (file, SESSION_DCC_ETA, &(ptr_dcc->eta), sizeof (unsigned long))); rc = rc && (session_write_id (file, SESSION_DCC_END)); if (!rc) return 0; } return 1; } /* * session_save_history: save history into session file * (from last to first, to restore it in good order) */ int session_save_history (FILE *file, t_history *last_history) { int rc; t_history *ptr_history; rc = 1; rc = rc && (session_write_id (file, SESSION_OBJ_HISTORY)); ptr_history = last_history; while (ptr_history) { rc = rc && (session_write_str (file, SESSION_HIST_TEXT, ptr_history->text)); ptr_history = ptr_history->prev_history; } rc = rc && (session_write_id (file, SESSION_HIST_END)); return rc; } /* * session_save_line: save a buffer line into session file */ int session_save_line (FILE *file, t_gui_line *line) { int rc; rc = 1; rc = rc && (session_write_id (file, SESSION_OBJ_LINE)); rc = rc && (session_write_int (file, SESSION_LINE_LENGTH, line->length)); rc = rc && (session_write_int (file, SESSION_LINE_LENGTH_ALIGN, line->length_align)); rc = rc && (session_write_int (file, SESSION_LINE_LOG_WRITE, line->log_write)); rc = rc && (session_write_int (file, SESSION_LINE_WITH_MESSAGE, line->line_with_message)); rc = rc && (session_write_int (file, SESSION_LINE_WITH_HIGHLIGHT, line->line_with_highlight)); rc = rc && (session_write_str (file, SESSION_LINE_DATA, line->data)); rc = rc && (session_write_int (file, SESSION_LINE_OFS_AFTER_DATE, line->ofs_start_message)); rc = rc && (session_write_int (file, SESSION_LINE_OFS_START_MESSAGE, line->ofs_start_message)); rc = rc && (session_write_str (file, SESSION_LINE_NICK, line->nick)); rc = rc && (session_write_id (file, SESSION_LINE_END)); return rc; } /* * session_save_buffers: save all buffers into session file */ int session_save_buffers (FILE *file) { int rc; t_gui_buffer *ptr_buffer; t_gui_line *ptr_line; rc = 1; for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer) { rc = rc && (session_write_id (file, SESSION_OBJ_BUFFER)); rc = rc && (session_write_str (file, SESSION_BUFF_SERVER, SERVER(ptr_buffer) ? SERVER(ptr_buffer)->name : NULL)); rc = rc && (session_write_str (file, SESSION_BUFF_CHANNEL, CHANNEL(ptr_buffer) ? CHANNEL(ptr_buffer)->name : NULL)); rc = rc && (session_write_int (file, SESSION_BUFF_TYPE, ptr_buffer->type)); rc = rc && (session_write_int (file, SESSION_BUFF_ALL_SERVERS, ptr_buffer->all_servers)); rc = rc && (session_write_id (file, SESSION_BUFF_END)); if (!rc) return 0; for (ptr_line = ptr_buffer->lines; ptr_line; ptr_line = ptr_line->next_line) { if (!session_save_line (file, ptr_line)) return 0; } if (!session_save_history (file, ptr_buffer->last_history)) return 0; } return 1; } /* * session_save_uptime: save uptime into session file */ int session_save_uptime (FILE *file) { int rc; rc = 1; rc = rc && (session_write_id (file, SESSION_OBJ_UPTIME)); rc = rc && (session_write_buf (file, SESSION_UPT_START_TIME, &weechat_start_time, sizeof (time_t))); rc = rc && (session_write_id (file, SESSION_UPT_END)); return rc; } /* * session_save: save current session */ int session_save (char *filename) { FILE *file; int rc; if ((file = fopen (filename, "wb")) == NULL) return 0; rc = 1; rc = rc && (session_write_str (file, -1, SESSION_SIGNATURE)); rc = rc && (session_save_servers (file)); rc = rc && (session_save_dcc (file)); rc = rc && (session_save_history (file, history_global_last)); rc = rc && (session_save_buffers (file)); rc = rc && (session_save_uptime (file)); fclose (file); return rc; } /* ========================================================================== */ /* * session_crash: stop WeeChat if problem during session loading */ void session_crash (FILE *file, char *message, ...) { char buffer[4096]; va_list argptr; va_start (argptr, message); vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); va_end (argptr); fclose (file); gui_main_end (); fprintf (stderr, "%s %s\n", WEECHAT_ERROR, buffer); fprintf (stderr, _("Last operation with session file was at position %ld, " "read of %d bytes\n"), session_last_read_pos, session_last_read_length); fprintf (stderr, _("Please send %s/%s, %s/%s and " "above messages to WeeChat developers for support.\n" "Be careful, private info may be in these files.\n"), weechat_home, WEECHAT_LOG_NAME, weechat_home, WEECHAT_SESSION_NAME); exit (EXIT_FAILURE); } /* * session_read_int: read integer from file */ int session_read_int (FILE *file, int *value) { char type; session_last_read_pos = ftell (file); session_last_read_length = sizeof (char); if (fread ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (type != SESSION_TYPE_INT) { session_crash (file, _("wrong type in file (expected: %d, read: %d)"), SESSION_TYPE_INT, type); return 0; } session_last_read_pos = ftell (file); session_last_read_length = sizeof (int); if (value) return (fread ((void *)value, sizeof (int), 1, file) > 0); else return (fseek (file, sizeof (int), SEEK_CUR) >= 0); } /* * session_read_str: read string from file */ int session_read_str (FILE *file, char **string) { char type; int length; if (string && *string) free (*string); session_last_read_pos = ftell (file); session_last_read_length = sizeof (char); if (fread ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (type != SESSION_TYPE_STR) { session_crash (file, _("wrong type in file (expected: %d, read: %d)"), SESSION_TYPE_STR, type); return 0; } session_last_read_pos = ftell (file); session_last_read_length = sizeof (int); if (fread ((void *)(&length), sizeof (int), 1, file) == 0) return 0; if (length == 0) { if (string) (*string) = NULL; return 1; } session_last_read_pos = ftell (file); session_last_read_length = length; if (string) { (*string) = (char *) malloc (length + 1); if (!(*string)) return 0; if (fread ((void *)(*string), length, 1, file) == 0) { free (*string); return 0; } (*string)[length] = '\0'; } else return (fseek (file, length, SEEK_CUR) >= 0); return 1; } /* * session_read_buf: read buffer from file */ int session_read_buf (FILE *file, void *buffer, int length_expected) { char type; int length; session_last_read_pos = ftell (file); session_last_read_length = sizeof (char); if (fread ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (type != SESSION_TYPE_BUF) { session_crash (file, _("wrong type in file (expected: %d, read: %d)"), SESSION_TYPE_BUF, type); return 0; } session_last_read_pos = ftell (file); session_last_read_length = sizeof (int); if (fread ((void *)(&length), sizeof (int), 1, file) == 0) return 0; if ((length <= 0) || ((length_expected > 0) && (length != length_expected))) { session_crash (file, _("invalid length for a buffer")); return 0; } session_last_read_pos = ftell (file); session_last_read_length = length; if (buffer) return (fread (buffer, length, 1, file) > 0); else return (fseek (file, length, SEEK_CUR) >= 0); } /* * session_read_buf_alloc: read buffer from file and allocate it in memory */ int session_read_buf_alloc (FILE *file, void **buffer, int *buffer_length) { char type; session_last_read_pos = ftell (file); session_last_read_length = sizeof (char); if (fread ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (type != SESSION_TYPE_BUF) { session_crash (file, _("wrong type in file (expected: %d, read: %d)"), SESSION_TYPE_BUF, type); return 0; } session_last_read_pos = ftell (file); session_last_read_length = sizeof (int); if (fread ((void *)(buffer_length), sizeof (int), 1, file) == 0) return 0; if (*buffer_length <= 0) { session_crash (file, _("invalid length for a buffer")); return 0; } *buffer = malloc (*buffer_length); session_last_read_pos = ftell (file); session_last_read_length = *buffer_length; return (fread (*buffer, *buffer_length, 1, file) > 0); } /* * session_read_object: read an object in file */ int session_read_object (FILE *file, int object_id, int type, void *target, int max_buf_length) { int object_id_read; char type_read; if (fread ((void *)(&object_id_read), sizeof (int), 1, file) == 0) { session_crash (file, _("object read error")); return 0; } if (object_id_read != object_id) { session_crash (file, _("wrong object (expected: %d, read: %d)"), object_id, object_id_read); return 0; } session_last_read_pos = ftell (file); session_last_read_length = sizeof (char); if (fread ((void *)(&type_read), sizeof (char), 1, file) == 0) { session_crash (file, _("type read error")); return 0; } if (type_read != type) { session_crash (file, _("wrong type (expected: %d, read: %d)"), type, type_read); return 0; } if (fseek (file, sizeof (char) * (-1), SEEK_CUR) < 0) return 0; switch (type) { case SESSION_TYPE_INT: return session_read_int (file, (int *)target); case SESSION_TYPE_STR: return session_read_str (file, (char **)target); case SESSION_TYPE_BUF: return session_read_buf (file, target, max_buf_length); } return 0; } /* * session_read_ignore_value: ignore a value from file */ int session_read_ignore_value (FILE *file) { char type; if (fread ((void *)(&type), sizeof (char), 1, file) == 0) return 0; if (fseek (file, sizeof (char) * (-1), SEEK_CUR) < 0) return 0; switch (type) { case SESSION_TYPE_INT: return session_read_int (file, NULL); case SESSION_TYPE_STR: return session_read_str (file, NULL); case SESSION_TYPE_BUF: return session_read_buf (file, NULL, 0); } return 0; } /* * session_read_ignore_object: ignore an object from file */ int session_read_ignore_object (FILE *file) { int object_id; while (1) { if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; if (feof (file)) return 0; if (object_id == SESSION_OBJ_END) return 1; if (!session_read_ignore_value (file)) return 0; } } /* * session_load_server: load server from file */ int session_load_server (FILE *file) { int object_id, rc; char *server_name; #ifdef HAVE_GNUTLS void *session_data; size_t session_size; int session_size_int; const int cert_type_prio[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 }; #endif /* read server name */ server_name = NULL; if (!session_read_object (file, SESSION_SERV_NAME, SESSION_TYPE_STR, &server_name, 0)) { session_crash (file, _("server name not found")); return 0; } /* use or allocate server */ weechat_log_printf (_("session: loading server \"%s\"\n"), server_name); session_current_server = server_search (server_name); if (session_current_server) weechat_log_printf (_("server found, updating values\n")); else { weechat_log_printf (_("server not found, creating new one\n")); session_current_server = server_alloc (); if (!session_current_server) { free (server_name); session_crash (file, _("can't create new server")); return 0; } server_init (session_current_server); session_current_server->name = strdup (server_name); } free (server_name); /* read server values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading server)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_SERV_END: return 1; case SESSION_SERV_AUTOCONNECT: rc = rc && (session_read_int (file, &(session_current_server->autoconnect))); break; case SESSION_SERV_AUTORECONNECT: rc = rc && (session_read_int (file, &(session_current_server->autoreconnect))); break; case SESSION_SERV_AUTORECONNECT_DELAY: rc = rc && (session_read_int (file, &(session_current_server->autoreconnect_delay))); break; case SESSION_SERV_COMMAND_LINE: rc = rc && (session_read_int (file, &(session_current_server->command_line))); break; case SESSION_SERV_ADDRESS: rc = rc && (session_read_str (file, &(session_current_server->address))); break; case SESSION_SERV_PORT: rc = rc && (session_read_int (file, &(session_current_server->port))); break; case SESSION_SERV_IPV6: rc = rc && (session_read_int (file, &(session_current_server->ipv6))); break; case SESSION_SERV_SSL: rc = rc && (session_read_int (file, &(session_current_server->ssl))); break; case SESSION_SERV_PASSWORD: rc = rc && (session_read_str (file, &(session_current_server->password))); break; case SESSION_SERV_NICK1: rc = rc && (session_read_str (file, &(session_current_server->nick1))); break; case SESSION_SERV_NICK2: rc = rc && (session_read_str (file, &(session_current_server->nick2))); break; case SESSION_SERV_NICK3: rc = rc && (session_read_str (file, &(session_current_server->nick3))); break; case SESSION_SERV_USERNAME: rc = rc && (session_read_str (file, &(session_current_server->username))); break; case SESSION_SERV_REALNAME: rc = rc && (session_read_str (file, &(session_current_server->realname))); break; case SESSION_SERV_HOSTNAME: rc = rc && (session_read_str (file, &(session_current_server->hostname))); break; case SESSION_SERV_COMMAND: rc = rc && (session_read_str (file, &(session_current_server->command))); break; case SESSION_SERV_COMMAND_DELAY: rc = rc && (session_read_int (file, &(session_current_server->command_delay))); break; case SESSION_SERV_AUTOJOIN: rc = rc && (session_read_str (file, &(session_current_server->autojoin))); break; case SESSION_SERV_AUTOREJOIN: rc = rc && (session_read_int (file, &(session_current_server->autorejoin))); break; case SESSION_SERV_NOTIFY_LEVELS: rc = rc && (session_read_str (file, &(session_current_server->notify_levels))); break; case SESSION_SERV_CHILD_PID: rc = rc && (session_read_int (file, &(session_current_server->child_pid))); break; case SESSION_SERV_CHILD_READ: rc = rc && (session_read_int (file, &(session_current_server->child_read))); break; case SESSION_SERV_CHILD_WRITE: rc = rc && (session_read_int (file, &(session_current_server->child_write))); break; case SESSION_SERV_SOCK: rc = rc && (session_read_int (file, &(session_current_server->sock))); break; case SESSION_SERV_IS_CONNECTED: rc = rc && (session_read_int (file, &(session_current_server->is_connected))); break; case SESSION_SERV_SSL_CONNECTED: rc = rc && (session_read_int (file, &(session_current_server->ssl_connected))); break; #ifdef HAVE_GNUTLS case SESSION_SERV_GNUTLS_SESS: if (gnutls_init (&(session_current_server->gnutls_sess), GNUTLS_CLIENT) != 0) { session_crash (file, _("gnutls init error")); return 0; } gnutls_set_default_priority (session_current_server->gnutls_sess); gnutls_certificate_type_set_priority (session_current_server->gnutls_sess, cert_type_prio); gnutls_credentials_set (session_current_server->gnutls_sess, GNUTLS_CRD_CERTIFICATE, gnutls_xcred); session_data = NULL; rc = rc && (session_read_buf_alloc (file, &session_data, &session_size_int)); if (rc) { session_size = session_size_int; gnutls_session_set_data (session_current_server->gnutls_sess, session_data, session_size); free (session_data); gnutls_transport_set_ptr (session_current_server->gnutls_sess, (gnutls_transport_ptr) session_current_server->sock); if (gnutls_handshake (session_current_server->gnutls_sess) < 0) { session_crash (file, _("gnutls handshake failed")); return 0; } } break; #endif case SESSION_SERV_UNTERMINATED_MESSAGE: rc = rc && (session_read_str (file, &(session_current_server->unterminated_message))); break; case SESSION_SERV_NICK: rc = rc && (session_read_str (file, &(session_current_server->nick))); break; case SESSION_SERV_NICK_MODES: rc = rc && (session_read_str (file, &(session_current_server->nick_modes))); break; case SESSION_SERV_RECONNECT_START: rc = rc && (session_read_buf (file, &(session_current_server->reconnect_start), sizeof (time_t))); break; case SESSION_SERV_RECONNECT_JOIN: rc = rc && (session_read_int (file, &(session_current_server->reconnect_join))); break; case SESSION_SERV_IS_AWAY: rc = rc && (session_read_int (file, &(session_current_server->is_away))); break; case SESSION_SERV_AWAY_TIME: rc = rc && (session_read_buf (file, &(session_current_server->away_time), sizeof (time_t))); break; case SESSION_SERV_LAG: rc = rc && (session_read_int (file, &(session_current_server->lag))); break; case SESSION_SERV_LAG_CHECK_TIME: rc = rc && (session_read_buf (file, &(session_current_server->lag_check_time), sizeof (struct timeval))); break; case SESSION_SERV_LAG_NEXT_CHECK: rc = rc && (session_read_buf (file, &(session_current_server->lag_next_check), sizeof (time_t))); break; case SESSION_SERV_CHARSET_DECODE_ISO: rc = rc && (session_read_str (file, &(session_current_server->charset_decode_iso))); break; case SESSION_SERV_CHARSET_DECODE_UTF: rc = rc && (session_read_str (file, &(session_current_server->charset_decode_utf))); break; case SESSION_SERV_CHARSET_ENCODE: rc = rc && (session_read_str (file, &(session_current_server->charset_encode))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "server (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_channel: load channel from file */ int session_load_channel (FILE *file) { int object_id, rc, channel_type; char *channel_name; /* check if server is allocated for this channel */ if (!session_current_server) { session_crash (file, _("channel found without server")); return 0; } /* read channel type */ if (!session_read_object (file, SESSION_CHAN_TYPE, SESSION_TYPE_INT, &channel_type, 0)) { session_crash (file, _("channel type not found")); return 0; } /* read channel name */ channel_name = NULL; if (!session_read_object (file, SESSION_CHAN_NAME, SESSION_TYPE_STR, &channel_name, 0)) { session_crash (file, _("channel name not found")); return 0; } /* allocate channel */ weechat_log_printf (_("session: loading channel \"%s\"\n"), channel_name); session_current_channel = channel_new (session_current_server, channel_type, channel_name); free (channel_name); if (!session_current_channel) { session_crash (file, _("can't create new channel")); return 0; } /* read channel values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading channel)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_CHAN_END: return 1; case SESSION_CHAN_TOPIC: rc = rc && (session_read_str (file, &(session_current_channel->topic))); break; case SESSION_CHAN_MODES: rc = rc && (session_read_str (file, (char **)(&(session_current_channel->modes)))); break; case SESSION_CHAN_LIMIT: rc = rc && (session_read_int (file, &(session_current_channel->limit))); break; case SESSION_CHAN_KEY: rc = rc && (session_read_str (file, &(session_current_channel->key))); break; case SESSION_CHAN_NICKS_COUNT: rc = rc && (session_read_int (file, &(session_current_channel->nicks_count))); /* will be incremented when adding nicks */ session_current_channel->nicks_count = 0; break; case SESSION_CHAN_CHECKING_AWAY: rc = rc && (session_read_int (file, &(session_current_channel->checking_away))); break; case SESSION_CHAN_AWAY_MESSAGE: rc = rc && (session_read_str (file, &(session_current_channel->away_message))); break; case SESSION_CHAN_CYCLE: rc = rc && (session_read_int (file, &(session_current_channel->cycle))); break; case SESSION_CHAN_CLOSE: rc = rc && (session_read_int (file, &(session_current_channel->close))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "channel (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_nick: load nick from file */ int session_load_nick (FILE *file) { int rc, object_id; char *nick_name; t_irc_nick *nick; /* check if channel is allocated for this nick */ if (!session_current_channel) { session_crash (file, _("nick found without channel")); return 0; } /* read nick name */ nick_name = NULL; if (!session_read_object (file, SESSION_NICK_NICK, SESSION_TYPE_STR, &nick_name, 0)) { session_crash (file, _("nick name not found")); return 0; } /* allocate nick */ nick = nick_new (session_current_server, session_current_channel, nick_name, 0, 0, 0, 0, 0); free (nick_name); if (!nick) { session_crash (file, _("can't create new nick")); return 0; } /* read nick values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading nick)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_NICK_END: return 1; case SESSION_NICK_FLAGS: rc = rc && (session_read_int (file, &(nick->flags))); break; case SESSION_NICK_COLOR: rc = rc && (session_read_int (file, &(nick->color))); break; case SESSION_NICK_HOST: rc = rc && (session_read_str (file, &(nick->host))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "nick (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_dcc: load DCC from file */ int session_load_dcc (FILE *file) { int object_id, rc; t_irc_dcc *dcc; char *string; t_irc_server *ptr_server; t_irc_channel *ptr_channel; /* allocate DCC */ dcc = dcc_alloc (); if (!dcc) { session_crash (file, _("can't create new DCC")); return 0; } weechat_log_printf (_("session: loading DCC\n")); /* read DCC values */ ptr_server = NULL; ptr_channel = NULL; rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading DCC)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_DCC_END: return 1; case SESSION_DCC_SERVER: string = NULL; rc = rc && (session_read_str (file, &string)); if (!rc) return 0; if (string && string[0]) { ptr_server = server_search (string); if (!ptr_server) { session_crash (file, _("server not found for DCC")); return 0; } dcc->server = ptr_server; } break; case SESSION_DCC_CHANNEL: if (!ptr_server) { session_crash (file, _("DCC with channel but without server")); return 0; } string = NULL; rc = rc && (session_read_str (file, &string)); if (!rc) return 0; if (string && string[0]) { ptr_channel = channel_search_any (ptr_server, string); if (!ptr_channel) { session_crash (file, _("channel not found for DCC")); return 0; } dcc->channel = ptr_channel; ptr_channel->dcc_chat = dcc; } break; case SESSION_DCC_TYPE: rc = rc && (session_read_int (file, &(dcc->type))); break; case SESSION_DCC_STATUS: rc = rc && (session_read_int (file, &(dcc->status))); break; case SESSION_DCC_START_TIME: rc = rc && (session_read_buf (file, &(dcc->start_time), sizeof (time_t))); break; case SESSION_DCC_START_TRANSFER: rc = rc && (session_read_buf (file, &(dcc->start_transfer), sizeof (time_t))); break; case SESSION_DCC_ADDR: rc = rc && (session_read_buf (file, &(dcc->addr), sizeof (unsigned long))); break; case SESSION_DCC_PORT: rc = rc && (session_read_int (file, &(dcc->port))); break; case SESSION_DCC_NICK: rc = rc && (session_read_str (file, &(dcc->nick))); break; case SESSION_DCC_SOCK: rc = rc && (session_read_int (file, &(dcc->sock))); break; case SESSION_DCC_UNTERMINATED_MESSAGE: rc = rc && (session_read_str (file, &(dcc->unterminated_message))); break; case SESSION_DCC_FILE: rc = rc && (session_read_int (file, &(dcc->file))); break; case SESSION_DCC_FILENAME: rc = rc && (session_read_str (file, &(dcc->filename))); break; case SESSION_DCC_LOCAL_FILENAME: rc = rc && (session_read_str (file, &(dcc->local_filename))); break; case SESSION_DCC_FILENAME_SUFFIX: rc = rc && (session_read_int (file, &(dcc->filename_suffix))); break; case SESSION_DCC_SIZE: rc = rc && (session_read_buf (file, &(dcc->size), sizeof (unsigned long))); break; case SESSION_DCC_POS: rc = rc && (session_read_buf (file, &(dcc->pos), sizeof (unsigned long))); break; case SESSION_DCC_ACK: rc = rc && (session_read_buf (file, &(dcc->ack), sizeof (unsigned long))); break; case SESSION_DCC_START_RESUME: rc = rc && (session_read_buf (file, &(dcc->start_resume), sizeof (unsigned long))); break; case SESSION_DCC_LAST_CHECK_TIME: rc = rc && (session_read_buf (file, &(dcc->last_check_time), sizeof (time_t))); break; case SESSION_DCC_LAST_CHECK_POS: rc = rc && (session_read_buf (file, &(dcc->last_check_pos), sizeof (unsigned long))); break; case SESSION_DCC_LAST_ACTIVITY: rc = rc && (session_read_buf (file, &(dcc->last_activity), sizeof (time_t))); break; case SESSION_DCC_BYTES_PER_SEC: rc = rc && (session_read_buf (file, &(dcc->bytes_per_sec), sizeof (unsigned long))); break; case SESSION_DCC_ETA: rc = rc && (session_read_buf (file, &(dcc->eta), sizeof (unsigned long))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "DCC (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_history: load history from file (global or for a buffer) */ int session_load_history (FILE *file) { int object_id, rc; char *text; if (session_current_buffer) weechat_log_printf (_("session: loading buffer history\n")); else weechat_log_printf (_("session: loading global history\n")); /* read history values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading history)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_HIST_END: return 1; case SESSION_HIST_TEXT: text = NULL; if (!session_read_str (file, &text)) return 0; if (session_current_buffer) history_buffer_add (session_current_buffer, text); else history_global_add (text); free (text); break; default: weechat_log_printf (_("session: warning: ignoring value from " "history (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_buffer: load buffer from file */ int session_load_buffer (FILE *file) { int object_id, rc; char *server_name, *channel_name; int buffer_type; t_irc_server *ptr_server; t_irc_channel *ptr_channel; /* read server name */ server_name = NULL; if (!session_read_object (file, SESSION_BUFF_SERVER, SESSION_TYPE_STR, &server_name, 0)) { session_crash (file, _("server name not found for buffer")); return 0; } /* read channel name */ channel_name = NULL; if (!session_read_object (file, SESSION_BUFF_CHANNEL, SESSION_TYPE_STR, &channel_name, 0)) { session_crash (file, _("channel name not found for buffer")); return 0; } /* read buffer type */ if (!session_read_object (file, SESSION_BUFF_TYPE, SESSION_TYPE_INT, &buffer_type, 0)) { session_crash (file, _("buffer type not found")); return 0; } /* allocate buffer */ weechat_log_printf (_("session: loading buffer (server: %s, channel: %s, type: %d)\n"), (server_name) ? server_name : "-", (channel_name) ? channel_name : "-", buffer_type); ptr_server = NULL; ptr_channel = NULL; if (server_name) { ptr_server = server_search (server_name); if (!ptr_server) { session_crash (file, _("server not found for buffer")); return 0; } } if (channel_name) { ptr_channel = channel_search_any_without_buffer (ptr_server, channel_name); if (!ptr_channel) { session_crash (file, _("channel not found for buffer")); return 0; } } session_current_buffer = gui_buffer_new (gui_windows, ptr_server, ptr_channel, buffer_type, 1); if (!session_current_buffer) { session_crash (file, _("can't create new buffer")); return 0; } free (server_name); free (channel_name); /* read buffer values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading buffer)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_BUFF_END: return 1; case SESSION_BUFF_ALL_SERVERS: rc = rc && (session_read_int (file, &(session_current_buffer->all_servers))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "buffer (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_line: load buffer line from file */ int session_load_line (FILE *file) { int object_id, rc; t_gui_line *line; /* check if buffer is allocated for this line */ if (!session_current_buffer) { session_crash (file, _("line found without buffer")); return 0; } /* allocate line */ line = gui_buffer_line_new (session_current_buffer); if (!line) { session_crash (file, _("can't create new line")); return 0; } /* read line values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading line)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_LINE_END: return 1; case SESSION_LINE_LENGTH: rc = rc && (session_read_int (file, &(line->length))); break; case SESSION_LINE_LENGTH_ALIGN: rc = rc && (session_read_int (file, &(line->length_align))); break; case SESSION_LINE_LOG_WRITE: rc = rc && (session_read_int (file, &(line->log_write))); break; case SESSION_LINE_WITH_MESSAGE: rc = rc && (session_read_int (file, &(line->line_with_message))); break; case SESSION_LINE_WITH_HIGHLIGHT: rc = rc && (session_read_int (file, &(line->line_with_highlight))); break; case SESSION_LINE_DATA: rc = rc && (session_read_str (file, &(line->data))); break; case SESSION_LINE_OFS_AFTER_DATE: rc = rc && (session_read_int (file, &(line->ofs_after_date))); break; case SESSION_LINE_OFS_START_MESSAGE: rc = rc && (session_read_int (file, &(line->ofs_start_message))); break; case SESSION_LINE_NICK: rc = rc && (session_read_str (file, &(line->nick))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "line (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load_uptime: load uptime from file */ int session_load_uptime (FILE *file) { int object_id, rc; /* read uptime values */ rc = 1; while (rc) { if (feof (file)) { session_crash (file, _("unexpected end of file (reading uptime)")); return 0; } if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) return 0; switch (object_id) { case SESSION_UPT_END: return 1; case SESSION_UPT_START_TIME: rc = rc && (session_read_buf (file, &weechat_start_time, sizeof (time_t))); break; default: weechat_log_printf (_("session: warning: ignoring value from " "uptime (object id: %d)\n")); rc = rc && (session_read_ignore_value (file)); break; } } return 0; } /* * session_load: load session from file */ int session_load (char *filename) { FILE *file; char *signature; int object_id; t_irc_server *ptr_server; session_current_server = NULL; session_current_channel = NULL; session_current_buffer = NULL; session_last_read_pos = -1; session_last_read_length = -1; if ((file = fopen (filename, "rb")) == NULL) { session_crash (file, _("session file not found")); return 0; } signature = NULL; if (!session_read_str (file, &signature)) { session_crash (file, _("signature not found")); return 0; } if (!signature || (strcmp (signature, SESSION_SIGNATURE) != 0)) { session_crash (file, _("bad session signature")); return 0; } free (signature); while (!feof (file)) { if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0) { if (feof (file)) break; session_crash (file, _("object id not found")); return 0; } switch (object_id) { case SESSION_OBJ_SERVER: if (!session_load_server (file)) { session_crash (file, _("failed to load server")); return 0; } break; case SESSION_OBJ_CHANNEL: if (!session_load_channel (file)) { session_crash (file, _("failed to load channel")); return 0; } break; case SESSION_OBJ_NICK: if (!session_load_nick (file)) { session_crash (file, _("failed to load nick")); return 0; } break; case SESSION_OBJ_DCC: if (!session_load_dcc (file)) { session_crash (file, _("failed to load DCC")); return 0; } break; case SESSION_OBJ_HISTORY: if (!session_load_history (file)) { session_crash (file, _("failed to load history")); return 0; } break; case SESSION_OBJ_BUFFER: if (!session_load_buffer (file)) { session_crash (file, _("failed to load buffer")); return 0; } break; case SESSION_OBJ_LINE: if (!session_load_line (file)) { session_crash (file, _("failed to load line")); return 0; } break; case SESSION_OBJ_UPTIME: if (!session_load_uptime (file)) { session_crash (file, _("failed to load uptime")); return 0; } break; default: weechat_log_printf (_("ignoring object (id: %d)\n"), object_id); if (!session_read_ignore_object (file)) { session_crash (file, _("failed to ignore object (id: %d)"), object_id); return 0; } } } /* assign a buffer to all connected servers */ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) { if ((ptr_server->is_connected) && (!ptr_server->buffer)) ptr_server->buffer = gui_buffers; } gui_window_switch_to_buffer (gui_windows, gui_buffers); gui_window_redraw_buffer (gui_current_window->buffer); fclose (file); if (unlink (filename) < 0) { irc_display_prefix (NULL, gui_current_window->buffer, PREFIX_ERROR); gui_printf_nolog (gui_current_window->buffer, _("%s can't delete session file (%s)\n"), WEECHAT_ERROR); } irc_display_prefix (NULL, gui_current_window->buffer, PREFIX_INFO); gui_printf_nolog (gui_current_window->buffer, _("Upgrade completed successfully\n")); return 1; }