Coverage Report

Created: 2026-01-10 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/irssi/src/core/servers-setup.c
Line
Count
Source
1
/*
2
 servers-setup.c : irssi
3
4
    Copyright (C) 1999-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 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/signals.h>
23
#include <irssi/src/core/network.h>
24
#include <irssi/src/lib-config/iconfig.h>
25
#include <irssi/src/core/settings.h>
26
27
#include <irssi/src/core/chat-protocols.h>
28
#include <irssi/src/core/chatnets.h>
29
#include <irssi/src/core/servers.h>
30
#include <irssi/src/core/servers-setup.h>
31
32
GSList *setupservers;
33
34
static char *old_source_host;
35
int source_host_ok; /* Use source_host_ip .. */
36
IPADDR *source_host_ip4, *source_host_ip6; /* Resolved address */
37
38
static void save_ips(IPADDR *ip4, IPADDR *ip6,
39
         IPADDR **save_ip4, IPADDR **save_ip6)
40
0
{
41
0
  if (ip4->family == 0)
42
0
    g_free_and_null(*save_ip4);
43
0
  else {
44
0
                if (*save_ip4 == NULL)
45
0
      *save_ip4 = g_new(IPADDR, 1);
46
0
    memcpy(*save_ip4, ip4, sizeof(IPADDR));
47
0
  }
48
49
0
  if (ip6->family == 0)
50
0
    g_free_and_null(*save_ip6);
51
0
  else {
52
0
                if (*save_ip6 == NULL)
53
0
      *save_ip6 = g_new(IPADDR, 1);
54
0
    memcpy(*save_ip6, ip6, sizeof(IPADDR));
55
0
  }
56
0
}
57
58
static void get_source_host_ip(void)
59
8
{
60
8
        const char *hostname;
61
8
  IPADDR ip4, ip6;
62
63
8
  if (source_host_ok)
64
0
    return;
65
66
  /* FIXME: This will block! */
67
8
        hostname = settings_get_str("hostname");
68
8
  source_host_ok = *hostname != '\0' &&
69
0
    net_gethostbyname(hostname, &ip4, &ip6) == 0;
70
71
8
  if (source_host_ok)
72
0
    save_ips(&ip4, &ip6, &source_host_ip4, &source_host_ip6);
73
8
  else {
74
8
                g_free_and_null(source_host_ip4);
75
8
                g_free_and_null(source_host_ip6);
76
8
  }
77
8
}
78
79
static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host,
80
      IPADDR **own_ip4, IPADDR **own_ip6)
81
0
{
82
0
  IPADDR ip4, ip6;
83
84
0
  if (*own_ip4 == NULL && *own_ip6 == NULL) {
85
    /* resolve the IP */
86
0
    if (net_gethostbyname(own_host, &ip4, &ip6) == 0)
87
0
                        save_ips(&ip4, &ip6, own_ip4, own_ip6);
88
0
  }
89
90
0
  server_connect_own_ip_save(conn, *own_ip4, *own_ip6);
91
0
}
92
93
/* Fill information to connection from server setup record */
94
void server_setup_fill_reconn(SERVER_CONNECT_REC *conn,
95
            SERVER_SETUP_REC *sserver)
96
0
{
97
0
  g_return_if_fail(IS_SERVER_CONNECT(conn));
98
0
  g_return_if_fail(IS_SERVER_SETUP(sserver));
99
100
0
  if (sserver->own_host != NULL) {
101
0
    conn_set_ip(conn, sserver->own_host,
102
0
          &sserver->own_ip4, &sserver->own_ip6);
103
0
  }
104
105
0
  if (sserver->chatnet != NULL && conn->chatnet == NULL)
106
0
    conn->chatnet = g_strdup(sserver->chatnet);
107
108
0
  if (sserver->password != NULL && conn->password == NULL)
109
0
    conn->password = g_strdup(sserver->password);
110
111
0
  if (sserver->no_proxy)
112
0
    g_free_and_null(conn->proxy);
113
114
0
  if (sserver->family != 0 && conn->family == 0)
115
0
    conn->family = sserver->family;
116
0
  if (sserver->address && !conn->address)
117
0
    conn->address = g_strdup(sserver->address);
118
0
  if (sserver->port > 0 && conn->port <= 0)
119
0
    conn->port = sserver->port;
120
121
0
  conn->use_tls = sserver->use_tls;
122
0
  if (conn->tls_cert == NULL && sserver->tls_cert != NULL && sserver->tls_cert[0] != '\0')
123
0
    conn->tls_cert = g_strdup(sserver->tls_cert);
124
0
  if (conn->tls_pkey == NULL && sserver->tls_pkey != NULL && sserver->tls_pkey[0] != '\0')
125
0
    conn->tls_pkey = g_strdup(sserver->tls_pkey);
126
0
  if (conn->tls_pass == NULL && sserver->tls_pass != NULL && sserver->tls_pass[0] != '\0')
127
0
    conn->tls_pass = g_strdup(sserver->tls_pass);
128
0
  conn->tls_verify = sserver->tls_verify;
129
0
  if (conn->tls_cafile == NULL && sserver->tls_cafile != NULL && sserver->tls_cafile[0] != '\0')
130
0
    conn->tls_cafile = g_strdup(sserver->tls_cafile);
131
0
  if (conn->tls_capath == NULL && sserver->tls_capath != NULL && sserver->tls_capath[0] != '\0')
132
0
    conn->tls_capath = g_strdup(sserver->tls_capath);
133
0
  if (conn->tls_ciphers == NULL && sserver->tls_ciphers != NULL && sserver->tls_ciphers[0] != '\0')
134
0
    conn->tls_ciphers = g_strdup(sserver->tls_ciphers);
135
0
  if (conn->tls_pinned_cert == NULL && sserver->tls_pinned_cert != NULL && sserver->tls_pinned_cert[0] != '\0')
136
0
    conn->tls_pinned_cert = g_strdup(sserver->tls_pinned_cert);
137
0
  if (conn->tls_pinned_pubkey == NULL && sserver->tls_pinned_pubkey != NULL && sserver->tls_pinned_pubkey[0] != '\0')
138
0
    conn->tls_pinned_pubkey = g_strdup(sserver->tls_pinned_pubkey);
139
140
0
  signal_emit("server setup fill reconn", 2, conn, sserver);
141
0
}
142
143
static void server_setup_fill(SERVER_CONNECT_REC *conn, const char *address, int port,
144
                              GHashTable *optlist)
145
6.59k
{
146
6.59k
  g_return_if_fail(conn != NULL);
147
6.59k
  g_return_if_fail(address != NULL);
148
149
6.59k
  conn->type = module_get_uniq_id("SERVER CONNECT", 0);
150
151
6.59k
  conn->address = g_strdup(address);
152
6.59k
  if (port > 0) conn->port = port;
153
154
6.59k
  if (strchr(address, '/') != NULL)
155
0
    conn->unix_socket = TRUE;
156
157
6.59k
  if (!conn->nick) conn->nick = g_strdup(settings_get_str("nick"));
158
6.59k
  conn->username = g_strdup(settings_get_str("user_name"));
159
6.59k
  conn->realname = g_strdup(settings_get_str("real_name"));
160
161
  /* proxy settings */
162
6.59k
  if (settings_get_bool("use_proxy")) {
163
0
    conn->proxy = g_strdup(settings_get_str("proxy_address"));
164
0
    conn->proxy_port = settings_get_int("proxy_port");
165
0
    conn->proxy_string = g_strdup(settings_get_str("proxy_string"));
166
0
    conn->proxy_string_after = g_strdup(settings_get_str("proxy_string_after"));
167
0
    conn->proxy_password = g_strdup(settings_get_str("proxy_password"));
168
0
  }
169
170
  /* source IP */
171
6.59k
  if (source_host_ip4 != NULL) {
172
0
    conn->own_ip4 = g_new(IPADDR, 1);
173
0
    memcpy(conn->own_ip4, source_host_ip4, sizeof(IPADDR));
174
0
  }
175
6.59k
  if (source_host_ip6 != NULL) {
176
0
    conn->own_ip6 = g_new(IPADDR, 1);
177
0
    memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR));
178
0
  }
179
180
6.59k
  signal_emit("server setup fill connect", 2, conn, optlist);
181
6.59k
}
182
183
static void server_setup_fill_optlist(SERVER_CONNECT_REC *conn, GHashTable *optlist)
184
0
{
185
0
  char *tmp;
186
187
0
  if (g_hash_table_lookup(optlist, "6") != NULL)
188
0
    conn->family = AF_INET6;
189
0
  else if (g_hash_table_lookup(optlist, "4") != NULL)
190
0
    conn->family = AF_INET;
191
192
  /* ad-hoc TLS settings from command optlist */
193
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_cert")) != NULL ||
194
0
      (tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL) {
195
0
    conn->tls_cert = g_strdup(tmp);
196
0
    conn->use_tls = TRUE;
197
0
  }
198
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_pkey")) != NULL ||
199
0
      (tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL)
200
0
    conn->tls_pkey = g_strdup(tmp);
201
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_pass")) != NULL ||
202
0
      (tmp = g_hash_table_lookup(optlist, "ssl_pass")) != NULL)
203
0
    conn->tls_pass = g_strdup(tmp);
204
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_cafile")) != NULL ||
205
0
      (tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL)
206
0
    conn->tls_cafile = g_strdup(tmp);
207
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_capath")) != NULL ||
208
0
      (tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL)
209
0
    conn->tls_capath = g_strdup(tmp);
210
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_ciphers")) != NULL ||
211
0
      (tmp = g_hash_table_lookup(optlist, "ssl_ciphers")) != NULL)
212
0
    conn->tls_ciphers = g_strdup(tmp);
213
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_cert")) != NULL ||
214
0
      (tmp = g_hash_table_lookup(optlist, "ssl_pinned_cert")) != NULL)
215
0
    conn->tls_pinned_cert = g_strdup(tmp);
216
0
  if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_pubkey")) != NULL ||
217
0
      (tmp = g_hash_table_lookup(optlist, "ssl_pinned_pubkey")) != NULL)
218
0
    conn->tls_pinned_pubkey = g_strdup(tmp);
219
0
  if ((conn->tls_capath != NULL && conn->tls_capath[0] != '\0') ||
220
0
      (conn->tls_cafile != NULL && conn->tls_cafile[0] != '\0'))
221
0
    conn->tls_verify = TRUE;
222
0
  if (g_hash_table_lookup(optlist, "notls_verify") != NULL)
223
0
    conn->tls_verify = FALSE;
224
0
  if (g_hash_table_lookup(optlist, "tls_verify") != NULL ||
225
0
      g_hash_table_lookup(optlist, "ssl_verify") != NULL) {
226
0
    conn->tls_verify = TRUE;
227
0
    conn->use_tls = TRUE;
228
0
  }
229
0
  if (g_hash_table_lookup(optlist, "notls") != NULL)
230
0
    conn->use_tls = FALSE;
231
0
  if (g_hash_table_lookup(optlist, "tls") != NULL ||
232
0
      g_hash_table_lookup(optlist, "ssl") != NULL)
233
0
    conn->use_tls = TRUE;
234
235
0
  if (g_hash_table_lookup(optlist, "!") != NULL)
236
0
    conn->no_autojoin_channels = TRUE;
237
238
0
  if (g_hash_table_lookup(optlist, "noautosendcmd") != NULL)
239
0
    conn->no_autosendcmd = TRUE;
240
241
0
  if (g_hash_table_lookup(optlist, "noproxy") != NULL)
242
0
    g_free_and_null(conn->proxy);
243
244
0
  signal_emit("server setup fill optlist", 2, conn, optlist);
245
0
}
246
247
static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
248
             SERVER_SETUP_REC *sserver)
249
0
{
250
0
  g_return_if_fail(IS_SERVER_CONNECT(conn));
251
0
  g_return_if_fail(IS_SERVER_SETUP(sserver));
252
253
0
  sserver->last_connect = time(NULL);
254
255
0
  server_setup_fill_reconn(conn, sserver);
256
257
0
  signal_emit("server setup fill server", 2, conn, sserver);
258
0
}
259
260
static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
261
              CHATNET_REC *chatnet)
262
0
{
263
0
  g_return_if_fail(IS_SERVER_CONNECT(conn));
264
0
  g_return_if_fail(IS_CHATNET(chatnet));
265
266
0
  if (chatnet->nick != NULL) {
267
0
    g_free(conn->nick);
268
0
    conn->nick = g_strdup(chatnet->nick);;
269
0
  }
270
0
  if (chatnet->username != NULL) {
271
0
                g_free(conn->username);
272
0
    conn->username = g_strdup(chatnet->username);;
273
0
  }
274
0
  if (chatnet->realname != NULL) {
275
0
                g_free(conn->realname);
276
0
    conn->realname = g_strdup(chatnet->realname);;
277
0
  }
278
0
  if (chatnet->own_host != NULL) {
279
0
    conn_set_ip(conn, chatnet->own_host,
280
0
          &chatnet->own_ip4, &chatnet->own_ip6);
281
0
  }
282
283
0
  signal_emit("server setup fill chatnet", 2, conn, chatnet);
284
0
}
285
286
static SERVER_CONNECT_REC *create_addr_conn(int chat_type, const char *address, int port,
287
                                            const char *chatnet, const char *password,
288
                                            const char *nick, GHashTable *optlist)
289
6.59k
{
290
6.59k
        CHAT_PROTOCOL_REC *proto;
291
6.59k
  SERVER_CONNECT_REC *conn;
292
6.59k
  SERVER_SETUP_REC *sserver;
293
6.59k
  CHATNET_REC *chatnetrec;
294
295
6.59k
  g_return_val_if_fail(address != NULL, NULL);
296
297
6.59k
  sserver = server_setup_find(address, port, chatnet);
298
6.59k
  if (sserver != NULL) {
299
0
    if (chat_type < 0)
300
0
      chat_type = sserver->chat_type;
301
0
    else if (chat_type != sserver->chat_type)
302
0
                        sserver = NULL;
303
0
  }
304
305
6.59k
  proto = chat_type >= 0 ? chat_protocol_find_id(chat_type) :
306
6.59k
                chat_protocol_get_default();
307
308
6.59k
  if (proto == NULL) {
309
0
    signal_stop();
310
0
    return NULL;
311
0
  }
312
313
6.59k
  g_return_val_if_fail(proto != NULL, NULL);
314
315
6.59k
  conn = proto->create_server_connect();
316
6.59k
  server_connect_ref(conn);
317
318
6.59k
  conn->chat_type = proto->id;
319
6.59k
        if (chatnet != NULL && *chatnet != '\0')
320
0
    conn->chatnet = g_strdup(chatnet);
321
322
  /* fill in the defaults */
323
6.59k
  server_setup_fill(conn, address, port, optlist);
324
325
  /* fill the rest from chat network settings */
326
6.59k
  chatnetrec = chatnet != NULL ? chatnet_find(chatnet) :
327
6.59k
    (sserver == NULL || sserver->chatnet == NULL ? NULL :
328
0
     chatnet_find(sserver->chatnet));
329
6.59k
  if (chatnetrec != NULL)
330
0
    server_setup_fill_chatnet(conn, chatnetrec);
331
332
  /* fill the information from setup */
333
6.59k
  if (sserver != NULL)
334
0
    server_setup_fill_server(conn, sserver);
335
336
  /* fill the optlist overrides */
337
6.59k
  if (g_hash_table_size(optlist))
338
0
    server_setup_fill_optlist(conn, optlist);
339
340
  /* nick / password given in command line overrides all settings */
341
6.59k
  if (password && *password) {
342
0
    g_free_not_null(conn->password);
343
0
    conn->password = g_strdup(password);
344
0
  }
345
6.59k
  if (nick && *nick) {
346
6.59k
    g_free_not_null(conn->nick);
347
6.59k
    conn->nick = g_strdup(nick);
348
6.59k
  }
349
350
6.59k
  return conn;
351
6.59k
}
352
353
/* Connect to server where last connect succeeded (or we haven't tried to
354
   connect yet). If there's no such server, connect to server where we
355
   haven't connected for the longest time */
356
static SERVER_CONNECT_REC *create_chatnet_conn(const char *dest, int port, const char *password,
357
                                               const char *nick, GHashTable *optlist)
358
0
{
359
0
  SERVER_SETUP_REC *bestrec;
360
0
  GSList *tmp;
361
0
  time_t now, besttime;
362
363
0
  now = time(NULL);
364
0
  bestrec = NULL; besttime = now;
365
0
  for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
366
0
    SERVER_SETUP_REC *rec = tmp->data;
367
368
0
    if (rec->chatnet == NULL ||
369
0
        g_ascii_strcasecmp(rec->chatnet, dest) != 0)
370
0
      continue;
371
372
0
    if (!rec->last_failed) {
373
0
      bestrec = rec;
374
0
      break;
375
0
    }
376
377
0
    if (bestrec == NULL || besttime > rec->last_connect) {
378
0
      bestrec = rec;
379
0
      besttime = rec->last_connect;
380
0
    }
381
0
  }
382
383
0
  return bestrec == NULL ? NULL :
384
0
                                 create_addr_conn(bestrec->chat_type, bestrec->address, 0, dest,
385
0
                                            NULL, nick, optlist);
386
0
}
387
388
/* Create server connection record. `dest' is required, rest can be NULL.
389
   `dest' is either a server address or chat network */
390
SERVER_CONNECT_REC *server_create_conn_opt(int chat_type, const char *dest, int port,
391
                                           const char *chatnet, const char *password,
392
                                           const char *nick, GHashTable *optlist)
393
6.59k
{
394
6.59k
  SERVER_CONNECT_REC *rec;
395
6.59k
        CHATNET_REC *chatrec;
396
397
6.59k
  g_return_val_if_fail(dest != NULL, NULL);
398
399
6.59k
        chatrec = chatnet_find(dest);
400
6.59k
  if (chatrec != NULL) {
401
0
    rec = create_chatnet_conn(chatrec->name, port, password, nick, optlist);
402
    /* If rec is NULL the chatnet has no url to connect to */
403
0
    return rec;
404
0
  }
405
406
6.59k
  chatrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
407
6.59k
  if (chatrec != NULL)
408
0
    chatnet = chatrec->name;
409
410
6.59k
  return create_addr_conn(chat_type, dest, port, chatnet, password, nick, optlist);
411
6.59k
}
412
413
SERVER_CONNECT_REC *server_create_conn(int chat_type, const char *dest, int port,
414
                                       const char *chatnet, const char *password, const char *nick)
415
6.59k
{
416
6.59k
  SERVER_CONNECT_REC *ret;
417
6.59k
  GHashTable *opt;
418
419
6.59k
  opt = g_hash_table_new(NULL, NULL);
420
6.59k
  ret = server_create_conn_opt(chat_type, dest, port, chatnet, password, nick, opt);
421
6.59k
  g_hash_table_destroy(opt);
422
423
6.59k
  return ret;
424
6.59k
}
425
426
/* Find matching server from setup. Try to find record with a same port,
427
   but fallback to any server with the same address. */
428
SERVER_SETUP_REC *server_setup_find(const char *address, int port,
429
            const char *chatnet)
430
13.0k
{
431
13.0k
  SERVER_SETUP_REC *server;
432
13.0k
  GSList *tmp;
433
434
13.0k
  g_return_val_if_fail(address != NULL, NULL);
435
436
13.0k
  server = NULL;
437
181k
  for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
438
168k
    SERVER_SETUP_REC *rec = tmp->data;
439
440
168k
    if (g_ascii_strcasecmp(rec->address, address) == 0 &&
441
0
        (chatnet == NULL || rec->chatnet == NULL ||
442
0
         g_ascii_strcasecmp(rec->chatnet, chatnet) == 0)) {
443
0
      server = rec;
444
0
      if (rec->port == port)
445
0
        break;
446
0
    }
447
168k
  }
448
449
13.0k
  return server;
450
13.0k
}
451
452
static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
453
28
{
454
28
  SERVER_SETUP_REC *rec;
455
28
  CHATNET_REC *chatnetrec;
456
28
  CHAT_PROTOCOL_REC *proto;
457
28
  char *server, *chatnet, *family;
458
28
  int port;
459
28
  char *value = NULL;
460
461
28
  g_return_val_if_fail(node != NULL, NULL);
462
463
28
  server = config_node_get_str(node, "address", NULL);
464
28
  if (server == NULL)
465
0
    return NULL;
466
467
28
  port = config_node_get_int(node, "port", 0);
468
28
  chatnet = config_node_get_str(node, "chatnet", NULL);
469
470
28
  if ((rec = server_setup_find(server, port, chatnet)) != NULL && rec->port == port) {
471
    /* duplicate server setup */
472
0
    server_setup_remove(rec);
473
0
  }
474
475
28
  rec = NULL;
476
477
28
  if (chatnet != NULL) {
478
28
    chatnetrec = chatnet_find(chatnet);
479
28
    if (chatnetrec != NULL) {
480
26
      proto = CHAT_PROTOCOL(chatnetrec);
481
26
    } else {
482
      /* chat network not found, create it. */
483
2
      if (chatnet_find_unavailable(chatnet)) {
484
        /* no protocols loaded, skip loading servers */
485
2
        return NULL;
486
2
      }
487
0
      proto = chat_protocol_get_default();
488
0
      chatnetrec = proto->create_chatnet();
489
0
      chatnetrec->chat_type = chat_protocol_get_default()->id;
490
0
      chatnetrec->name = g_strdup(chatnet);
491
0
      chatnet_create(chatnetrec);
492
0
    }
493
28
  } else {
494
0
    chatnetrec = NULL;
495
0
    proto = chat_protocol_get_default();
496
0
    if (proto == NULL) {
497
      /* no protocols loaded, skip loading servers */
498
0
      return NULL;
499
0
    }
500
0
  }
501
502
26
  family = config_node_get_str(node, "family", "");
503
504
26
  rec = proto->create_server_setup();
505
26
  rec->type = module_get_uniq_id("SERVER SETUP", 0);
506
26
  rec->chat_type = proto->id;
507
26
  rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name);
508
26
  rec->family = g_ascii_strcasecmp(family, "inet6") == 0 ?
509
26
                    AF_INET6 :
510
26
                    (g_ascii_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
511
26
  rec->address = g_strdup(server);
512
26
  rec->password = g_strdup(config_node_get_str(node, "password", NULL));
513
514
26
  rec->use_tls = config_node_get_bool(node, "use_tls", FALSE) || config_node_get_bool(node, "use_ssl", FALSE);
515
26
  rec->tls_verify = config_node_find(node, "tls_verify") != NULL ?
516
12
                              config_node_get_bool(node, "tls_verify", TRUE) :
517
26
                              config_node_get_bool(node, "ssl_verify", TRUE);
518
519
26
  value = config_node_get_str(node, "tls_cert", NULL);
520
26
  if (value == NULL)
521
26
    value = config_node_get_str(node, "ssl_cert", NULL);
522
26
  rec->tls_cert = g_strdup(value);
523
524
26
  value = config_node_get_str(node, "tls_pkey", NULL);
525
26
  if (value == NULL)
526
26
    value = config_node_get_str(node, "ssl_pkey", NULL);
527
26
  rec->tls_pkey = g_strdup(value);
528
529
26
  value = config_node_get_str(node, "tls_pass", NULL);
530
26
  if (value == NULL)
531
26
    value = config_node_get_str(node, "ssl_pass", NULL);
532
26
  rec->tls_pass = g_strdup(value);
533
534
26
  value = config_node_get_str(node, "tls_cafile", NULL);
535
26
  if (value == NULL)
536
26
    value = config_node_get_str(node, "ssl_cafile", NULL);
537
26
  rec->tls_cafile = g_strdup(value);
538
539
26
  value = config_node_get_str(node, "tls_capath", NULL);
540
26
  if (value == NULL)
541
26
    value = config_node_get_str(node, "ssl_capath", NULL);
542
26
  rec->tls_capath = g_strdup(value);
543
544
26
  value = config_node_get_str(node, "tls_ciphers", NULL);
545
26
  if (value == NULL)
546
26
    value = config_node_get_str(node, "ssl_ciphers", NULL);
547
26
  rec->tls_ciphers = g_strdup(value);
548
549
26
  value = config_node_get_str(node, "tls_pinned_cert", NULL);
550
26
  if (value == NULL)
551
26
    value = config_node_get_str(node, "ssl_pinned_cert", NULL);
552
26
  rec->tls_pinned_cert = g_strdup(value);
553
554
26
  value = config_node_get_str(node, "tls_pinned_pubkey", NULL);
555
26
  if (value == NULL)
556
26
    value = config_node_get_str(node, "ssl_pinned_pubkey", NULL);
557
26
  rec->tls_pinned_pubkey = g_strdup(value);
558
559
26
  rec->port = port;
560
26
  rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
561
26
  rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
562
26
  rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL));
563
564
26
  signal_emit("server setup read", 2, rec, node);
565
566
26
  setupservers = g_slist_append(setupservers, rec);
567
26
  return rec;
568
28
}
569
570
static int compare_server_setup (CONFIG_NODE *node, SERVER_SETUP_REC *server)
571
0
{
572
0
  char *address, *chatnet;
573
0
  int port;
574
575
  /* skip comment nodes */
576
0
  if (node->type == NODE_TYPE_COMMENT)
577
0
    return -1;
578
579
0
  address = config_node_get_str(node, "address", NULL);
580
0
  chatnet = config_node_get_str(node, "chatnet", "");
581
0
  port = config_node_get_int(node, "port", 0);
582
583
0
  if (address == NULL || chatnet == NULL) {
584
0
    return 0;
585
0
  }
586
587
0
  if (g_ascii_strcasecmp(address, server->address) != 0 ||
588
0
      g_ascii_strcasecmp(chatnet, server->chatnet != NULL ? server->chatnet : "") != 0 ||
589
0
      port != server->port) {
590
0
    return 1;
591
0
  }
592
593
0
  return 0;
594
0
}
595
596
static void server_setup_save(SERVER_SETUP_REC *rec, int old_port, const char *old_chatnet)
597
0
{
598
0
  CONFIG_NODE *parent_node, *node;
599
0
  SERVER_SETUP_REC search_rec = { 0 };
600
0
  GSList *config_node;
601
602
0
  parent_node = iconfig_node_traverse("(servers", TRUE);
603
604
  /* Try to find this channel in the configuration */
605
0
  search_rec.address = rec->address;
606
0
  search_rec.chatnet = old_chatnet != NULL ? (char *) old_chatnet : rec->chatnet;
607
0
  search_rec.port = old_port;
608
0
  config_node = g_slist_find_custom(parent_node->value, &search_rec,
609
0
                                    (GCompareFunc) compare_server_setup);
610
0
  if (config_node != NULL)
611
    /* Let's update this server record */
612
0
    node = config_node->data;
613
0
  else
614
    /* Create a brand-new server record */
615
0
    node = iconfig_node_section(parent_node, NULL, NODE_TYPE_BLOCK);
616
617
0
        iconfig_node_clear(node);
618
0
  iconfig_node_set_str(node, "address", rec->address);
619
0
  iconfig_node_set_str(node, "chatnet", rec->chatnet);
620
621
0
  iconfig_node_set_int(node, "port", rec->port);
622
0
  iconfig_node_set_str(node, "password", rec->password);
623
624
0
  iconfig_node_set_bool(node, "use_tls", rec->use_tls);
625
0
  iconfig_node_set_str(node, "tls_cert", rec->tls_cert);
626
0
  iconfig_node_set_str(node, "tls_pkey", rec->tls_pkey);
627
0
  iconfig_node_set_str(node, "tls_pass", rec->tls_pass);
628
0
  iconfig_node_set_bool(node, "tls_verify", rec->tls_verify);
629
0
  iconfig_node_set_str(node, "tls_cafile", rec->tls_cafile);
630
0
  iconfig_node_set_str(node, "tls_capath", rec->tls_capath);
631
0
  iconfig_node_set_str(node, "tls_ciphers", rec->tls_ciphers);
632
0
  iconfig_node_set_str(node, "tls_pinned_cert", rec->tls_pinned_cert);
633
0
  iconfig_node_set_str(node, "tls_pinned_pubkey", rec->tls_pinned_pubkey);
634
635
0
  iconfig_node_set_str(node, "own_host", rec->own_host);
636
637
0
  iconfig_node_set_str(node, "family",
638
0
           rec->family == AF_INET6 ? "inet6" :
639
0
           rec->family == AF_INET ? "inet" : NULL);
640
641
0
  if (rec->autoconnect)
642
0
    iconfig_node_set_bool(node, "autoconnect", TRUE);
643
0
  if (rec->no_proxy)
644
0
    iconfig_node_set_bool(node, "no_proxy", TRUE);
645
646
0
  signal_emit("server setup saved", 2, rec, node);
647
0
}
648
649
static void server_setup_remove_config(SERVER_SETUP_REC *rec)
650
0
{
651
0
  CONFIG_NODE *parent_node;
652
0
  GSList *config_node;
653
654
0
  parent_node = iconfig_node_traverse("servers", FALSE);
655
656
0
  if (parent_node == NULL)
657
0
    return;
658
659
  /* Try to find this server in the configuration */
660
0
  config_node = g_slist_find_custom(parent_node->value, rec,
661
0
            (GCompareFunc)compare_server_setup);
662
663
0
  if (config_node != NULL)
664
    /* Delete the server from the configuration */
665
0
    iconfig_node_remove(parent_node, config_node->data);
666
0
}
667
668
static void server_setup_destroy(SERVER_SETUP_REC *rec)
669
0
{
670
0
  setupservers = g_slist_remove(setupservers, rec);
671
0
  signal_emit("server setup destroyed", 1, rec);
672
673
0
  g_free_not_null(rec->own_host);
674
0
  g_free_not_null(rec->own_ip4);
675
0
  g_free_not_null(rec->own_ip6);
676
0
  g_free_not_null(rec->chatnet);
677
0
  g_free_not_null(rec->password);
678
0
  g_free_not_null(rec->tls_cert);
679
0
  g_free_not_null(rec->tls_pkey);
680
0
  g_free_not_null(rec->tls_pass);
681
0
  g_free_not_null(rec->tls_cafile);
682
0
  g_free_not_null(rec->tls_capath);
683
0
  g_free_not_null(rec->tls_ciphers);
684
0
  g_free_not_null(rec->tls_pinned_cert);
685
0
  g_free_not_null(rec->tls_pinned_pubkey);
686
0
  g_free(rec->address);
687
0
  g_free(rec);
688
0
}
689
690
void server_setup_modify(SERVER_SETUP_REC *rec, int old_port, const char *old_chatnet)
691
0
{
692
0
  g_return_if_fail(g_slist_find(setupservers, rec) != NULL);
693
694
0
  rec->type = module_get_uniq_id("SERVER SETUP", 0);
695
0
  server_setup_save(rec, old_port, old_chatnet);
696
697
0
  signal_emit("server setup updated", 1, rec);
698
0
}
699
700
void server_setup_add(SERVER_SETUP_REC *rec)
701
0
{
702
0
  if (g_slist_find(setupservers, rec) == NULL)
703
0
    setupservers = g_slist_append(setupservers, rec);
704
0
  server_setup_modify(rec, -1, NULL);
705
0
}
706
707
void server_setup_remove_chatnet(const char *chatnet)
708
0
{
709
0
  GSList *tmp, *next;
710
711
0
  g_return_if_fail(chatnet != NULL);
712
713
0
  for (tmp = setupservers; tmp != NULL; tmp = next) {
714
0
    SERVER_SETUP_REC *rec = tmp->data;
715
716
0
    next = tmp->next;
717
0
    if (g_ascii_strcasecmp(rec->chatnet, chatnet) == 0)
718
0
      server_setup_remove(rec);
719
0
  }
720
0
}
721
722
void server_setup_remove(SERVER_SETUP_REC *rec)
723
0
{
724
0
  server_setup_remove_config(rec);
725
0
  server_setup_destroy(rec);
726
0
}
727
728
static void read_servers(void)
729
2
{
730
2
  CONFIG_NODE *node;
731
2
  GSList *tmp;
732
733
2
  while (setupservers != NULL)
734
0
    server_setup_destroy(setupservers->data);
735
736
  /* Read servers */
737
2
  node = iconfig_node_traverse("servers", FALSE);
738
2
  if (node != NULL) {
739
2
    int i = 0;
740
2
    tmp = config_node_first(node->value);
741
30
    for (; tmp != NULL; tmp = config_node_next(tmp), i++) {
742
28
      node = tmp->data;
743
28
      if (node->type != NODE_TYPE_BLOCK) {
744
0
        g_critical("Expected block node at `servers[%d]' was of %s type. "
745
0
                   "Corrupt config?",
746
0
                   i, node->type == NODE_TYPE_LIST ? "list" : "scalar");
747
28
      } else {
748
28
        server_setup_read(node);
749
28
      }
750
28
    }
751
2
  }
752
2
}
753
754
static void read_settings(void)
755
8
{
756
8
  if (old_source_host == NULL ||
757
8
      g_strcmp0(old_source_host, settings_get_str("hostname")) != 0) {
758
8
                g_free_not_null(old_source_host);
759
8
    old_source_host = g_strdup(settings_get_str("hostname"));
760
761
8
    source_host_ok = FALSE;
762
8
    get_source_host_ip();
763
8
  }
764
8
}
765
766
void servers_setup_init(void)
767
8
{
768
8
  settings_add_str("server", "hostname", "");
769
770
8
  settings_add_str("server", "nick", NULL);
771
8
  settings_add_str("server", "user_name", NULL);
772
8
  settings_add_str("server", "real_name", NULL);
773
774
8
  settings_add_bool("proxy", "use_proxy", FALSE);
775
8
  settings_add_str("proxy", "proxy_address", "");
776
8
  settings_add_int("proxy", "proxy_port", 6667);
777
8
  settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
778
8
  settings_add_str("proxy", "proxy_string_after", "");
779
8
  settings_add_str("proxy", "proxy_password", "");
780
781
8
        setupservers = NULL;
782
8
  source_host_ip4 = source_host_ip6 = NULL;
783
8
        old_source_host = NULL;
784
8
  read_settings();
785
786
8
  signal_add("setup changed", (SIGNAL_FUNC) read_settings);
787
8
  signal_add("setup reread servers", (SIGNAL_FUNC) read_servers);
788
8
}
789
790
void servers_setup_deinit(void)
791
0
{
792
0
  g_free_not_null(source_host_ip4);
793
0
  g_free_not_null(source_host_ip6);
794
0
  g_free_not_null(old_source_host);
795
796
0
  while (setupservers != NULL)
797
0
    server_setup_destroy(setupservers->data);
798
799
0
  signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
800
0
  signal_remove("setup reread servers", (SIGNAL_FUNC) read_servers);
801
802
0
  module_uniq_destroy("SERVER SETUP");
803
0
}