1 /* Copyright (C) 2016-2018 Shengyu Zhang <i@silverrainz.me>
2  *
3  * This file is part of Srain.
4  *
5  * Srain is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file reader.c
21  * @brief Configuration readers for various config structures
22  * @author Shengyu Zhang <i@silverrainz.me>
23  * @version 0.06.3
24  * @date 2018-02-16
25  */
26 
27 #include <glib.h>
28 #include <libconfig.h>
29 
30 #include "core/core.h"
31 #include "config/config.h"
32 #include "config/password.h"
33 #include "i18n.h"
34 #include "utils.h"
35 #include "log.h"
36 
37 /* Libconfig helpers */
38 static int config_lookup_string_ex(const config_t *config, const char *path, char **value);
39 static int config_setting_lookup_string_ex(const config_setting_t *config, const char *name, char **value);
40 static char* config_setting_get_string_elem_ex(const config_setting_t *setting, int index);
41 static int config_lookup_bool_ex(const config_t *config, const char *name, bool *value);
42 static int config_setting_lookup_bool_ex(const config_setting_t *config, const char *name, bool *value);
43 
44 /* Configuration readers for various config structures */
45 static SrnRet read_log_config_from_cfg(config_t *cfg, SrnLoggerConfig *log_cfg);
46 static SrnRet read_log_targets_from_log(config_setting_t *log, const char *name, GList **lst);
47 
48 static SrnRet read_application_config_from_cfg(config_t *cfg, SrnApplicationConfig *app_cfg);
49 
50 static SrnRet read_server_config_list_from_cfg(config_t *cfg, GList **srv_cfg_list);
51 static SrnRet read_server_config_from_server(config_setting_t *server, SrnServerConfig *cfg);
52 static SrnRet read_server_config_from_server_list(config_setting_t *server_list, SrnServerConfig *cfg, const char *srv_name);
53 static SrnRet read_server_config_from_cfg(config_t *cfg, SrnServerConfig *srv_cfg, const char *srv_name);
54 
55 static SrnRet read_chat_config_from_chat(config_setting_t *chat, SrnChatConfig *cfg);
56 static SrnRet read_chat_config_from_chat_list(config_setting_t *chat_list, SrnChatConfig *cfg, const char *chat_name);
57 static SrnRet read_chat_config_from_cfg(config_t *cfg, SrnChatConfig *chat_cfg, const char *srv_name, const char *chat_name);
58 
59 static SrnRet read_user_config_from_user(config_setting_t *user, SrnUserConfig *cfg);
60 
61 /*****************************************************************************
62  * Exported functions
63  *****************************************************************************/
64 
srn_config_manager_read_log_config(SrnConfigManager * mgr,SrnLoggerConfig * cfg)65 SrnRet srn_config_manager_read_log_config(SrnConfigManager *mgr,
66         SrnLoggerConfig *cfg){
67     SrnRet ret;
68 
69     ret = read_log_config_from_cfg(&mgr->system_cfg, cfg);
70     if (!RET_IS_OK(ret)){
71         return RET_ERR(_("Error occurred while reading log config in %1$s: %2$s"),
72                 config_setting_source_file(config_root_setting(&mgr->system_cfg)),
73                 RET_MSG(ret));
74     }
75     ret = read_log_config_from_cfg(&mgr->user_cfg, cfg);
76     if (!RET_IS_OK(ret)){
77         return RET_ERR(_("Error occurred while reading log config in %1$s: %2$s"),
78                 config_setting_source_file(config_root_setting(&mgr->user_cfg)),
79                 RET_MSG(ret));
80     }
81 
82     return SRN_OK;
83 }
84 
srn_config_manager_read_application_config(SrnConfigManager * mgr,SrnApplicationConfig * cfg)85 SrnRet srn_config_manager_read_application_config(SrnConfigManager *mgr,
86         SrnApplicationConfig *cfg){
87     SrnRet ret;
88 
89     ret = read_application_config_from_cfg(&mgr->system_cfg, cfg);
90     if (!RET_IS_OK(ret)){
91         return RET_ERR(_("Error occurred while reading application config in %1$s: %2$s"),
92                 config_setting_source_file(config_root_setting(&mgr->system_cfg)),
93                 RET_MSG(ret));
94     }
95     ret = read_application_config_from_cfg(&mgr->user_cfg, cfg);
96     if (!RET_IS_OK(ret)){
97         return RET_ERR(_("Error occurred while reading application config in %1$s: %2$s"),
98                 config_setting_source_file(config_root_setting(&mgr->user_cfg)),
99                 RET_MSG(ret));
100     }
101 
102     return SRN_OK;
103 }
104 
srn_config_manager_read_server_config_list(SrnConfigManager * mgr,GList ** srv_cfg_list)105 SrnRet srn_config_manager_read_server_config_list(SrnConfigManager *mgr,
106         GList **srv_cfg_list){
107     SrnRet ret;
108 
109     ret = read_server_config_list_from_cfg(&mgr->system_cfg, srv_cfg_list);
110     if (!RET_IS_OK(ret)){
111         return RET_ERR(_("Error occurred while reading server list config in %1$s: %2$s"),
112                 config_setting_source_file(config_root_setting(&mgr->system_cfg)),
113                 RET_MSG(ret));
114     }
115     ret = read_server_config_list_from_cfg(&mgr->user_cfg, srv_cfg_list);
116     if (!RET_IS_OK(ret)){
117         return RET_ERR(_("Error occurred while reading server list config in %1$s: %2$s"),
118                 config_setting_source_file(config_root_setting(&mgr->user_cfg)),
119                 RET_MSG(ret));
120     }
121 
122     return SRN_OK;
123 }
124 
srn_config_manager_read_server_config(SrnConfigManager * mgr,SrnServerConfig * cfg,const char * srv_name)125 SrnRet srn_config_manager_read_server_config(SrnConfigManager *mgr,
126         SrnServerConfig *cfg, const char *srv_name){
127     SrnRet ret;
128 
129     ret = read_server_config_from_cfg(&mgr->system_cfg, cfg, srv_name);
130     if (!RET_IS_OK(ret)){
131         return RET_ERR(_("Error occurred while reading server config in %1$s: %2$s"),
132                 config_setting_source_file(config_root_setting(&mgr->system_cfg)),
133                 RET_MSG(ret));
134     }
135     ret = read_server_config_from_cfg(&mgr->user_cfg, cfg, srv_name);
136     if (!RET_IS_OK(ret)){
137         return RET_ERR(_("Error occurred while reading server config in %1$s: %2$s"),
138                 config_setting_source_file(config_root_setting(&mgr->user_cfg)),
139                 RET_MSG(ret));
140     }
141     ret = srn_config_manager_lookup_server_password(mgr, &cfg->password, srv_name);
142     if (!RET_IS_OK(ret)){
143         WARN_FR(_("Error occurred while looking up server password: %1$s"),
144                 RET_MSG(ret));
145     }
146     ret = srn_config_manager_lookup_user_password(mgr,
147             &cfg->user->login->password, srv_name, cfg->user->nick);
148     if (!RET_IS_OK(ret)){
149         WARN_FR(_("Error occurred while looking up user password: %1$s"),
150                 RET_MSG(ret));
151     }
152 
153     return SRN_OK;
154 }
155 
srn_config_manager_read_server_config_by_addr(SrnConfigManager * mgr,SrnServerConfig * cfg,SrnServerAddr * addr)156 SrnRet srn_config_manager_read_server_config_by_addr(SrnConfigManager *mgr,
157         SrnServerConfig *cfg, SrnServerAddr *addr){
158     GList *lst;
159     GList *cfg_lst;
160     SrnRet ret;
161     SrnServerConfig *tmp;
162 
163     cfg_lst = NULL;
164     ret = srn_config_manager_read_server_config_list(mgr, &cfg_lst);
165     tmp = NULL;
166     if (!RET_IS_OK(ret)){
167         goto FIN;
168     }
169 
170     lst = cfg_lst;
171     while (lst) {
172         GList *addr_lst;
173 
174         tmp = srn_server_config_new();
175         // Do not read config to cfg until the address is found
176         ret = srn_config_manager_read_server_config(mgr, tmp, lst->data);
177         if (!RET_IS_OK(ret)){
178             goto FIN;
179         }
180 
181         addr_lst = tmp->addrs;
182         while (addr_lst){
183             if (srn_server_addr_equal(addr, addr_lst->data)){
184                 ret = srn_config_manager_read_server_config(mgr, cfg, lst->data);
185                 goto FIN;
186             }
187             addr_lst = g_list_next(addr_lst);
188         }
189 
190         srn_server_config_free(tmp);
191         tmp = NULL;
192         lst = g_list_next(lst);
193     }
194 
195     ret = SRN_ERR;
196 FIN:
197     if (cfg_lst) {
198         g_list_free_full(cfg_lst, g_free);
199     }
200     if (tmp) {
201         srn_server_config_free(tmp);
202     }
203     return ret;
204 }
205 
srn_config_manager_read_chat_config(SrnConfigManager * mgr,SrnChatConfig * cfg,const char * srv_name,const char * chat_name)206 SrnRet srn_config_manager_read_chat_config(SrnConfigManager *mgr,
207         SrnChatConfig *cfg, const char *srv_name, const char *chat_name){
208     SrnRet ret;
209 
210     ret = read_chat_config_from_cfg(&mgr->system_cfg, cfg, srv_name, chat_name);
211     if (!RET_IS_OK(ret)){
212         return RET_ERR(_("Error occurred while reading chat config in %1$s: %2$s"),
213                 config_setting_source_file(config_root_setting(&mgr->system_cfg)),
214                 RET_MSG(ret));
215     }
216 
217     ret = read_chat_config_from_cfg(&mgr->user_cfg, cfg, srv_name, chat_name);
218     if (!RET_IS_OK(ret)){
219         return RET_ERR(_("Error occurred while reading chat config in %1$s: %2$s"),
220                 config_setting_source_file(config_root_setting(&mgr->user_cfg)),
221                 RET_MSG(ret));
222     }
223 
224     // In fact we don't known whether this chat is channel
225     ret = srn_config_manager_lookup_channel_password(mgr,
226             &cfg->password, srv_name, chat_name);
227     if (!RET_IS_OK(ret)){
228         WARN_FR(_("Error occurred while looking up channel password: %1$s"),
229                 RET_MSG(ret));
230     }
231 
232     return SRN_OK;
233 }
234 
235 /*****************************************************************************
236  * Static functions
237  *****************************************************************************/
238 
read_log_config_from_cfg(config_t * cfg,SrnLoggerConfig * log_cfg)239 static SrnRet read_log_config_from_cfg(config_t *cfg, SrnLoggerConfig *log_cfg){
240     SrnRet ret;
241     config_setting_t *log;
242 
243     log = config_lookup(cfg, "log");
244     if (log){
245         config_setting_lookup_bool_ex(log, "prompt-color", &log_cfg->prompt_color);
246         config_setting_lookup_bool_ex(log, "prompt-file", &log_cfg->prompt_file);
247         config_setting_lookup_bool_ex(log, "prompt-function", &log_cfg->prompt_function);
248         config_setting_lookup_bool_ex(log, "prompt-line", &log_cfg->prompt_line);
249 
250         ret = read_log_targets_from_log(log, "debug-targets", &log_cfg->debug_targets);
251         if (!RET_IS_OK(ret)) return ret;
252         ret = read_log_targets_from_log(log, "info-targets", &log_cfg->info_targets);
253         if (!RET_IS_OK(ret)) return ret;
254         ret = read_log_targets_from_log(log, "warn-targets", &log_cfg->warn_targets);
255         if (!RET_IS_OK(ret)) return ret;
256         ret = read_log_targets_from_log(log, "error-targets", &log_cfg->error_targets);
257         if (!RET_IS_OK(ret)) return ret;
258     }
259 
260     return SRN_OK;
261 }
262 
read_log_targets_from_log(config_setting_t * log,const char * name,GList ** lst)263 static SrnRet read_log_targets_from_log(config_setting_t *log, const char *name,
264         GList **lst){
265     config_setting_t *targets;
266 
267     targets = config_setting_lookup(log, name);
268     if (!targets) return SRN_OK;
269 
270     int count = config_setting_length(targets);
271     for (int i = 0; i < count; i++){
272         const char *val;
273         config_setting_t *target;
274 
275         target = config_setting_get_elem(targets, i);
276         if (!target) break;
277 
278         val = config_setting_get_string(target);
279         if (!val) continue;
280 
281         *lst = g_list_append(*lst, g_strdup(val));
282     }
283 
284     return SRN_OK;
285 }
read_application_config_from_cfg(config_t * cfg,SrnApplicationConfig * app_cfg)286 static SrnRet read_application_config_from_cfg(config_t *cfg,
287         SrnApplicationConfig *app_cfg){
288     config_lookup_string_ex(cfg, "id", &app_cfg->id);
289     config_lookup_string_ex(cfg, "theme", &app_cfg->ui->theme);
290     config_lookup_bool_ex(cfg, "csd", &app_cfg->ui->window.csd);
291     config_lookup_bool_ex(cfg, "send-on-ctrl-enter",
292             &app_cfg->ui->window.send_on_ctrl_enter);
293     config_lookup_bool_ex(cfg, "exit-on-close",
294             &app_cfg->ui->window.exit_on_close);
295 
296     /* Read auto connect server list */
297     config_setting_t *auto_connect;
298     auto_connect = config_lookup(cfg, "auto-connect");
299     if (auto_connect){
300         for (int i = 0; i < config_setting_length(auto_connect); i++){
301             const char *val;
302             config_setting_t *server;
303 
304             server = config_setting_get_elem(auto_connect, i);
305             if (!server) continue;
306             val = config_setting_get_string(server);
307             if (!val) continue;
308 
309             app_cfg->auto_connect_srv_list = g_list_append(
310                     app_cfg->auto_connect_srv_list, g_strdup(val));
311         }
312     }
313 
314     return SRN_OK;
315 }
316 
read_server_config_list_from_cfg(config_t * cfg,GList ** srv_cfg_list)317 static SrnRet read_server_config_list_from_cfg(config_t *cfg,
318         GList **srv_cfg_list){
319     config_setting_t *server_list;
320 
321     server_list = config_lookup(cfg, "server-list");
322     if (server_list){
323         for (int i = 0, count = config_setting_length(server_list); i < count; i++){
324             char *name = NULL;
325             config_setting_t *server;
326 
327             server = config_setting_get_elem(server_list, i);
328             if (!server) break;
329 
330             if (config_setting_lookup_string_ex(server, "name", &name) != CONFIG_TRUE) {
331                 return RET_ERR(_("server-list[%1$d] doesn't have a name"), i);
332             }
333             if (name) {
334                 GList *lst;
335 
336                 lst = *srv_cfg_list;
337                 while (lst) {
338                     if (g_ascii_strcasecmp(name, lst->data) == 0){
339                         break;
340                     }
341                     lst = g_list_next(lst);
342                 }
343                 if (!lst){
344                     *srv_cfg_list = g_list_append(*srv_cfg_list, name);
345                 }
346             }
347         }
348     }
349 
350     return SRN_OK;
351 }
352 
read_server_config_from_server(config_setting_t * server,SrnServerConfig * cfg)353 static SrnRet read_server_config_from_server(config_setting_t *server,
354         SrnServerConfig *cfg){
355     /* Read server meta info,
356      * NOTE: Server password is not stored in configuration file */
357     config_setting_lookup_string_ex(server, "name", &cfg->name);
358     config_setting_lookup_bool_ex(server, "tls", &cfg->irc->tls);
359     config_setting_lookup_bool_ex(server, "tls-noverify", &cfg->irc->tls_noverify);
360     config_setting_lookup_string_ex(server, "encoding", &cfg->irc->encoding);
361     if (cfg->irc->tls_noverify) {
362         cfg->irc->tls = TRUE;
363     }
364 
365     /* Read server.addrs */
366     config_setting_t *addrs;
367     addrs = config_setting_lookup(server, "addresses");
368     if (addrs){
369         for (int i = 0, count = config_setting_length(addrs); i < count; i++){
370             char *addr;
371 
372             addr = config_setting_get_string_elem_ex(addrs, i);
373             if (addr){
374                 SrnRet ret;
375                 SrnServerAddr *srv_addr;
376 
377                 srv_addr = srn_server_addr_new_from_string(addr);
378                 ret = srn_server_config_add_addr(cfg, srv_addr);
379                 g_free(addr);
380 
381                 if (!RET_IS_OK(ret)){
382                     srn_server_addr_free(srv_addr);
383                     return ret;
384                 }
385             }
386         }
387     }
388 
389     /* Read server.user */
390     config_setting_t *user;
391     user = config_setting_lookup(server, "user");
392     if (user){
393         SrnRet ret;
394         ret = read_user_config_from_user(user, cfg->user);
395         if (!RET_IS_OK(ret)){
396             return ret;
397         }
398     }
399 
400     /* Read auto join chat list */
401     config_setting_t *auto_join;
402     auto_join = config_setting_lookup(server, "auto-join");
403     if (auto_join){
404         for (int i = 0; i < config_setting_length(auto_join); i++){
405             const char *val;
406             config_setting_t *chat;
407 
408             chat = config_setting_get_elem(auto_join, i);
409             if (!chat) continue;
410             val = config_setting_get_string(chat);
411             if (!val) continue;
412 
413             cfg->auto_join_chat_list = g_list_append(
414                     cfg->auto_join_chat_list, g_strdup(val));
415         }
416     }
417 
418     /* Read autorun command list */
419     config_setting_t *cmds;
420     cmds = config_setting_lookup(server, "auto-run");
421     if (cmds){
422         for (int i = 0; i < config_setting_length(cmds); i++){
423             const char *val;
424             config_setting_t *cmd;
425 
426             cmd = config_setting_get_elem(cmds, i);
427             if (!cmd) continue;
428             val = config_setting_get_string(cmd);
429             if (!val) continue;
430 
431             cfg->auto_run_cmd_list = g_list_append(cfg->auto_run_cmd_list,
432                     g_strdup(val));
433         }
434     }
435 
436     return SRN_OK;
437 }
438 
read_server_config_from_server_list(config_setting_t * server_list,SrnServerConfig * cfg,const char * srv_name)439 static SrnRet read_server_config_from_server_list(config_setting_t *server_list,
440         SrnServerConfig *cfg, const char *srv_name){
441     int count;
442     SrnRet ret;
443 
444     count = config_setting_length(server_list);
445     for (int i = 0; i < count; i++){
446         const char *name = NULL;
447         config_setting_t *server;
448 
449         server = config_setting_get_elem(server_list, i);
450         if (!server) break;
451 
452         config_setting_lookup_string(server, "name", &name);
453         if (g_strcmp0(srv_name, name) != 0) continue;
454 
455         DBG_FR("Read: server-list.[name = %s], srv_name: %s", name, srv_name);
456         ret = read_server_config_from_server(server, cfg);
457         if (!RET_IS_OK(ret)) return ret;
458     }
459 
460     return SRN_OK;
461 }
462 
read_server_config_from_cfg(config_t * cfg,SrnServerConfig * srv_cfg,const char * srv_name)463 static SrnRet read_server_config_from_cfg(config_t *cfg, SrnServerConfig *srv_cfg,
464         const char *srv_name){
465     SrnRet ret;
466     config_setting_t *server;
467 
468     /* Read server */
469     server = config_lookup(cfg, "server");
470     if (server){
471         DBG_FR("Read: server, srv_name: %s", srv_name);
472         ret = read_server_config_from_server(server, srv_cfg);
473         if (!RET_IS_OK(ret)) return ret;
474     }
475 
476     /* Read server_list[name = srv_name] */
477     config_setting_t *server_list;
478 
479     server_list = config_lookup(cfg, "server-list");
480     if (server_list){
481         ret = read_server_config_from_server_list(server_list, srv_cfg, srv_name);
482         if (!RET_IS_OK(ret)) return ret;
483     }
484 
485     return SRN_OK;
486 }
487 
read_chat_config_from_chat(config_setting_t * chat,SrnChatConfig * cfg)488 static SrnRet read_chat_config_from_chat(config_setting_t *chat, SrnChatConfig *cfg){
489     config_setting_lookup_bool_ex(chat, "notify", &cfg->ui->notify);
490     config_setting_lookup_bool_ex(chat, "show-topic", &cfg->ui->show_topic);
491     config_setting_lookup_bool_ex(chat, "show-avatar", &cfg->ui->show_avatar);
492     config_setting_lookup_bool_ex(chat, "show-user-list", &cfg->ui->show_user_list);
493     config_setting_lookup_bool_ex(chat, "render-mirc-color", &cfg->render_mirc_color);
494     config_setting_lookup_bool_ex(chat, "preview-url", &cfg->ui->preview_url);
495     config_setting_lookup_bool_ex(chat, "auto-preview-url", &cfg->ui->auto_preview_url);
496     config_setting_lookup_string_ex(chat, "nick-completion-suffix", &cfg->ui->nick_completion_suffix);
497 
498     /* Read autorun command list */
499     config_setting_t *cmds;
500     cmds = config_setting_lookup(chat, "auto-run");
501     if (cmds){
502         for (int i = 0; i < config_setting_length(cmds); i++){
503             const char *val;
504             config_setting_t *cmd;
505 
506             cmd = config_setting_get_elem(cmds, i);
507             if (!cmd) continue;
508             val = config_setting_get_string(cmd);
509             if (!val) continue;
510 
511             cfg->auto_run_cmd_list = g_list_append(cfg->auto_run_cmd_list,
512                     g_strdup(val));
513         }
514     }
515 
516     return SRN_OK;
517 }
518 
read_chat_config_from_chat_list(config_setting_t * chat_list,SrnChatConfig * cfg,const char * chat_name)519 static SrnRet read_chat_config_from_chat_list(config_setting_t *chat_list,
520         SrnChatConfig *cfg, const char *chat_name){
521     SrnRet ret;
522 
523     for (int i = 0, count = config_setting_length(chat_list); i < count; i++){
524         const char *name = NULL;
525         config_setting_t *chat;
526 
527         chat = config_setting_get_elem(chat_list, i);
528         if (!chat) break;
529         if (config_setting_lookup_string(chat, "name", &name) != CONFIG_TRUE){
530             continue;
531         }
532         if (g_strcmp0(chat_name, name) != 0) continue;
533 
534         DBG_FR("Read: chat-list.%s, chat_name: %s", name, chat_name);
535         ret = read_chat_config_from_chat(chat, cfg);
536         if (!RET_IS_OK(ret)) return ret;
537     }
538 
539     return SRN_OK;
540 }
541 
read_chat_config_from_cfg(config_t * cfg,SrnChatConfig * chat_cfg,const char * srv_name,const char * chat_name)542 static SrnRet read_chat_config_from_cfg(config_t *cfg, SrnChatConfig *chat_cfg,
543         const char *srv_name, const char *chat_name){
544     SrnRet ret;
545 
546     /* Read server.chat */
547     config_setting_t *chat;
548 
549     chat = config_lookup(cfg, "server.chat");
550     if (chat){
551         DBG_FR("Read: server.chat, srv_name: %s, chat_name: %s", srv_name, chat_name);
552         ret = read_chat_config_from_chat(chat, chat_cfg);
553         if (!RET_IS_OK(ret)) return ret;
554     }
555 
556     /* Read server.chat_list[name = chat_name] */
557     if (chat_name){
558         config_setting_t *chat_list;
559 
560         chat_list = config_lookup(cfg, "server.chat-list");
561         if (chat_list){
562             ret = read_chat_config_from_chat_list(chat_list, chat_cfg, chat_name);
563             if (!RET_IS_OK(ret)) return ret;
564         }
565     }
566 
567     if (srv_name){
568         config_setting_t *server_list;
569 
570         server_list = config_lookup(cfg, "server-list");
571         if (server_list){
572             for (int i = 0, count = config_setting_length(server_list); i < count; i++){
573                 const char *name = NULL;
574                 config_setting_t *server;
575                 config_setting_t *chat;
576 
577                 server = config_setting_get_elem(server_list, i);
578                 if (!server) break;
579 
580                 config_setting_lookup_string(server, "name", &name);
581                 if (g_strcmp0(srv_name, name) != 0) continue;
582 
583                 /* Read server_list.[name = srv_name].chat */
584                 chat = config_setting_lookup(server, "chat");
585                 if (chat){
586                     DBG_FR("Read server-list.[name = %s].chat, srv_name: %s, chat_name: %s",
587                             name, srv_name, chat_name);
588                     ret = read_chat_config_from_chat(chat, chat_cfg);
589                     if (!RET_IS_OK(ret)) return ret;
590                 }
591 
592                 /* Read server_list.[name = srv_name].chat_list[name = chat_name] */
593                 if (chat_name){
594                     config_setting_t *chat_list;
595 
596                     chat_list = config_setting_lookup(server, "server.chat-list");
597                     if (chat_list){
598                         ret = read_chat_config_from_chat_list(chat_list, chat_cfg, chat_name);
599                         if (!RET_IS_OK(ret)) return ret;
600                     }
601                 }
602             }
603         }
604     }
605 
606     return SRN_OK;
607 }
608 
read_user_config_from_user(config_setting_t * user,SrnUserConfig * cfg)609 static SrnRet read_user_config_from_user(config_setting_t *user, SrnUserConfig *cfg){
610     config_setting_t *login;
611 
612     // Read user.login
613     // NOTE: Login password is not stored in configuration file
614     login = config_setting_lookup(user, "login");
615     if (login) {
616         const char *method = NULL;
617 
618         config_setting_lookup_string(login, "method", &method);
619         cfg->login->method = srn_login_method_from_string(method);
620 
621         config_setting_lookup_string_ex(login, "certificate", &cfg->login->cert_file);
622     }
623 
624     config_setting_lookup_string_ex(user, "nickname", &cfg->nick);
625     config_setting_lookup_string_ex(user, "username", &cfg->username);
626     config_setting_lookup_string_ex(user, "realname", &cfg->realname);
627 
628     config_setting_lookup_string_ex(user, "part-message", &cfg->part_message);
629     config_setting_lookup_string_ex(user, "kick-message", &cfg->kick_message);
630     config_setting_lookup_string_ex(user, "away-message", &cfg->away_message);
631     config_setting_lookup_string_ex(user, "quit-message", &cfg->quit_message);
632 
633     return SRN_OK;
634 }
635 
636 /**
637  * @brief Wrapper of config_lookup_string(), This function will allocate a new
638  * string, you should free it by yourself
639  *
640  * @param config
641  * @param path
642  * @param value
643  *
644  * @return
645  */
config_lookup_string_ex(const config_t * config,const char * path,char ** value)646 static int config_lookup_string_ex(const config_t *config, const char *path, char **value){
647     int ret;
648     const char *constval = NULL;
649 
650     ret = config_lookup_string(config, path, &constval);
651     if (ret == CONFIG_TRUE){
652         str_assign(value, constval);
653     }
654 
655     return ret;
656 }
657 
658 /**
659  * @brief Wrapper of config_setting_lookup_string(), This function will
660  *      allocate a new string, you should free it by yourself
661  *
662  * @param config
663  * @param path
664  * @param value
665  *
666  * @return
667  */
config_setting_lookup_string_ex(const config_setting_t * config,const char * name,char ** value)668 static int config_setting_lookup_string_ex(const config_setting_t *config,
669         const char *name, char **value){
670     int ret;
671     const char *constval = NULL;
672 
673     ret = config_setting_lookup_string(config, name, &constval);
674     if (ret == CONFIG_TRUE){
675         str_assign(value, constval);
676     }
677 
678     return ret;
679 }
680 
config_setting_get_string_elem_ex(const config_setting_t * setting,int index)681 static char* config_setting_get_string_elem_ex(const config_setting_t *setting,
682         int index){
683     return g_strdup(config_setting_get_string_elem(setting, index));
684 }
685 
config_lookup_bool_ex(const config_t * config,const char * name,bool * value)686 static int config_lookup_bool_ex(const config_t *config, const char *name,
687         bool *value){
688     int intval;
689     int ret;
690 
691     ret = config_lookup_bool(config, name, &intval);
692     if (ret == CONFIG_TRUE){
693         *value = (bool)intval;
694     }
695 
696     return ret;
697 }
698 
699 /**
700  * @brief Wrapper of config_setting_lookup_bool(), The "bool" in libconfig is
701  * actually an integer, This function transform it to fit bool (alias of
702  * gboolean) defined in "srain.h"
703  *
704  * @param config
705  * @param name
706  * @param value
707  *
708  * @return
709  */
config_setting_lookup_bool_ex(const config_setting_t * config,const char * name,bool * value)710 static int config_setting_lookup_bool_ex(const config_setting_t *config,
711         const char *name, bool *value){
712     int intval;
713     int ret;
714 
715     ret = config_setting_lookup_bool(config, name, &intval);
716     if (ret == CONFIG_TRUE){
717         *value = (bool)intval;
718     }
719 
720     return ret;
721 }
722