Coverage Report

Created: 2026-04-01 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/irssi/src/core/rawlog.c
Line
Count
Source
1
/*
2
 rawlog.c : irssi
3
4
    Copyright (C) 1999-2000 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 along
17
    with this program; if not, write to the Free Software Foundation, Inc.,
18
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
*/
20
21
#include "module.h"
22
#include <irssi/src/core/rawlog.h>
23
#include <irssi/src/core/log.h>
24
#include <irssi/src/core/modules.h>
25
#include <irssi/src/core/signals.h>
26
#include <irssi/src/core/commands.h>
27
#include <irssi/src/core/misc.h>
28
#include <irssi/src/core/write-buffer.h>
29
#include <irssi/src/core/settings.h>
30
#ifdef HAVE_CAPSICUM
31
#include <irssi/src/core/capsicum.h>
32
#endif
33
34
#include <irssi/src/core/servers.h>
35
36
static int rawlog_lines;
37
static int signal_rawlog;
38
39
RAWLOG_REC *rawlog_create(void)
40
36.6k
{
41
36.6k
  RAWLOG_REC *rec;
42
43
36.6k
  rec = g_new0(RAWLOG_REC, 1);
44
36.6k
  rec->lines = g_queue_new();
45
36.6k
  return rec;
46
36.6k
}
47
48
void rawlog_destroy(RAWLOG_REC *rawlog)
49
36.6k
{
50
36.6k
  g_return_if_fail(rawlog != NULL);
51
52
36.6k
  g_queue_foreach(rawlog->lines, (GFunc) g_free, NULL);
53
36.6k
  g_queue_free(rawlog->lines);
54
55
36.6k
  if (rawlog->logging) {
56
0
    write_buffer_flush();
57
0
    close(rawlog->handle);
58
0
  }
59
36.6k
  g_free(rawlog);
60
36.6k
}
61
62
/* NOTE! str must be dynamically allocated and must not be freed after! */
63
static void rawlog_add(RAWLOG_REC *rawlog, char *str)
64
68.6k
{
65
126k
  while (rawlog->lines->length >= rawlog_lines && rawlog_lines > 0) {
66
57.8k
    void *tmp = g_queue_pop_head(rawlog->lines);
67
57.8k
    g_free(tmp);
68
57.8k
  }
69
70
68.6k
  if (rawlog->logging) {
71
0
    write_buffer(rawlog->handle, str, strlen(str));
72
0
    write_buffer(rawlog->handle, "\n", 1);
73
0
  }
74
75
68.6k
  g_queue_push_tail(rawlog->lines, str);
76
68.6k
  signal_emit_id(signal_rawlog, 2, rawlog, str);
77
68.6k
}
78
79
void rawlog_input(RAWLOG_REC *rawlog, const char *str)
80
0
{
81
0
  g_return_if_fail(rawlog != NULL);
82
0
  g_return_if_fail(str != NULL);
83
84
0
  rawlog_add(rawlog, g_strdup_printf(">> %s", str));
85
0
}
86
87
void rawlog_output(RAWLOG_REC *rawlog, const char *str)
88
63.8k
{
89
63.8k
  g_return_if_fail(rawlog != NULL);
90
63.8k
  g_return_if_fail(str != NULL);
91
92
63.8k
  rawlog_add(rawlog, g_strdup_printf("<< %s", str));
93
63.8k
}
94
95
void rawlog_redirect(RAWLOG_REC *rawlog, const char *str)
96
4.75k
{
97
4.75k
  g_return_if_fail(rawlog != NULL);
98
4.75k
  g_return_if_fail(str != NULL);
99
100
4.75k
  rawlog_add(rawlog, g_strdup_printf("--> %s", str));
101
4.75k
}
102
103
static void rawlog_dump(RAWLOG_REC *rawlog, int f)
104
0
{
105
0
  GList *tmp;
106
0
  ssize_t ret = 0;
107
108
0
  for (tmp = rawlog->lines->head; ret != -1 && tmp != NULL; tmp = tmp->next) {
109
0
    ret = write(f, tmp->data, strlen((char *) tmp->data));
110
0
                if (ret != -1)
111
0
                        ret = write(f, "\n", 1);
112
0
        }
113
114
0
  if (ret == -1) {
115
0
    g_warning("rawlog write() failed: %s", strerror(errno));
116
0
  }
117
0
}
118
119
void rawlog_open(RAWLOG_REC *rawlog, const char *fname)
120
0
{
121
0
  char *path;
122
123
0
        g_return_if_fail(rawlog != NULL);
124
0
  g_return_if_fail(fname != NULL);
125
126
0
  if (rawlog->logging)
127
0
    return;
128
129
0
  path = convert_home(fname);
130
#ifdef HAVE_CAPSICUM
131
  rawlog->handle = capsicum_open_wrapper(path,
132
                 O_WRONLY | O_APPEND | O_CREAT,
133
                 log_file_create_mode);
134
#else
135
0
  rawlog->handle = open(path, O_WRONLY | O_APPEND | O_CREAT,
136
0
            log_file_create_mode);
137
0
#endif
138
139
0
  g_free(path);
140
141
0
  if (rawlog->handle == -1) {
142
0
    g_warning("rawlog open() failed: %s", strerror(errno));
143
0
    return;
144
0
  }
145
146
0
  rawlog_dump(rawlog, rawlog->handle);
147
0
  rawlog->logging = TRUE;
148
0
}
149
150
void rawlog_close(RAWLOG_REC *rawlog)
151
0
{
152
0
  if (rawlog->logging) {
153
0
    write_buffer_flush();
154
0
    close(rawlog->handle);
155
0
    rawlog->logging = FALSE;
156
0
  }
157
0
}
158
159
void rawlog_save(RAWLOG_REC *rawlog, const char *fname)
160
0
{
161
0
  char *path, *dir;
162
0
  int f;
163
164
0
        dir = g_path_get_dirname(fname);
165
#ifdef HAVE_CAPSICUM
166
        capsicum_mkdir_with_parents_wrapper(dir, log_dir_create_mode);
167
#else
168
0
        g_mkdir_with_parents(dir, log_dir_create_mode);
169
0
#endif
170
0
        g_free(dir);
171
172
0
  path = convert_home(fname);
173
#ifdef HAVE_CAPSICUM
174
  f = capsicum_open_wrapper(path, O_WRONLY | O_APPEND | O_CREAT,
175
          log_file_create_mode);
176
#else
177
0
  f = open(path, O_WRONLY | O_APPEND | O_CREAT, log_file_create_mode);
178
0
#endif
179
0
  g_free(path);
180
181
0
  if (f < 0) {
182
0
    g_warning("rawlog open() failed: %s", strerror(errno));
183
0
    return;
184
0
  }
185
186
0
  rawlog_dump(rawlog, f);
187
0
  close(f);
188
0
}
189
190
void rawlog_set_size(int lines)
191
10
{
192
10
  rawlog_lines = lines;
193
10
}
194
195
static void read_settings(void)
196
8
{
197
8
  rawlog_set_size(settings_get_int("rawlog_lines"));
198
8
}
199
200
static void cmd_rawlog(const char *data, SERVER_REC *server, void *item)
201
0
{
202
0
  command_runsub("rawlog", data, server, item);
203
0
}
204
205
/* SYNTAX: RAWLOG SAVE <file> */
206
static void cmd_rawlog_save(const char *data, SERVER_REC *server)
207
0
{
208
0
  g_return_if_fail(data != NULL);
209
0
  if (server == NULL || server->rawlog == NULL)
210
0
    cmd_return_error(CMDERR_NOT_CONNECTED);
211
212
0
  if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
213
0
  rawlog_save(server->rawlog, data);
214
0
}
215
216
/* SYNTAX: RAWLOG OPEN <file> */
217
static void cmd_rawlog_open(const char *data, SERVER_REC *server)
218
0
{
219
0
  g_return_if_fail(data != NULL);
220
0
  if (server == NULL || server->rawlog == NULL)
221
0
    cmd_return_error(CMDERR_NOT_CONNECTED);
222
223
0
  if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
224
0
  rawlog_open(server->rawlog, data);
225
0
}
226
227
/* SYNTAX: RAWLOG CLOSE */
228
static void cmd_rawlog_close(const char *data, SERVER_REC *server)
229
0
{
230
0
  g_return_if_fail(data != NULL);
231
0
  if (server == NULL || server->rawlog == NULL)
232
0
    cmd_return_error(CMDERR_NOT_CONNECTED);
233
234
0
  rawlog_close(server->rawlog);
235
0
}
236
237
void rawlog_init(void)
238
8
{
239
8
  signal_rawlog = signal_get_uniq_id("rawlog");
240
241
8
  settings_add_int("history", "rawlog_lines", 200);
242
8
  read_settings();
243
244
8
  signal_add("setup changed", (SIGNAL_FUNC) read_settings);
245
246
8
  command_bind("rawlog", NULL, (SIGNAL_FUNC) cmd_rawlog);
247
8
  command_bind("rawlog save", NULL, (SIGNAL_FUNC) cmd_rawlog_save);
248
8
  command_bind("rawlog open", NULL, (SIGNAL_FUNC) cmd_rawlog_open);
249
8
  command_bind("rawlog close", NULL, (SIGNAL_FUNC) cmd_rawlog_close);
250
8
}
251
252
void rawlog_deinit(void)
253
0
{
254
0
  signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
255
256
0
  command_unbind("rawlog", (SIGNAL_FUNC) cmd_rawlog);
257
0
  command_unbind("rawlog save", (SIGNAL_FUNC) cmd_rawlog_save);
258
0
  command_unbind("rawlog open", (SIGNAL_FUNC) cmd_rawlog_open);
259
  command_unbind("rawlog close", (SIGNAL_FUNC) cmd_rawlog_close);
260
0
}