Coverage Report

Created: 2025-07-23 06:42

/src/irssi/src/fe-common/irc/fe-whois.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 1999-2004 Timo Sirainen */
2
3
#include "module.h"
4
#include <irssi/src/fe-common/irc/module-formats.h>
5
#include <irssi/src/core/signals.h>
6
#include <irssi/src/core/levels.h>
7
#include <irssi/src/core/misc.h>
8
#include <irssi/src/core/settings.h>
9
#include <irssi/src/core/recode.h>
10
11
#include <irssi/src/irc/core/irc-servers.h>
12
13
#include <irssi/src/fe-common/core/printtext.h>
14
15
static void event_whois(IRC_SERVER_REC *server, const char *data)
16
3.09k
{
17
3.09k
  char *params, *nick, *user, *host, *realname, *recoded;
18
19
3.09k
  g_return_if_fail(data != NULL);
20
21
3.09k
  params = event_get_params(data, 6, NULL, &nick, &user,
22
3.09k
          &host, NULL, &realname);
23
3.09k
  recoded = recode_in(SERVER(server), realname, nick);
24
3.09k
  printformat(server, nick, MSGLEVEL_CRAP,
25
3.09k
        IRCTXT_WHOIS, nick, user, host, recoded);
26
3.09k
  g_free(params);
27
3.09k
  g_free(recoded);
28
3.09k
}
29
30
static void event_whois_special(IRC_SERVER_REC *server, const char *data)
31
7.32k
{
32
7.32k
  char *params, *nick, *str;
33
34
7.32k
  g_return_if_fail(data != NULL);
35
36
7.32k
  params = event_get_params(data, 3 | PARAM_FLAG_GETREST, NULL, &nick, &str);
37
7.32k
  printformat(server, nick, MSGLEVEL_CRAP,
38
7.32k
        IRCTXT_WHOIS_SPECIAL, nick, str);
39
7.32k
  g_free(params);
40
7.32k
}
41
42
static void event_whois_idle(IRC_SERVER_REC *server, const char *data)
43
783
{
44
783
  char *params, *nick, *secstr, *signonstr, *rest, *timestr;
45
783
  long days, hours, mins, secs;
46
783
  time_t signon;
47
48
783
  g_return_if_fail(data != NULL);
49
50
783
  params = event_get_params(data, 5 | PARAM_FLAG_GETREST, NULL,
51
783
          &nick, &secstr, &signonstr, &rest);
52
53
783
  secs = atol(secstr);
54
783
  signon = strstr(rest, "signon time") == NULL ? 0 :
55
783
    (time_t) atol(signonstr);
56
57
783
  days = secs/3600/24;
58
783
  hours = (secs%(3600*24))/3600;
59
783
  mins = (secs%3600)/60;
60
783
  secs %= 60;
61
62
783
  if (signon == 0)
63
358
    printformat(server, nick, MSGLEVEL_CRAP, IRCTXT_WHOIS_IDLE,
64
783
          nick, days, hours, mins, secs);
65
425
  else {
66
425
    timestr = my_asctime(signon);
67
425
    printformat(server, nick, MSGLEVEL_CRAP,
68
425
          IRCTXT_WHOIS_IDLE_SIGNON,
69
425
          nick, days, hours, mins, secs, timestr);
70
425
    g_free(timestr);
71
425
  }
72
783
  g_free(params);
73
783
}
74
75
static void event_whois_server(IRC_SERVER_REC *server, const char *data)
76
725
{
77
725
  char *params, *nick, *whoserver, *desc;
78
79
725
  g_return_if_fail(data != NULL);
80
81
725
  params = event_get_params(data, 4, NULL, &nick, &whoserver, &desc);
82
725
  printformat(server, nick, MSGLEVEL_CRAP,
83
725
        IRCTXT_WHOIS_SERVER, nick, whoserver, desc);
84
725
  g_free(params);
85
725
}
86
87
static void event_whois_oper(IRC_SERVER_REC *server, const char *data)
88
3.17k
{
89
3.17k
  char *params, *nick, *type;
90
91
3.17k
  g_return_if_fail(data != NULL);
92
93
3.17k
  params = event_get_params(data, 3, NULL, &nick, &type);
94
95
  /* Bugfix: http://bugs.irssi.org/?do=details&task_id=99
96
   * Author: Geert Hauwaerts <geert@irssi.org>
97
   * Date:   Wed Sep 15 20:17:24 CEST 2004
98
   */
99
100
3.17k
  if ((!strncmp(type, "is an ", 6)) || (!strncmp(type, "is a ", 5))) {
101
1.89k
    type += 5;
102
1.89k
    if (*type == ' ') type++;
103
1.89k
  }
104
105
3.17k
  if (*type == '\0')
106
537
    type = "IRC Operator";
107
108
3.17k
  printformat(server, nick, MSGLEVEL_CRAP,
109
3.17k
    IRCTXT_WHOIS_OPER, nick, type);
110
3.17k
  g_free(params);
111
3.17k
}
112
113
static void event_whois_modes(IRC_SERVER_REC *server, const char *data)
114
1.64k
{
115
1.64k
  char *params, *nick, *modes;
116
117
1.64k
  g_return_if_fail(data != NULL);
118
119
1.64k
  params = event_get_params(data, 3 | PARAM_FLAG_GETREST,
120
1.64k
      NULL, &nick, &modes);
121
1.64k
  if (!strncmp(modes, "is using modes ", 15))
122
569
    modes += 15;
123
1.64k
  printformat(server, nick, MSGLEVEL_CRAP,
124
1.64k
        IRCTXT_WHOIS_MODES, nick, modes);
125
1.64k
  g_free(params);
126
1.64k
}
127
128
static void event_whois_realhost(IRC_SERVER_REC *server, const char *data)
129
8.24k
{
130
8.24k
  char *params, *nick, *txt_real, *txt_hostname, *hostname;
131
132
8.24k
  g_return_if_fail(data != NULL);
133
134
        /* <yournick> real hostname <nick> <hostname> */
135
8.24k
  params = event_get_params(data, 5, NULL, &nick, &txt_real,
136
8.24k
          &txt_hostname, &hostname);
137
8.24k
  if (g_strcmp0(txt_real, "real") != 0 ||
138
8.24k
      g_strcmp0(txt_hostname, "hostname") != 0) {
139
    /* <yournick> <nick> :... from <hostname> */
140
6.17k
                g_free(params);
141
6.17k
    params = event_get_params(data, 3, NULL, &nick, &hostname);
142
143
6.17k
    hostname = strstr(hostname, "from ");
144
6.17k
                if (hostname != NULL) hostname += 5;
145
6.17k
  }
146
147
8.24k
  if (hostname != NULL) {
148
2.76k
    if (!strncmp(hostname, "*@", 2))
149
670
      hostname += 2;
150
2.76k
    printformat(server, nick, MSGLEVEL_CRAP,
151
2.76k
          IRCTXT_WHOIS_REALHOST, nick, hostname, "");
152
5.47k
  } else {
153
5.47k
    event_whois_special(server, data);
154
5.47k
  }
155
8.24k
  g_free(params);
156
8.24k
}
157
158
static void event_whois_usermode326(IRC_SERVER_REC *server, const char *data)
159
470
{
160
470
  char *params, *nick, *usermode;
161
162
470
  g_return_if_fail(data != NULL);
163
164
        /* <yournick> <nick> :has oper privs: <mode> */
165
470
  params = event_get_params(data, 3, NULL, &nick, &usermode);
166
470
  printformat(server, nick, MSGLEVEL_CRAP,
167
470
        IRCTXT_WHOIS_USERMODE, nick, usermode);
168
470
        g_free(params);
169
470
}
170
171
static void event_whois_realhost327(IRC_SERVER_REC *server, const char *data)
172
1.04k
{
173
1.04k
  char *params, *nick, *hostname, *ip, *text;
174
175
1.04k
  g_return_if_fail(data != NULL);
176
177
  /* <yournick> <hostname> <ip> :Real hostname/IP */
178
1.04k
  params = event_get_params(data, 5, NULL, &nick, &hostname, &ip, &text);
179
1.04k
  if (*text != '\0') {
180
364
    printformat(server, nick, MSGLEVEL_CRAP,
181
364
          IRCTXT_WHOIS_REALHOST, nick, hostname, ip);
182
679
  } else {
183
679
    event_whois_special(server, data);
184
679
  }
185
1.04k
  g_free(params);
186
1.04k
}
187
188
static void event_whois_realhost338(IRC_SERVER_REC *server, const char *data)
189
1.64k
{
190
1.64k
  char *params, *nick, *arg1, *arg2, *arg3;
191
192
1.64k
  g_return_if_fail(data != NULL);
193
194
  /*
195
   * :<server> 338 <yournick> <nick> <user>@<host> <ip> :Actual user@host, actual IP
196
   * (ircu) or
197
   * :<server> 338 <yournick> <nick> <ip> :actually using host
198
   * (ratbox)
199
   */
200
1.64k
  params = event_get_params(data, 5, NULL, &nick, &arg1, &arg2, &arg3);
201
1.64k
  if (*arg3 != '\0') {
202
374
    printformat(server, nick, MSGLEVEL_CRAP,
203
374
          IRCTXT_WHOIS_REALHOST, nick, arg1, arg2);
204
1.27k
  } else if (*arg2 != '\0') {
205
656
    printformat(server, nick, MSGLEVEL_CRAP,
206
656
          IRCTXT_WHOIS_REALHOST, nick, arg1, "");
207
656
  } else {
208
615
    event_whois_special(server, data);
209
615
  }
210
1.64k
  g_free(params);
211
1.64k
}
212
213
static void event_whois_usermode(IRC_SERVER_REC *server, const char *data)
214
816
{
215
816
  char *params, *txt_usermodes, *nick, *usermode;
216
217
816
  g_return_if_fail(data != NULL);
218
219
816
  params = event_get_params(data, 4, NULL, &txt_usermodes,
220
816
          &nick, &usermode);
221
222
816
  if (g_strcmp0(txt_usermodes, "usermodes") == 0) {
223
    /* <yournick> usermodes <nick> usermode */
224
262
    printformat(server, nick, MSGLEVEL_CRAP,
225
262
          IRCTXT_WHOIS_USERMODE, nick, usermode);
226
554
  } else {
227
554
    event_whois_special(server, data);
228
554
  }
229
816
  g_free(params);
230
816
}
231
232
static void hide_safe_channel_id(IRC_SERVER_REC *server, char *chans)
233
1.17k
{
234
1.17k
  const char *idchan, *nick_flags;
235
1.17k
  char *p, *dest, *end, id;
236
1.17k
  int count, length, chanstart;
237
238
1.17k
  if (!server->isupport_sent)
239
828
    idchan = "!:5";
240
348
  else {
241
348
    idchan = g_hash_table_lookup(server->isupport, "IDCHAN");
242
348
    if (idchan == NULL)
243
348
      return;
244
348
  }
245
828
  nick_flags = server->get_nick_flags(SERVER(server));
246
247
1.65k
  while (*idchan != '\0') {
248
828
    id = *idchan;
249
828
    if (idchan[1] != ':')
250
0
      return;
251
252
828
    length = strtoul(idchan+2, &end, 10);
253
828
    if (*end == ',')
254
0
      end++;
255
828
    else if (*end != '\0')
256
0
      return;
257
828
    idchan = end;
258
259
828
    count = 0;
260
828
    chanstart = TRUE;
261
53.8k
    for (dest = p = chans; *p != '\0'; p++) {
262
53.0k
      if (count > 0)
263
1.28k
        count--;
264
51.7k
      else {
265
51.7k
        if (*p == ' ')
266
23.8k
          chanstart = TRUE;
267
27.8k
        else {
268
27.8k
          if (chanstart && *p == id)
269
259
            count = length;
270
27.8k
          chanstart = chanstart && strchr(nick_flags, *p);
271
27.8k
        }
272
51.7k
        *dest++ = *p;
273
51.7k
      }
274
53.0k
    }
275
828
    *dest = '\0';
276
828
  }
277
828
}
278
279
static void event_whois_channels(IRC_SERVER_REC *server, const char *data)
280
1.17k
{
281
1.17k
  char *params, *nick, *chans, *recoded;
282
283
1.17k
  g_return_if_fail(data != NULL);
284
285
1.17k
  params = event_get_params(data, 3, NULL, &nick, &chans);
286
287
  /* sure - we COULD print the channel names as-is, but since the
288
     colors, bolds, etc. are mostly just to fool people, I think we
289
     should show the channel names as they REALLY are so they could
290
     even be joined without any extra tricks. */
291
1.17k
  chans = show_lowascii(chans);
292
1.17k
  if (settings_get_bool("whois_hide_safe_channel_id"))
293
1.17k
    hide_safe_channel_id(server, chans);
294
1.17k
  recoded = recode_in(SERVER(server), chans, nick);
295
1.17k
  printformat(server, nick, MSGLEVEL_CRAP,
296
1.17k
        IRCTXT_WHOIS_CHANNELS, nick, recoded);
297
1.17k
  g_free(chans);
298
299
1.17k
  g_free(params);
300
1.17k
  g_free(recoded);
301
1.17k
}
302
303
static void event_whois_away(IRC_SERVER_REC *server, const char *data)
304
0
{
305
0
  char *params, *nick, *awaymsg, *recoded;
306
307
0
  g_return_if_fail(data != NULL);
308
309
0
  params = event_get_params(data, 3, NULL, &nick, &awaymsg);
310
0
  recoded = recode_in(SERVER(server), awaymsg, nick);
311
0
  printformat(server, nick, MSGLEVEL_CRAP,
312
0
        IRCTXT_WHOIS_AWAY, nick, recoded);
313
0
  g_free(params);
314
0
  g_free(recoded);
315
0
}
316
317
static void event_end_of_whois(IRC_SERVER_REC *server, const char *data)
318
1.51k
{
319
1.51k
  char *params, *nick;
320
321
1.51k
  g_return_if_fail(data != NULL);
322
323
1.51k
  params = event_get_params(data, 2, NULL, &nick);
324
1.51k
  if (server->whois_found) {
325
0
    printformat(server, nick, MSGLEVEL_CRAP,
326
0
          IRCTXT_END_OF_WHOIS, nick);
327
0
  }
328
1.51k
  g_free(params);
329
1.51k
}
330
331
static void event_whois_auth(IRC_SERVER_REC *server, const char *data)
332
324
{
333
324
  char *params, *nick, *text;
334
335
324
  g_return_if_fail(data != NULL);
336
337
324
  params = event_get_params(data, 3, NULL, &nick, &text);
338
324
  printformat(server, nick, MSGLEVEL_CRAP,
339
324
        IRCTXT_WHOIS_EXTRA, nick, text);
340
324
  g_free(params);
341
324
}
342
343
static void event_whowas(IRC_SERVER_REC *server, const char *data)
344
3.15k
{
345
3.15k
  char *params, *nick, *user, *host, *realname, *recoded;
346
347
3.15k
  g_return_if_fail(data != NULL);
348
349
3.15k
  params = event_get_params(data, 6, NULL, &nick, &user,
350
3.15k
          &host, NULL, &realname);
351
3.15k
  recoded = recode_in(SERVER(server), realname, nick);
352
3.15k
  printformat(server, nick, MSGLEVEL_CRAP,
353
3.15k
        IRCTXT_WHOWAS, nick, user, host, recoded);
354
3.15k
  g_free(params);
355
3.15k
  g_free(recoded);
356
3.15k
}
357
358
static void event_end_of_whowas(IRC_SERVER_REC *server, const char *data)
359
294
{
360
294
  char *params, *nick;
361
362
294
  g_return_if_fail(data != NULL);
363
364
294
  params = event_get_params(data, 2, NULL, &nick);
365
294
  if (server->whowas_found) {
366
0
    printformat(server, nick, MSGLEVEL_CRAP,
367
0
          IRCTXT_END_OF_WHOWAS, nick);
368
0
  }
369
294
  g_free(params);
370
294
}
371
372
struct whois_event_table {
373
  int num;
374
  void (*func)(IRC_SERVER_REC *, const char *);
375
};
376
377
static struct whois_event_table events[] = {
378
  { 312, event_whois_server },
379
  { 326, event_whois_usermode326 },
380
  { 327, event_whois_realhost327 },
381
  { 338, event_whois_realhost338 },
382
  { 379, event_whois_modes },
383
  { 378, event_whois_realhost },
384
  { 377, event_whois_usermode },
385
  { 317, event_whois_idle },
386
  { 330, event_whois_auth },
387
  { 319, event_whois_channels },
388
  { 0, NULL }
389
};
390
391
static void event_whois_default(IRC_SERVER_REC *server, const char *data)
392
0
{
393
0
  int i, num;
394
395
0
  num = atoi(current_server_event);
396
0
  for (i = 0; events[i].num != 0; i++) {
397
0
    if (events[i].num == num) {
398
0
      events[i].func(server, data);
399
0
      return;
400
0
    }
401
0
  }
402
403
0
  event_whois_special(server, data);
404
0
}
405
406
void fe_whois_init(void)
407
2
{
408
2
  settings_add_bool("lookandfeel", "whois_hide_safe_channel_id", TRUE);
409
410
2
  signal_add("event 311", (SIGNAL_FUNC) event_whois);
411
2
  signal_add("event 312", (SIGNAL_FUNC) event_whois_server);
412
  /* readding this events fixes the printing of /whois -yes *
413
     Bug http://bugs.irssi.org/?do=details&task_id=123 */
414
2
  signal_add("event 317", (SIGNAL_FUNC) event_whois_idle);
415
2
  signal_add("event 319", (SIGNAL_FUNC) event_whois_channels);
416
2
  signal_add("event 313", (SIGNAL_FUNC) event_whois_oper);
417
2
  signal_add("event 330", (SIGNAL_FUNC) event_whois_auth);
418
2
  signal_add("whois account", (SIGNAL_FUNC) event_whois_auth);
419
2
  signal_add("event 377", (SIGNAL_FUNC) event_whois_usermode);
420
2
  signal_add("event 378", (SIGNAL_FUNC) event_whois_realhost);
421
2
  signal_add("event 379", (SIGNAL_FUNC) event_whois_modes);
422
2
  signal_add("event 327", (SIGNAL_FUNC) event_whois_realhost327);
423
2
  signal_add("event 326", (SIGNAL_FUNC) event_whois_usermode326);
424
2
  signal_add("event 338", (SIGNAL_FUNC) event_whois_realhost338);
425
2
  signal_add("whois away", (SIGNAL_FUNC) event_whois_away);
426
2
  signal_add("whois oper", (SIGNAL_FUNC) event_whois_oper);
427
2
  signal_add("whowas away", (SIGNAL_FUNC) event_whois_away);
428
2
  signal_add("whois default event", (SIGNAL_FUNC) event_whois_default);
429
2
  signal_add("event 318", (SIGNAL_FUNC) event_end_of_whois);
430
2
  signal_add("event 314", (SIGNAL_FUNC) event_whowas);
431
2
  signal_add("event 369", (SIGNAL_FUNC) event_end_of_whowas);
432
2
}
433
434
void fe_whois_deinit(void)
435
0
{
436
0
  signal_remove("event 311", (SIGNAL_FUNC) event_whois);
437
0
  signal_remove("event 312", (SIGNAL_FUNC) event_whois_server);
438
0
  signal_remove("event 317", (SIGNAL_FUNC) event_whois_idle);
439
0
  signal_remove("event 319", (SIGNAL_FUNC) event_whois_channels);
440
0
  signal_remove("event 313", (SIGNAL_FUNC) event_whois_oper);
441
0
  signal_remove("event 330", (SIGNAL_FUNC) event_whois_auth);
442
0
  signal_remove("whois account", (SIGNAL_FUNC) event_whois_auth);
443
0
  signal_remove("event 377", (SIGNAL_FUNC) event_whois_usermode);
444
0
  signal_remove("event 378", (SIGNAL_FUNC) event_whois_realhost);
445
0
  signal_remove("event 379", (SIGNAL_FUNC) event_whois_modes);
446
0
  signal_remove("event 327", (SIGNAL_FUNC) event_whois_realhost327);
447
0
  signal_remove("event 326", (SIGNAL_FUNC) event_whois_usermode326);
448
0
  signal_remove("event 338", (SIGNAL_FUNC) event_whois_realhost338);
449
0
  signal_remove("whois away", (SIGNAL_FUNC) event_whois_away);
450
0
  signal_remove("whois oper", (SIGNAL_FUNC) event_whois_oper);
451
0
  signal_remove("whowas away", (SIGNAL_FUNC) event_whois_away);
452
0
  signal_remove("whois default event", (SIGNAL_FUNC) event_whois_default);
453
0
  signal_remove("event 318", (SIGNAL_FUNC) event_end_of_whois);
454
0
  signal_remove("event 314", (SIGNAL_FUNC) event_whowas);
455
0
  signal_remove("event 369", (SIGNAL_FUNC) event_end_of_whowas);
456
0
}