1 /* config.c -- functions to define, create, and set configuration files */
2 
3 /*
4  * This file is part of CliFM
5  *
6  * Copyright (C) 2016-2021, L. Abramovich <johndoe.arch@outlook.com>
7  * All rights reserved.
8 
9  * CliFM is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * CliFM is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301, USA.
23 */
24 
25 #include "helpers.h"
26 
27 #include <errno.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <readline/readline.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <time.h>
34 #include <unistd.h>
35 
36 #include "aux.h"
37 #include "colors.h"
38 #include "config.h"
39 #include "exec.h"
40 #include "init.h"
41 #include "listing.h"
42 #include "mime.h"
43 #include "misc.h"
44 #include "navigation.h"
45 #include "file_operations.h"
46 #include "autocmds.h"
47 
48 /* Regenerate the configuration file and create a back up of the old
49  * one */
50 static int
regen_config(void)51 regen_config(void)
52 {
53 	int config_found = 1;
54 	struct stat config_attrib;
55 
56 	if (stat(config_file, &config_attrib) == -1) {
57 		puts(_("No configuration file found"));
58 		config_found = 0;
59 	}
60 
61 	if (config_found) {
62 		time_t rawtime = time(NULL);
63 		struct tm t;
64 		localtime_r(&rawtime, &t);
65 
66 		char date[18];
67 		strftime(date, 18, "%Y%m%d@%H:%M:%S", &t);
68 
69 		char *bk = (char *)xnmalloc(strlen(config_file) + strlen(date) + 2, sizeof(char));
70 		sprintf(bk, "%s.%s", config_file, date);
71 
72 		char *cmd[] = {"mv", config_file, bk, NULL};
73 
74 		if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) {
75 			free(bk);
76 			return EXIT_FAILURE;
77 		}
78 
79 		printf(_("Old configuration file stored as '%s'\n"), bk);
80 		free(bk);
81 	}
82 
83 	if (create_config(config_file) != EXIT_SUCCESS)
84 		return EXIT_FAILURE;
85 
86 	printf(_("New configuration file written to '%s'\n"), config_file);
87 	reload_config();
88 	return EXIT_SUCCESS;
89 }
90 
91 /* Edit the config file, either via the mime function or via the first
92  * passed argument (Ex: 'edit nano'). The 'gen' option regenerates
93  * the configuration file and creates a back up of the old one. */
94 int
edit_function(char ** comm)95 edit_function(char **comm)
96 {
97 	if (xargs.stealth_mode == 1) {
98 		printf(_("%s: Access to configuration files is not allowed in "
99 			 "stealth mode\n"), PROGRAM_NAME);
100 		return EXIT_SUCCESS;
101 	}
102 
103 	if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
104 		printf("%s\n", EDIT_USAGE);
105 		return EXIT_SUCCESS;
106 	}
107 
108 	if (comm[1] && *comm[1] == 'r' && strcmp(comm[1], "reset") == 0)
109 		return regen_config();
110 
111 	if (!config_ok) {
112 		fprintf(stderr, _("%s: Cannot access the configuration file\n"),
113 		    PROGRAM_NAME);
114 		return EXIT_FAILURE;
115 	}
116 
117 	/* Get modification time of the config file before opening it */
118 	struct stat file_attrib;
119 
120 	/* If, for some reason (like someone erasing the file while the
121 	 * program is running) clifmrc doesn't exist, recreate the
122 	 * configuration file. Then run 'stat' again to reread the attributes
123 	 * of the file */
124 	if (stat(config_file, &file_attrib) == -1) {
125 		create_config(config_file);
126 		stat(config_file, &file_attrib);
127 	}
128 
129 	time_t mtime_bfr = (time_t)file_attrib.st_mtime;
130 	int ret = EXIT_SUCCESS;
131 
132 	/* If there is an argument... */
133 	if (comm[1]) {
134 		char *cmd[] = {comm[1], config_file, NULL};
135 		ret = launch_execve(cmd, FOREGROUND, E_NOSTDERR);
136 	} else {
137 		/* If no application was passed as 2nd argument */
138 		open_in_foreground = 1;
139 		ret = open_file(config_file);
140 		open_in_foreground = 0;
141 	}
142 
143 	if (ret != EXIT_SUCCESS)
144 		return EXIT_FAILURE;
145 
146 	/* Get modification time after opening the config file */
147 	stat(config_file, &file_attrib);
148 	/* If modification times differ, the file was modified after being
149 	 * opened */
150 
151 	if (mtime_bfr != (time_t)file_attrib.st_mtime) {
152 		/* Reload configuration only if the config file was modified */
153 		reload_config();
154 		welcome_message = 0;
155 
156 		if (autols) {
157 			free_dirlist();
158 			ret = list_dir();
159 		}
160 	}
161 
162 	return ret;
163 }
164 
165 void
set_env(void)166 set_env(void)
167 {
168 	if (xargs.stealth_mode == 1)
169 		return;
170 
171 	/* Set a few environment variables, mostly useful to run custom
172 	 * scripts via the actions function */
173 	/* CLIFM env variable is set to one when CliFM is running, so that
174 	 * external programs can determine if they were spawned by CliFM */
175 	setenv("CLIFM", config_dir ? config_dir : "1", 1);
176 	setenv("CLIFM_PROFILE", alt_profile ? alt_profile : "default", 1);
177 
178 	if (sel_file)
179 		setenv("CLIFM_SELFILE", sel_file, 1);
180 }
181 
182 /* Define the file for the Selection Box */
183 void
set_sel_file(void)184 set_sel_file(void)
185 {
186 	if (sel_file) {
187 		free(sel_file);
188 		sel_file = (char *)NULL;
189 	}
190 
191 	if (!config_dir)
192 		return;
193 
194 	size_t config_len = strlen(config_dir);
195 
196 	if (!share_selbox) {
197 		/* Private selection box is stored in the profile
198 		 * directory */
199 		sel_file = (char *)xnmalloc(config_len + 9, sizeof(char));
200 
201 		sprintf(sel_file, "%s/selbox", config_dir);
202 	} else {
203 		/* Common selection box is stored in the general
204 		 * configuration directory */
205 		sel_file = (char *)xnmalloc(config_len + 17, sizeof(char));
206 		sprintf(sel_file, "%s/.config/%s/selbox", user.home, PNL);
207 	}
208 
209 	return;
210 }
211 
212 int
create_kbinds_file(void)213 create_kbinds_file(void)
214 {
215 	if (!config_ok)
216 		return EXIT_FAILURE;
217 
218 	struct stat attr;
219 	/* If the file already exists, do nothing */
220 	if (stat(kbinds_file, &attr) == EXIT_SUCCESS)
221 		return EXIT_SUCCESS;
222 
223 	/* If not, try to import it from DATADIR */
224 	if (data_dir) {
225 		char sys_file[PATH_MAX];
226 		snprintf(sys_file, PATH_MAX - 1, "%s/%s/keybindings.cfm", data_dir, PNL);
227 		if (stat(sys_file, &attr) == EXIT_SUCCESS) {
228 			char *cmd[] = {"cp", sys_file, kbinds_file, NULL};
229 			if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS)
230 				return EXIT_SUCCESS;
231 		}
232 	}
233 
234 	/* Else, create it */
235 	FILE *fp = fopen(kbinds_file, "w");
236 	if (!fp) {
237 		_err('w', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME, kbinds_file,
238 		    strerror(errno));
239 		return EXIT_FAILURE;
240 	}
241 
242 	fprintf(fp, "# Keybindings file for %s\n\n\
243 # Use the 'kbgen' plugin (compile it first: gcc -o kbgen kbgen.c) to \n\
244 # find out the escape code for the key or key sequence you want. Use \n\
245 # either octal, hexadecimal codes or symbols.\n\
246 # Ex: For Alt-/ (in rxvt terminals) 'kbgen' will print the following \n\
247 # lines:\n\
248 # Hex  | Oct | Symbol\n\
249 # ---- | ---- | ------\n\
250 # \\x1b | \\033 | ESC (\\e)\n\
251 # \\x2f | \\057 | /\n\
252 # In this case, the keybinding, if using symbols, is: \"\\e/:function\"\n\
253 # In case you prefer the hex codes it would be: \\x1b\\x2f:function.\n\
254 # GNU emacs escape sequences are also allowed (ex: \"\\M-a\", Alt-a\n\
255 # in most keyboards, or \"\\C-r\" for Ctrl-r).\n\
256 # Some codes, especially those involving keys like Ctrl or the arrow\n\
257 # keys, vary depending on the terminal emulator and the system settings.\n\
258 # These keybindings should be set up thus on a per terminal basis.\n\
259 # You can also consult the terminfo database via the infocmp command.\n\
260 # See terminfo(5) and infocmp(1).\n\
261 \n\
262 # Alt-j\n\
263 previous-dir:\\M-j\n\
264 # Shift-Left (rxvt)\n\
265 previous-dir2:\\e[d\n\
266 # Shift-Left (xterm)\n\
267 previous-dir3:\\e[2D\n\
268 # Shift-Left (others)\n\
269 previous-dir4:\\e[1;2D\n\
270 \n\
271 # Alt-k\n\
272 next-dir:\\M-k\n\
273 # Shift-right (rxvt)\n\
274 next-dir2:\\e[c\n\
275 # Shift-Right (xterm)\n\
276 next-dir3:\\e[2C\n\
277 # Shift-Right (others)\n\
278 next-dir4:\\e[1;2C\n\
279 first-dir:\\C-\\M-j\n\
280 last-dir:\\C-\\M-k\n\
281 \n\
282 # Alt-u\n\
283 parent-dir:\\M-u\n\
284 # Shift-Up (rxvt)\n\
285 parent-dir2:\\e[a\n\
286 # Shift-Up (xterm)\n\
287 parent-dir3:\\e[2A\n\
288 # Shift-Up (others)\n\
289 parent-dir4:\\e[1;2A\n\
290 \n\
291 # Alt-e\n\
292 home-dir:\\M-e\n\
293 # Home key (rxvt)\n\
294 home-dir2:\\e[7~\n\
295 # Home key (xterm)\n\
296 home-dir3:\\e[H\n\
297 home-dir4:\n\
298 \n\
299 # Alt-r\n\
300 root-dir:\\M-r\n\
301 # Alt-/ (rxvt)\n\
302 root-dir2:\\e/\n\
303 #root-dir3:\n\
304 \n\
305 pinned-dir:\\M-p\n\
306 workspace1:\\M-1\n\
307 workspace2:\\M-2\n\
308 workspace3:\\M-3\n\
309 workspace4:\\M-4\n\
310 \n\
311 # Help\n\
312 # F1-3\n\
313 show-manpage:\\eOP\n\
314 show-cmds:\\eOQ\n\
315 show-kbinds:\\eOR\n\
316 \n\
317 prepend-sudo:\\M-v\n\
318 create-file:\\M-n\n\
319 new-instance:\\C-x\n\
320 previous-profile:\\C-\\M-o\n\
321 next-profile:\\C-\\M-p\n\
322 archive-sel:\\C-\\M-a\n\
323 rename-sel:\\C-\\M-r\n\
324 remove-sel:\\C-\\M-d\n\
325 trash-sel:\\C-\\M-t\n\
326 untrash-all:\\C-\\M-u\n\
327 paste-sel:\\C-\\M-v\n\
328 move-sel:\\C-\\M-n\n\
329 export-sel:\\C-\\M-e\n\
330 open-sel:\\C-\\M-g\n\
331 bookmark-sel:\\C-\\M-b\n\
332 refresh-screen:\\C-r\n\
333 clear-line:\\M-c\n\
334 clear-msgs:\\M-t\n\
335 show-dirhist:\\M-h\n\
336 toggle-hidden:\\M-i\n\
337 toggle-hidden2:\\M-.\n\
338 toggle-light:\\M-y\n\
339 toggle-long:\\M-l\n\
340 sort-previous:\\M-z\n\
341 sort-next:\\M-x\n\
342 bookmarks:\\M-b\n\
343 select-all:\\M-a\n\
344 deselect-all:\\M-d\n\
345 mountpoints:\\M-m\n\
346 folders-first:\\M-g\n\
347 selbox:\\M-s\n\
348 lock:\\M-o\n\
349 # F6-12\n\
350 open-mime:\\e[17~\n\
351 open-jump-db:\\e[18~\n\
352 edit-color-scheme:\\e[19~\n\
353 open-keybinds:\\e[20~\n\
354 open-config:\\e[21~\n\
355 open-bookmarks:\\e[23~\n\
356 quit:\\e[24~\n\n\
357 # Plugins\n\
358 # 1) Make sure your plugin is in the plugins directory (or use any of the\n\
359 # plugins in there)\n\
360 # 2) Link pluginx to your plugin using the 'actions edit' command. Ex:\n\
361 # \"plugin1=myplugin.sh\"\n\
362 # 3) Set a keybinding here for pluginx. Ex: \"plugin1:\\M-7\"\n\n\
363 #plugin1:\n\
364 #plugin2:\n\
365 #plugin3:\n\
366 #plugin4:\n",
367 	    PROGRAM_NAME);
368 
369 	fclose(fp);
370 	return EXIT_SUCCESS;
371 }
372 
373 static int
import_from_data_dir(char * src_filename,char * dest)374 import_from_data_dir(char *src_filename, char *dest)
375 {
376 	if (!data_dir || !src_filename || !dest)
377 		return EXIT_FAILURE;
378 
379 	if (!*data_dir || !*src_filename || !*dest)
380 		return EXIT_FAILURE;
381 
382 	struct stat attr;
383 	char sys_file[PATH_MAX];
384 	snprintf(sys_file, PATH_MAX - 1, "%s/%s/%s", data_dir, PNL, src_filename);
385 	if (stat(sys_file, &attr) == EXIT_SUCCESS) {
386 		char *cmd[] = {"cp", sys_file, dest, NULL};
387 		if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS)
388 			return EXIT_SUCCESS;
389 	}
390 
391 	return EXIT_FAILURE;
392 }
393 
394 static int
create_actions_file(char * file)395 create_actions_file(char *file)
396 {
397 	struct stat attr;
398 	/* If the file already exists, do nothing */
399 	if (stat(file, &attr) == EXIT_SUCCESS)
400 		return EXIT_SUCCESS;
401 
402 	/* If not, try to import it from DATADIR */
403 	if (import_from_data_dir("actions.cfm", file) == EXIT_SUCCESS)
404 		return EXIT_SUCCESS;
405 
406 	/* Else, create it */
407 	int fd;
408 	FILE *fp = open_fstream_w(file, &fd);
409 	if (!fp) {
410 		_err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME,
411 		    file, strerror(errno));
412 		return EXIT_FAILURE;
413 	}
414 
415 	fprintf(fp, "######################\n"
416 		"# Actions file for %s #\n"
417 		"######################\n\n"
418 		"# Define here your custom actions. Actions are "
419 		"custom command names\n"
420 		"# bound to a executable file located either in "
421 		"DATADIR/clifm/plugins\n"
422 		"# (usually /usr/share/clifm/plugins) or in "
423 		"$XDG_CONFIG_HOME/clifm/plugins.\n"
424 		"# Actions can be executed directly from "
425 		"%s command line, as if they\n"
426 		"# were any other command, and the associated "
427 		"file will be executed\n"
428 		"# instead. All parameters passed to the action "
429 		"command will be passed\n"
430 		"# to the corresponding plugin as well.\n\n"
431 		"i=img_viewer.sh\n"
432 		"kbgen=kbgen\n"
433 		"vid=vid_viewer.sh\n"
434 		"ptot=pdf_viewer.sh\n"
435 		"music=music_player.sh\n"
436 		"update=update.sh\n"
437 		"wall=wallpaper_setter.sh\n"
438 		"dragon=dragondrop.sh\n"
439 		"bn=batch_create.sh\n"
440 		"+=finder.sh\n"
441 		"++=jumper.sh\n"
442 		"-=fzfnav.sh\n"
443 		"*=fzfsel.sh\n"
444 		"**=fzfdesel.sh\n"
445 		"h=fzfhist.sh\n"
446 		"dh=fzfdirhist.sh\n"
447 		"//=rgfind.sh\n"
448 		"ih=ihelp.sh\n",
449 	    PROGRAM_NAME, PROGRAM_NAME);
450 
451 	close_fstream(fp, fd);
452 	return EXIT_SUCCESS;
453 }
454 
455 void
create_tmp_files(void)456 create_tmp_files(void)
457 {
458 	if (xargs.stealth_mode == 1)
459 		return;
460 
461 	if (!user.name)
462 		return;
463 
464 	size_t pnl_len = strlen(PNL);
465 
466 	/* #### CHECK THE TMP DIR #### */
467 
468 	/* If the temporary directory doesn't exist, create it. I create
469 	 * the parent directory (/tmp/clifm) with 1777 permissions (world
470 	 * writable with the sticky bit set), so that every user is able
471 	 * to create files in here, but only the file's owner can remove
472 	 * or modify them */
473 	size_t user_len = strlen(user.name);
474 	tmp_dir = (char *)xnmalloc(P_tmpdir_len + pnl_len + user_len + 3, sizeof(char));
475 	sprintf(tmp_dir, "%s/%s", P_tmpdir, PNL);
476 	/* P_tmpdir is defined in stdio.h and it's value is usually /tmp */
477 
478 	int tmp_root_ok = 1;
479 	struct stat attr;
480 	/* Create /tmp */
481 	if (stat(P_tmpdir, &attr) == -1)
482 		if (xmkdir(P_tmpdir, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX) == EXIT_FAILURE)
483 			tmp_root_ok = 0;
484 	/* Create /tmp/clifm */
485 	if (stat(tmp_dir, &attr) == -1)
486 		xmkdir(tmp_dir, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
487 
488 	/* Once the parent directory exists, create the user's directory to
489 	 * store the list of selected files:
490 	 * TMP_DIR/clifm/username/.selbox_PROFILE. I use here very
491 	 * restrictive permissions (700), since only the corresponding user
492 	 * must be able to read and/or modify this list */
493 	sprintf(tmp_dir, "%s/%s/%s", P_tmpdir, PNL, user.name);
494 	if (stat(tmp_dir, &attr) == -1) {
495 		if (xmkdir(tmp_dir, S_IRWXU) == EXIT_FAILURE) {
496 			selfile_ok = 0;
497 			_err('e', PRINT_PROMPT, _("%s: %s: %s\n"), PROGRAM_NAME,
498 				tmp_dir, strerror(errno));
499 		}
500 	}
501 
502 	/* If the directory exists, check it is writable */
503 	else if (access(tmp_dir, W_OK) == -1) {
504 		if (!sel_file) {
505 			selfile_ok = 0;
506 			_err('w', PRINT_PROMPT, "%s: %s: Directory not writable. Selected "
507 				"files will be lost after program exit\n",
508 			    PROGRAM_NAME, tmp_dir);
509 		}
510 	}
511 
512 	/* sel_file should has been set before by set_sel_file(). If not set,
513 	 * we do not have access to the config dir */
514 	if (sel_file)
515 		return;
516 
517 	/*"We will write a temporary selfile in /tmp. Check if this latter is
518 	 * available */
519 	if (!tmp_root_ok) {
520 		_err('w', PRINT_PROMPT, "%s: Could not create the selections file.\n"
521 			"Selected files will be lost after program exit\n",
522 		    PROGRAM_NAME, tmp_dir);
523 		return;
524 	}
525 
526 	/* If the config directory isn't available, define an alternative
527 	 * selection file in /tmp (if available) */
528 	if (!share_selbox) {
529 		size_t prof_len = 0;
530 
531 		if (alt_profile)
532 			prof_len = strlen(alt_profile);
533 		else
534 			prof_len = 7; /* Lenght of "default" */
535 
536 		sel_file = (char *)xnmalloc(P_tmpdir_len + prof_len + 9,
537 		    sizeof(char));
538 		sprintf(sel_file, "%s/selbox_%s", P_tmpdir,
539 		    (alt_profile) ? alt_profile : "default");
540 	} else {
541 		sel_file = (char *)xnmalloc(P_tmpdir_len + 8, sizeof(char));
542 		sprintf(sel_file, "%s/selbox", P_tmpdir);
543 	}
544 
545 	_err('w', PRINT_PROMPT, _("%s: '%s': Using a temporary directory for "
546 		"the Selection Box. Selected files won't be persistent across "
547 		"reboots"), PROGRAM_NAME, tmp_dir);
548 }
549 
550 static void
define_config_file_names(void)551 define_config_file_names(void)
552 {
553 	size_t pnl_len = strlen(PNL);
554 
555 	if (alt_config_dir) {
556 		config_dir_gral = (char *)xnmalloc(strlen(alt_config_dir) + pnl_len
557 											+ 2, sizeof(char));
558 		sprintf(config_dir_gral, "%s/%s", alt_config_dir, PNL);
559 		free(alt_config_dir);
560 	} else {
561 		/* If $XDG_CONFIG_HOME is set, use it for the config file.
562 		 * Else, fall back to $HOME/.config */
563 		char *xdg_config_home = getenv("XDG_CONFIG_HOME");
564 		if (xdg_config_home) {
565 			size_t xdg_config_home_len = strlen(xdg_config_home);
566 			config_dir_gral = (char *)xnmalloc(xdg_config_home_len + pnl_len
567 												+ 2, sizeof(char));
568 			sprintf(config_dir_gral, "%s/%s", xdg_config_home, PNL);
569 			xdg_config_home = (char *)NULL;
570 		} else {
571 			config_dir_gral = (char *)xnmalloc(user.home_len + pnl_len + 11,
572 												sizeof(char));
573 			sprintf(config_dir_gral, "%s/.config/%s", user.home, PNL);
574 		}
575 	}
576 
577 	size_t config_gral_len = strlen(config_dir_gral);
578 
579 	/* alt_profile will not be NULL whenever the -P option is used
580 	 * to run the program under an alternative profile */
581 	if (alt_profile) {
582 		config_dir = (char *)xnmalloc(config_gral_len + strlen(alt_profile) + 11, sizeof(char));
583 		sprintf(config_dir, "%s/profiles/%s", config_dir_gral, alt_profile);
584 	} else {
585 		config_dir = (char *)xnmalloc(config_gral_len + 18, sizeof(char));
586 		sprintf(config_dir, "%s/profiles/default", config_dir_gral);
587 	}
588 
589 	if (alt_kbinds_file) {
590 		kbinds_file = savestring(alt_kbinds_file, strlen(alt_kbinds_file));
591 		free(alt_kbinds_file);
592 		alt_kbinds_file = (char *)NULL;
593 	} else {
594 		/* Keybindings per user, not per profile */
595 		kbinds_file = (char *)xnmalloc(config_gral_len + 17, sizeof(char));
596 		sprintf(kbinds_file, "%s/keybindings.cfm", config_dir_gral);
597 	}
598 
599 	colors_dir = (char *)xnmalloc(config_gral_len + 8, sizeof(char));
600 	sprintf(colors_dir, "%s/colors", config_dir_gral);
601 
602 	plugins_dir = (char *)xnmalloc(config_gral_len + 9, sizeof(char));
603 	sprintf(plugins_dir, "%s/plugins", config_dir_gral);
604 
605 #ifndef _NO_TRASH
606 	trash_dir = (char *)xnmalloc(user.home_len + 20, sizeof(char));
607 	sprintf(trash_dir, "%s/.local/share/Trash", user.home);
608 
609 	size_t trash_len = strlen(trash_dir);
610 
611 	trash_files_dir = (char *)xnmalloc(trash_len + 7, sizeof(char));
612 	sprintf(trash_files_dir, "%s/files", trash_dir);
613 
614 	trash_info_dir = (char *)xnmalloc(trash_len + 6, sizeof(char));
615 	sprintf(trash_info_dir, "%s/info", trash_dir);
616 #endif
617 
618 	size_t config_len = strlen(config_dir);
619 
620 	dirhist_file = (char *)xnmalloc(config_len + 13, sizeof(char));
621 	sprintf(dirhist_file, "%s/dirhist.cfm", config_dir);
622 
623 	if (!alt_bm_file) {
624 		bm_file = (char *)xnmalloc(config_len + 15, sizeof(char));
625 		sprintf(bm_file, "%s/bookmarks.cfm", config_dir);
626 	} else {
627 		bm_file = savestring(alt_bm_file, strlen(alt_bm_file));
628 		free(alt_bm_file);
629 		alt_bm_file = (char *)NULL;
630 	}
631 
632 	log_file = (char *)xnmalloc(config_len + 9, sizeof(char));
633 	sprintf(log_file, "%s/log.cfm", config_dir);
634 
635 	hist_file = (char *)xnmalloc(config_len + 13, sizeof(char));
636 	sprintf(hist_file, "%s/history.cfm", config_dir);
637 
638 	if (!alt_config_file) {
639 		config_file = (char *)xnmalloc(config_len + pnl_len + 4, sizeof(char));
640 		sprintf(config_file, "%s/%src", config_dir, PNL);
641 	} else {
642 		config_file = savestring(alt_config_file, strlen(alt_config_file));
643 		free(alt_config_file);
644 		alt_config_file = (char *)NULL;
645 	}
646 
647 	profile_file = (char *)xnmalloc(config_len + 13, sizeof(char));
648 	sprintf(profile_file, "%s/profile.cfm", config_dir);
649 
650 	msg_log_file = (char *)xnmalloc(config_len + 14, sizeof(char));
651 	sprintf(msg_log_file, "%s/messages.cfm", config_dir);
652 
653 	mime_file = (char *)xnmalloc(config_len + 14, sizeof(char));
654 	sprintf(mime_file, "%s/mimelist.cfm", config_dir);
655 
656 	actions_file = (char *)xnmalloc(config_len + 13, sizeof(char));
657 	sprintf(actions_file, "%s/actions.cfm", config_dir);
658 
659 	remotes_file = (char *)xnmalloc(config_len + 10, sizeof(char));
660 	sprintf(remotes_file, "%s/nets.cfm", config_dir);
661 
662 	return;
663 }
664 
665 static int
import_rl_file(void)666 import_rl_file(void)
667 {
668 	if (!data_dir || !config_dir_gral)
669 		return EXIT_FAILURE;
670 
671 	char tmp[PATH_MAX];
672 	sprintf(tmp, "%s/readline.cfm", config_dir_gral);
673 	struct stat attr;
674 	if (lstat(tmp, &attr) == 0)
675 		return EXIT_SUCCESS;
676 
677 	char rl_file[PATH_MAX];
678 	snprintf(rl_file, PATH_MAX - 1, "%s/%s/readline.cfm", data_dir, PNL);
679 	if (stat(rl_file, &attr) == EXIT_SUCCESS) {
680 		char *cmd[] = {"cp", rl_file, config_dir_gral, NULL};
681 		if (launch_execve(cmd, FOREGROUND, E_NOSTDERR) == EXIT_SUCCESS)
682 			return EXIT_SUCCESS;
683 	}
684 
685 	return EXIT_FAILURE;
686 }
687 
688 int
create_config(char * file)689 create_config(char *file)
690 {
691 //	struct stat attr;
692 
693 	/* First, try to import it from DATADIR */
694 	char src_filename[NAME_MAX];
695 	snprintf(src_filename, NAME_MAX, "%src", PNL);
696 	if (import_from_data_dir(src_filename, file) == EXIT_SUCCESS)
697 		return EXIT_SUCCESS;
698 /*	if (data_dir) {
699 		char sys_file[PATH_MAX];
700 		snprintf(sys_file, PATH_MAX - 1, "%s/%s/%src", data_dir, PNL, PNL);
701 		if (stat(sys_file, &attr) == EXIT_SUCCESS) {
702 			char *cmd[] = {"cp", sys_file, file, NULL};
703 			if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS)
704 				return EXIT_SUCCESS;
705 		}
706 	} */
707 
708 	/* If not found, create it */
709 	int fd;
710 	FILE *config_fp = open_fstream_w(file, &fd);
711 
712 	if (!config_fp) {
713 		fprintf(stderr, "%s: fopen: %s: %s\n", PROGRAM_NAME, file, strerror(errno));
714 		return EXIT_FAILURE;
715 	}
716 
717 	/* Do not translate anything in the config file */
718 	fprintf(config_fp,
719 
720 "\t\t###########################################\n\
721 \t\t#                  CLIFM                  #\n\
722 \t\t#      The command line file manager      #\n\
723 \t\t###########################################\n\n"
724 
725 	    "# This is the configuration file for CliFM\n\n"
726 
727 	    "# Color schemes are stored in the colors directory. By default,\n\
728 # the 'default' color scheme is used. Visit %s\n\
729 # to get a few more\n\
730 ColorScheme=%s\n\n"
731 
732 	    "# The amount of files contained by a directory is informed next\n\
733 # to the directory name. However, this feature might slow things down when,\n\
734 # for example, listing files on a remote server. The filescounter can be\n\
735 # disabled here, via the --no-files-counter option, or using the 'fc'\n\
736 # command while in the program itself.\n\
737 FilesCounter=%s\n\n"
738 
739 		"# The character(s) used to construct the line dividing the list of files and\n\
740 # the prompt. if '0', print just an empty line; if only one char, this char\n\
741 # is printed reapeatedly to fulfill the screen; if 3 or more chars, only these\n\
742 # chars (no more) will be printed. Finally, if unset, print a special line\n\
743 # drawn with bow-drawing characters (not supported by all terminals/consoles)\n\
744 DividingLineChar='%c'\n\n"
745 
746 		"# How to list files: 0 = vertically (like ls(1) would), 1 = horizontally\n\
747 ListingMode=%d\n\n"
748 
749 		"# List files automatically after changing current directory\n\
750 AutoLs=%s\n\n"
751 
752 	    "# If set to true, print a map of the current position in the directory\n\
753 # history list, showing previous, current, and next entries\n\
754 DirhistMap=%s\n\n"
755 
756 		"# Use a regex expression to filter file names when listing files.\n\
757 # Example: !.*~$ to exclude backup files (ending with ~), or ^\\. to list \n\
758 # only hidden files. Do not quote the regular expression\n\
759 Filter=\n\n"
760 
761 	    "# Set the default copy command. Available options are: 0 = cp,\n\
762 # 1 = advcp, and 2 = wcp. Both 1 and 2 add a progress bar to cp.\n\
763 cpCmd=%d\n\n"
764 
765 	    "# Set the default move command. Available options are: 0 = mv,\n\
766 # and 1 = advmv. 1 adds a progress bar to mv.\n\
767 mvCmd=%d\n\n"
768 
769 	    "# The prompt line is built using string literals and/or one or more of\n\
770 # the following escape sequences:\n"
771 	    "# \\e: Escape character\n\
772 # \\h: The hostname, up to the first dot\n\
773 # \\u: The username\n\
774 # \\H: The full hostname\n\
775 # \\n: A newline character\n\
776 # \\r: A carriage return\n\
777 # \\a: A bell character\n\
778 # \\d: The date, in abbrevieted form (ex: 'Tue May 26')\n\
779 # \\s: The name of the shell (everything after the last slash) currently used\n\
780 # by CliFM\n\
781 # \\S: The number of the current workspace\n\
782 # \\l: Print an 'L' if running in light mode\n\
783 # \\P: Current profile name\n\
784 # \\t: The time, in 24-hour HH:MM:SS format\n\
785 # \\T: The time, in 12-hour HH:MM:SS format\n\
786 # \\@: The time, in 12-hour am/pm format\n\
787 # \\A: The time, in 24-hour HH:MM format\n\
788 # \\w: The full current working directory, with $HOME abbreviated with a tilde\n\
789 # \\W: The basename of $PWD, with $HOME abbreviated with a tilde\n\
790 # \\p: A mix of the two above, it abbreviates the current working directory \n\
791 # only if longer than PathMax (a value defined in the configuration file).\n\
792 # \\z: Exit code of the last executed command. :) if success and :( in case of\n\
793 # error\n\
794 # \\$ '#', if the effective user ID is 0, and '$' otherwise\n\
795 # \\nnn: The character whose ASCII code is the octal value nnn\n\
796 # \\\\: A backslash\n\
797 # \\[: Begin a sequence of non-printing characters. This is mostly used to\n\
798 # add color to the prompt line\n\
799 # \\]: End a sequence of non-printing characters\n\n"
800 
801 	    "Prompt=\"%s\"\n\n"
802 
803 	    "# If set to 'default', CliFM state information (selected files,\n\
804 # trashed files, current workspace, messages, and stealth mode) will be printed\n\
805 # to the left of the prompt. Otherwise, if set to 'custom', this information\n\
806 # will be stored in environment variables to be handled by the prompt string\n\
807 # itself. Consult the manpage for more information.\n\
808 PromptStyle=default\n\n"
809 
810 		"# A prompt to warn the user about invalid command names\n\
811 WarningPrompt=%s\n\n"
812 
813 		"# String to be used by the warning prompt. The color of this prompt\n\
814 # can be customized using the 'wp' code in the color scheme file\n\
815 WarningPromptStr=\"%s\"\n\n"
816 
817 		"# Should we add padding to ELN's. Possible values: 0:none, 1=zeroes\n\
818 # 2=spaces on the left, and 3=spaces on the right\n\
819 ELNPad=%d\n\n",
820 
821 	    COLORS_REPO,
822 		DEF_COLOR_SCHEME,
823 		DEF_FILES_COUNTER == 1 ? "true" : "false",
824 		DEF_DIV_LINE_CHAR,
825 		DEF_LISTING_MODE,
826 		DEF_AUTOLS == 1 ? "true" : "false",
827 		DEF_DIRHIST_MAP == 1 ? "true" : "false",
828 		DEF_CP_CMD,
829 		DEF_MV_CMD,
830 	    DEFAULT_PROMPT,
831 		DEF_WARNING_PROMPT == 1 ? "true" : "false",
832 	    DEF_WPROMPT_STR,
833 	    DEF_ELNPAD);
834 
835 	fprintf(config_fp,
836 
837 		"# TAB completion mode: either 'standard' (default) or 'fzf'\n\
838 TabCompletionMode=%s\n\n"
839 
840 		"# If FZF TAB completion mode is enabled, pass these options to fzf.\n\
841 # --height, --margin, +i/-i, and --query will be appended to set up the \n\
842 # completions interface.\n\
843 FzfTabOptions=%s\n\n"
844 
845 	    "# MaxPath is only used for the /p option of the prompt: the current working\n\
846 # directory will be abbreviated to its basename (everything after last slash)\n\
847 # whenever the current path is longer than MaxPath.\n\
848 MaxPath=%d\n\n"
849 
850 	    "WelcomeMessage=%s\n\n\
851 # Print %s's logo screen at startup\n\
852 SplashScreen=%s\n\n\
853 ShowHiddenFiles=%s\n\n\
854 # List files properties next to file names instead of just file names\n\
855 LongViewMode=%s\n\n\
856 # Keep a record of both external commands and internal commands able to\n\
857 # modify the files system (e.g. 'r', 'c', 'm', and so on)\n\
858 LogCmds=%s\n\n"
859 
860 	    "# Minimum length at which a file name can be trimmed in long view mode\n\
861 # (including ELN length and spaces). When running in long mode, this setting\n\
862 # overrides MaxFilenameLen\n\
863 MinFilenameTrim=%d\n\n"
864 
865 	    "# When a directory rank in the jump database is below MinJumpRank, it\n\
866 # will be forgotten\n\
867 MinJumpRank=%d\n\n"
868 
869 	    "# When the sum of all ranks in the jump database reaches MaxJumpTotalRank,\n\
870 # all ranks will be reduced 10%%, and those falling below MinJumpRank will\n\
871 # be deleted\n\
872 MaxJumpTotalRank=%d\n\n"
873 
874 	    "# Should CliFM be allowed to run external, shell commands?\n\
875 ExternalCommands=%s\n\n"
876 
877 	    "# Write the last visited directory to $XDG_CONFIG_HOME/clifm/.last to be\n\
878 # later accessed by the corresponding shell function at program exit.\n\
879 # To enable this feature consult the manpage.\n\
880 CdOnQuit=%s\n\n"
881 
882 	    "# If set to true, a command name that is the name of a directory or a\n\
883 # file is executed as if it were the argument to the the 'cd' or the \n\
884 # 'open' commands respectivelly: 'cd DIR' works the same as just 'DIR'\n\
885 # and 'open FILE' works the same as just 'FILE'.\n\
886 Autocd=%s\n\
887 AutoOpen=%s\n\n"
888 
889 	    "# If set to true, enable auto-suggestions.\n\
890 AutoSuggestions=%s\n\n"
891 
892 	    "# The following checks will be performed in the order specified\n\
893 # by SuggestionStrategy. Available checks:\n\
894 # a = Aliases names\n\
895 # b = Bookmarks names\n\
896 # c = Possible completions\n\
897 # e = ELN's\n\
898 # f = File names in current directory\n\
899 # h = Commands history\n\
900 # j = Jump database\n\
901 # Use a dash (-) to skip a check. Ex: 'eahfj-c' to skip the bookmarks check\n\
902 SuggestionStrategy=%s\n\n"
903 
904 	    "# If set to true, suggest file names using the corresponding\n\
905 # file type color (set via the color scheme file).\n\
906 SuggestFiletypeColor=%s\n\n"
907 
908 "SyntaxHighlighting=%s\n\n"
909 
910 	    "# If set to true, expand bookmark names into the corresponding bookmark\n\
911 # path: if the bookmark is \"name=/path\", \"name\" will be interpreted\n\
912 # as /path. TAB completion is also available for bookmark names.\n\
913 ExpandBookmarks=%s\n\n"
914 
915 	    "# In light mode, extra file type checks (except those provided by\n\
916 # the d_type field of the dirent structure (see readdir(3))\n\
917 # are disabled to speed up the listing process. stat(3) and access(3)\n\
918 # are not executed at all, so that we cannot know in advance if a file\n\
919 # is readable by the current user, if it is executable, SUID, SGID, if a\n\
920 # symlink is broken, and so on. The file extension check is ignored as\n\
921 # well, so that the color per extension feature is disabled.\n\
922 LightMode=%s\n\n",
923 
924 		DEF_FZFTAB == 1 ? "fzf" : "standard",
925 		DEF_FZFTAB_OPTIONS,
926 		DEF_MAX_PATH,
927 		DEF_WELCOME_MESSAGE == 1 ? "true" : "false",
928 		PROGRAM_NAME,
929 		DEF_SPLASH_SCREEN == 1 ? "true" : "false",
930 		DEF_SHOW_HIDDEN == 1 ? "true" : "false",
931 		DEF_LONG_VIEW == 1 ? "true" : "false",
932 		DEF_LOGS_ENABLED == 1 ? "true" : "false",
933 		DEF_MIN_NAME_TRIM,
934 		DEF_MIN_JUMP_RANK,
935 		DEF_MAX_JUMP_TOTAL_RANK,
936 		DEF_EXT_CMD_OK == 1 ? "true" : "false",
937 		DEF_CD_ON_QUIT == 1 ? "true" : "false",
938 		DEF_AUTOCD == 1 ? "true" : "false",
939 		DEF_AUTO_OPEN == 1 ? "true" : "false",
940 		DEF_SUGGESTIONS == 1 ? "true" : "false",
941 		DEF_SUG_STRATEGY,
942 		DEF_SUG_FILETYPE_COLOR == 1 ? "true" : "false",
943 		DEF_HIGHLIGHT == 1 ? "true" : "false",
944 		DEF_EXPAND_BOOKMARKS == 1 ? "true" : "false",
945 		DEF_LIGHT_MODE == 1 ? "true" : "false"
946 		);
947 
948 	fprintf(config_fp,
949 	    "# If running with colors, append directory indicator\n\
950 # to directories. If running without colors (via the --no-colors option),\n\
951 # append file type indicator at the end of file names: '/' for directories,\n\
952 # '@' for symbolic links, '=' for sockets, '|' for FIFO/pipes, '*'\n\
953 # for for executable files, and '?' for unknown file types. Bear in mind\n\
954 # that when running in light mode the check for executable files won't be\n\
955 # performed, and thereby no indicator will be added to executable files.\n\
956 Classify=%s\n\n"
957 
958 	    "# Should the Selection Box be shared among different profiles?\n\
959 ShareSelbox=%s\n\n"
960 
961 	    "# Choose the resource opener to open files with their default associated\n\
962 # application. If not set, 'lira', CLiFM's built-in opener, is used.\n\
963 Opener=\n\n"
964 
965 	    "# Only used when opening a directory via a new CliFM instance (with the 'x'\n\
966 # command), this option specifies the command to be used to launch a\n\
967 # terminal emulator to run CliFM on it.\n\
968 TerminalCmd='%s'\n\n"
969 
970 	    "# Choose sorting method: 0 = none, 1 = name, 2 = size, 3 = atime\n\
971 # 4 = btime (ctime if not available), 5 = ctime, 6 = mtime, 7 = version\n\
972 # (name if note available) 8 = extension, 9 = inode, 10 = owner, 11 = group\n\
973 # NOTE: the 'version' method is not available on FreeBSD\n\
974 Sort=%d\n\
975 # By default, CliFM sorts files from less to more (ex: from 'a' to 'z' if\n\
976 # using the \"name\" method). To invert this ordering, set SortReverse to\n\
977 # true (you can also use the --sort-reverse option or the 'st' command)\n\
978 SortReverse=%s\n\n"
979 
980 	    "# Print a usage tip at startup\n\
981 Tips=%s\n\n\
982 ListFoldersFirst=%s\n\n\
983 # Enable case sensitive listing for files in the current directory\n\
984 CaseSensitiveList=%s\n\n\
985 # Enable case sensitive lookup for the directory jumper function (via \n\
986 # the 'j' command)\n\
987 CaseSensitiveDirJump=%s\n\n\
988 # Enable case sensitive completion for file names\n\
989 CaseSensitivePathComp=%s\n\n\
990 # Enable case sensitive search\n\
991 CaseSensitiveSearch=%s\n\n\
992 Unicode=%s\n\n\
993 # Enable Mas, the files list pager (executed whenever the list of files\n\
994 # does not fit in the screen)\n\
995 Pager=%s\n\n"
996 
997 	"# Maximum file name length for listed files. Names larger than\n\
998 # MAXFILENAMELEN will be truncated at MAXFILENAMELEN using a tilde.\n\
999 # When running in long mode, this setting is overriden by MinFilenameTrim\n\
1000 MaxFilenameLen=\n\n"
1001 
1002 	"MaxHistory=%d\n\
1003 MaxDirhist=%d\n\
1004 MaxLog=%d\n\
1005 Icons=%s\n\
1006 DiskUsage=%s\n\n"
1007 
1008 		"# If set to true, always print the list of selected files. Since this\n\
1009 # list could become quite extensive, you can limit the number of printed \n\
1010 # entries using the MaxPrintSelfiles option (-1 = no limit, 0 = auto (never\n\
1011 # print more than half terminal height), or any custom value)\n\
1012 PrintSelfiles=%s\n\
1013 MaxPrintSelfiles=%d\n\n"
1014 
1015 	    "# If set to true, clear the screen before listing files\n\
1016 ClearScreen=%s\n\n"
1017 
1018 	    "# If not specified, StartingPath defaults to the current working\n\
1019 # directory.\n\
1020 StartingPath=\n\n"
1021 
1022 	    "# If set to true, start CliFM in the last visited directory (and in the\n\
1023 # last used workspace). This option overrides StartingPath.\n\
1024 RestoreLastPath=%s\n\n"
1025 
1026 	    "# If set to true, the 'r' command executes 'trash' instead of 'rm' to\n\
1027 # prevent accidental deletions.\n\
1028 TrashAsRm=%s\n\n"
1029 
1030 	    "# Set readline editing mode: 0 for vi and 1 for emacs (default).\n\
1031 RlEditMode=%d\n\n",
1032 
1033 		DEF_CLASSIFY == 1 ? "true" : "false",
1034 		DEF_SHARE_SELBOX == 1 ? "true" : "false",
1035 		DEFAULT_TERM_CMD,
1036 		DEF_SORT,
1037 		DEF_SORT_REVERSE == 1 ? "true" : "false",
1038 		DEF_TIPS == 1 ? "true" : "false",
1039 		DEF_LIST_FOLDERS_FIRST == 1 ? "true" : "false",
1040 		DEF_CASE_SENS_LIST == 1 ? "true" : "false",
1041 		DEF_CASE_SENS_DIRJUMP == 1 ? "true" : "false",
1042 		DEF_CASE_SENS_PATH_COMP == 1 ? "true" : "false",
1043 		DEF_CASE_SENS_SEARCH == 1 ? "true" : "false",
1044 		DEF_UNICODE == 1 ? "true" : "false",
1045 		DEF_PAGER == 1 ? "true" : "false",
1046 		DEF_MAX_HIST,
1047 		DEF_MAX_DIRHIST,
1048 		DEF_MAX_LOG,
1049 		DEF_ICONS == 1 ? "true" : "false",
1050 		DEF_DISK_USAGE == 1 ? "true" : "false",
1051 		DEF_PRINTSEL == 1 ? "true" : "false",
1052 		DEF_MAXPRINTSEL,
1053 		DEF_CLEAR_SCREEN == 1 ? "true" : "false",
1054 		DEF_RESTORE_LAST_PATH == 1 ? "true" : "false",
1055 		DEF_TRASRM == 1 ? "true" : "false",
1056 		DEF_RL_EDIT_MODE
1057 		);
1058 
1059 	fputs(
1060 
1061 	    "# ALIASES\n\
1062 #alias ls='ls --color=auto -A'\n\n"
1063 
1064 	    "# PROMPT COMMANDS\n\
1065 # Write below the commands you want to be executed before the prompt. Ex:\n\
1066 #promptcmd /usr/share/clifm/plugins/git_status.sh\n\
1067 #promptcmd date | awk '{print $1\", \"$2,$3\", \"$4}'\n\n"
1068 
1069 		"# AUTOCOMMANDS\n\
1070 # Control CliFM settings on a per directory basis. For more information\n\
1071 # consult the manpage\n\
1072 #autocmd /media/remotes/** lm=1,fc=0\n\
1073 #autocmd ~/important !printf \"Keep your fingers outta here!\n\" && read -n1\n\
1074 #autocmd ~/Downloads !/usr/share/clifm/plugins/fzfnav.sh\n\n",
1075 	    config_fp);
1076 
1077 	close_fstream(config_fp, fd);
1078 	return EXIT_SUCCESS;
1079 }
1080 
1081 static void
create_def_cscheme(void)1082 create_def_cscheme(void)
1083 {
1084 	if (!colors_dir)
1085 		return;
1086 
1087 	char *cscheme_file = (char *)xnmalloc(strlen(colors_dir) + 13, sizeof(char));
1088 	sprintf(cscheme_file, "%s/default.cfm", colors_dir);
1089 
1090 	/* If the file already exists, do nothing */
1091 	struct stat attr;
1092 	if (stat(cscheme_file, &attr) != -1) {
1093 		free(cscheme_file);
1094 		return;
1095 	}
1096 
1097 	int fd;
1098 	FILE *fp = open_fstream_w(cscheme_file, &fd);
1099 	if (!fp) {
1100 		_err('w', PRINT_PROMPT, "%s: Error creating default color scheme "
1101 			"file: %s\n", PROGRAM_NAME, strerror(errno));
1102 		free(cscheme_file);
1103 		return;
1104 	}
1105 
1106 	fprintf(fp, "# Default color scheme for %s\n\n\
1107 # FiletypeColors defines the color used for file types when listing files,\n\
1108 # just as InterfaceColors defines colors for CliFM's interface and ExtColors\n\
1109 # for file extensions. They all make use of the same format used by the\n\
1110 # LS_COLORS environment variable. Thus, \"di=01;34\" means that (non-empty)\n\
1111 # directories will be listed in bold blue.\n\
1112 # Color codes are traditional ANSI escape sequences less the escape char and\n\
1113 # the final 'm'. 8 bit, 256 colors, and RGB colors are supported.\n\
1114 # A detailed explanation of all these codes can be found in the manpage.\n\n"
1115 
1116 		    "FiletypeColors=\"%s\"\n\n"
1117 
1118 		    "InterfaceColors=\"%s\"\n\n"
1119 
1120 		    "# Same as FiletypeColors, but for file extensions. The format is always\n\
1121 # *.EXT=COLOR\n"
1122 #ifndef _NO_ICONS
1123 		    "ExtColors=\"%s\"\n\n"
1124 
1125 		    "DirIconsColor=\"00;33\"\n",
1126 #else
1127 		    "ExtColors=\"%s\"\n\n",
1128 #endif
1129 		PROGRAM_NAME,
1130 	    DEF_FILE_COLORS,
1131 	    DEF_IFACE_COLORS,
1132 	    DEF_EXT_COLORS);
1133 
1134 	close_fstream(fp, fd);
1135 	free(cscheme_file);
1136 	return;
1137 }
1138 
1139 static int
create_remotes_file(void)1140 create_remotes_file(void)
1141 {
1142 	if (!remotes_file || !*remotes_file)
1143 		return EXIT_FAILURE;
1144 
1145 	struct stat attr;
1146 	if (stat(remotes_file, &attr) == EXIT_SUCCESS)
1147 		return EXIT_SUCCESS;
1148 
1149 	int fd;
1150 	FILE *fp = open_fstream_w(remotes_file, &fd);
1151 	if (!fp) {
1152 		_err('e', PRINT_PROMPT, "%s: '%s': %s\n", PROGRAM_NAME,
1153 		    remotes_file, strerror(errno));
1154 		return EXIT_FAILURE;
1155 	}
1156 
1157 	fprintf(fp, "#####################################\n"
1158 		"# Remotes management file for %s #\n"
1159 		"#####################################\n\n"
1160 		"# Blank and commented lines are omitted\n\n"
1161 		"# Example:\n"
1162 		"# A name for this remote. It will be used by the 'net' command\n"
1163 		"# and will be available for TAB completion\n"
1164 		"# [work_smb]\n\n"
1165 		"# Comment=My work samba server\n"
1166 		"# Mountpoint=/home/user/.config/clifm/mounts/work_smb\n\n"
1167 		"# Use %%m as a placeholder for Mountpoint\n"
1168 		"# MountCmd=mount.cifs //WORK_IP/shared %%m -o OPTIONS\n"
1169 		"# UnmountCmd=umount %%m\n\n"
1170 		"# Automatically mount this remote at startup\n"
1171 		"# AutoMount=true\n\n"
1172 		"# Automatically unmount this remote at exit\n"
1173 		"# AutoUnmount=true\n\n", PROGRAM_NAME);
1174 
1175 	close_fstream(fp, fd);
1176 	return EXIT_SUCCESS;
1177 }
1178 
1179 static void
create_config_files(void)1180 create_config_files(void)
1181 {
1182 	struct stat attr;
1183 
1184 			/* #############################
1185 			 * #        TRASH DIRS         #
1186 			 * ############################# */
1187 #ifndef _NO_TRASH
1188 	if (stat(trash_dir, &attr) == -1) {
1189 		char *trash_files = (char *)NULL;
1190 		trash_files = (char *)xnmalloc(strlen(trash_dir) + 7, sizeof(char));
1191 
1192 		sprintf(trash_files, "%s/files", trash_dir);
1193 		char *trash_info = (char *)NULL;
1194 		trash_info = (char *)xnmalloc(strlen(trash_dir) + 6, sizeof(char));
1195 
1196 		sprintf(trash_info, "%s/info", trash_dir);
1197 		char *cmd[] = {"mkdir", "-p", trash_files, trash_info, NULL};
1198 
1199 		int ret = launch_execve(cmd, FOREGROUND, E_NOFLAG);
1200 		free(trash_files);
1201 		free(trash_info);
1202 
1203 		if (ret != EXIT_SUCCESS) {
1204 			trash_ok = 0;
1205 			_err('w', PRINT_PROMPT, _("%s: mkdir: '%s': Error creating trash "
1206 				"directory. Trash function disabled\n"), PROGRAM_NAME, trash_dir);
1207 		}
1208 	}
1209 
1210 	/* If it exists, check it is writable */
1211 	else if (access(trash_dir, W_OK) == -1) {
1212 		trash_ok = 0;
1213 		_err('w', PRINT_PROMPT, _("%s: '%s': Directory not writable. "
1214 				"Trash function disabled\n"), PROGRAM_NAME, trash_dir);
1215 	}
1216 #endif
1217 				/* ####################
1218 				 * #    CONFIG DIR    #
1219 				 * #################### */
1220 
1221 	/* If the config directory doesn't exist, create it */
1222 	/* Use the mkdir(1) to let it handle parent directories */
1223 	if (stat(config_dir, &attr) == -1) {
1224 		char *tmp_cmd[] = {"mkdir", "-p", config_dir, NULL};
1225 		if (launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) {
1226 			config_ok = 0;
1227 			_err('e', PRINT_PROMPT, _("%s: mkdir: '%s': Error creating "
1228 				"configuration directory. Bookmarks, commands logs, and "
1229 				"command history are disabled. Program messages won't be "
1230 				"persistent. Using default options\n"),
1231 			    PROGRAM_NAME, config_dir);
1232 			return;
1233 		}
1234 	}
1235 
1236 	/* If it exists, check it is writable */
1237 	else if (access(config_dir, W_OK) == -1) {
1238 		config_ok = 0;
1239 		_err('e', PRINT_PROMPT, _("%s: '%s': Directory not writable. Bookmarks, "
1240 			"commands logs, and commands history are disabled. Program messages "
1241 			"won't be persistent. Using default options\n"),
1242 		    PROGRAM_NAME, config_dir);
1243 		return;
1244 	}
1245 
1246 				/* #####################
1247 				 * #    CONFIG FILE    #
1248 				 * #####################*/
1249 
1250 	if (stat(config_file, &attr) == -1) {
1251 		if (create_config(config_file) == EXIT_SUCCESS)
1252 			config_ok = 1;
1253 		else
1254 			config_ok = 0;
1255 	}
1256 
1257 	if (!config_ok)
1258 		return;
1259 
1260 				/* ######################
1261 				 * #    PROFILE FILE    #
1262 				 * ###################### */
1263 
1264 	if (stat(profile_file, &attr) == -1) {
1265 		FILE *profile_fp = fopen(profile_file, "w");
1266 		if (!profile_fp) {
1267 			_err('e', PRINT_PROMPT, "%s: fopen: '%s': %s\n", PROGRAM_NAME,
1268 			    profile_file, strerror(errno));
1269 		} else {
1270 			fprintf(profile_fp, _("#%s profile\n\
1271 # Write here the commands you want to be executed at startup\n\
1272 # Ex:\n#echo -e \"%s, the anti-eye-candy/KISS file manager\"\n"),
1273 			    PROGRAM_NAME, PROGRAM_NAME);
1274 			fclose(profile_fp);
1275 		}
1276 	}
1277 
1278 				/* #####################
1279 				 * #    COLORS DIR     #
1280 				 * ##################### */
1281 
1282 	if (stat(colors_dir, &attr) == -1) {
1283 /*		char *cmd[] = {"mkdir", colors_dir, NULL};
1284 		if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { */
1285 		if (xmkdir(colors_dir, S_IRWXU) == EXIT_FAILURE) {
1286 			_err('w', PRINT_PROMPT, _("%s: mkdir: Error creating colors "
1287 				"directory. Using the default color scheme\n"),
1288 			    PROGRAM_NAME);
1289 		}
1290 	}
1291 
1292 	/* Generate the default color scheme file */
1293 	create_def_cscheme();
1294 
1295 				/* #####################
1296 				 * #      PLUGINS      #
1297 				 * #####################*/
1298 
1299 	if (stat(plugins_dir, &attr) == -1) {
1300 /*		char *cmd[] = {"mkdir", plugins_dir, NULL};
1301 		if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS) { */
1302 		if (xmkdir(plugins_dir, S_IRWXU) == EXIT_FAILURE) {
1303 			_err('e', PRINT_PROMPT, _("%s: mkdir: Error creating plugins "
1304 				"directory. The actions function is disabled\n"),
1305 			    PROGRAM_NAME);
1306 		}
1307 	}
1308 
1309 	import_rl_file();
1310 	create_actions_file(actions_file);
1311 	create_mime_file(mime_file, 0);
1312 	create_remotes_file();
1313 }
1314 
1315 int
create_mime_file(char * file,int new_prof)1316 create_mime_file(char *file, int new_prof)
1317 {
1318 	struct stat attr;
1319 	if (stat(file, &attr) == EXIT_SUCCESS)
1320 		return EXIT_SUCCESS;
1321 
1322 	if (!data_dir)
1323 		return EXIT_FAILURE;
1324 
1325 	char sys_mimelist[PATH_MAX];
1326 	snprintf(sys_mimelist, PATH_MAX - 1, "%s/%s/mimelist.cfm", data_dir, PNL);
1327 
1328 	if (stat(sys_mimelist, &attr) == -1) {
1329 		_err('e', PRINT_PROMPT, "%s: %s: %s\n", PROGRAM_NAME,
1330 			sys_mimelist, strerror(errno));
1331 		return EXIT_FAILURE;
1332 	}
1333 
1334 	char *cmd[] = {"cp", "-f", sys_mimelist, file, NULL};
1335 	if (launch_execve(cmd, FOREGROUND, E_NOFLAG) == EXIT_SUCCESS) {
1336 		if (!new_prof) {
1337 			_err('n', PRINT_PROMPT, _("%s created a new MIME list file (%s) "
1338 				"It is recommended to edit this file (entering 'mm edit' or "
1339 				"pressing F6) to add the programs you use and remove those "
1340 				"you don't. This will make the process of opening files "
1341 				"faster and smoother\n"),
1342 				PROGRAM_NAME, file, sys_mimelist);
1343 		}
1344 		return EXIT_SUCCESS;
1345 	}
1346 
1347 	return EXIT_FAILURE;
1348 }
1349 
1350 int
create_bm_file(void)1351 create_bm_file(void)
1352 {
1353 	if (!bm_file)
1354 		return EXIT_FAILURE;
1355 
1356 	struct stat file_attrib;
1357 	if (stat(bm_file, &file_attrib) == -1) {
1358 		FILE *fp = fopen(bm_file, "w+");
1359 		if (!fp) {
1360 			_err('e', PRINT_PROMPT, "bookmarks: '%s': %s\n", bm_file,
1361 			    strerror(errno));
1362 			return EXIT_FAILURE;
1363 		} else {
1364 			fprintf(fp, "### This is the bookmarks file for %s ###\n\n"
1365 				    "# Empty and commented lines are ommited\n"
1366 				    "# The bookmarks syntax is: [shortcut]name:path\n"
1367 				    "# Example:\n"
1368 				    "[c]clifm:%s\n",
1369 			    PROGRAM_NAME, config_dir ? config_dir : "path/to/file");
1370 			fclose(fp);
1371 		}
1372 	}
1373 
1374 	return EXIT_SUCCESS;
1375 }
1376 
1377 static char *
get_line_value(char * line)1378 get_line_value(char *line)
1379 {
1380 	char *opt = strchr(line, '=');
1381 	if (!opt || !*opt || !*(++opt) )
1382 		return (char *)NULL;
1383 
1384 	return remove_quotes(opt);
1385 }
1386 
1387 static void
read_config(void)1388 read_config(void)
1389 {
1390 	int ret = -1;
1391 
1392 	int fd;
1393 	FILE *config_fp = open_fstream_r(config_file, &fd);
1394 	if (!config_fp) {
1395 		_err('e', PRINT_PROMPT, _("%s: fopen: '%s': %s. Using default values.\n"),
1396 		    PROGRAM_NAME, config_file, strerror(errno));
1397 		return;
1398 	}
1399 
1400 	if (xargs.rl_vi_mode == 1)
1401 		rl_vi_editing_mode(1, 0);
1402 
1403 	max_name_len = UNSET;
1404 
1405 	*div_line_char = '\0';
1406 #define MAX_BOOL 6 /* false (5) + 1 */
1407 	/* starting path(14) + PATH_MAX + \n(1)*/
1408 	char line[PATH_MAX + 15];
1409 
1410 	while (fgets(line, (int)sizeof(line), config_fp)) {
1411 
1412 		if (*line == '\n' || *line == '#')
1413 			continue;
1414 /* 		if (*line == '\n' || (*line == '#' && line[1] != 'E'))
1415 			continue;
1416 		if (*line == '#' && strncmp(line, "#END OF OPTIONS", 15) == 0)
1417 			break; */
1418 
1419 		else if (*line == 'a' && strncmp(line, "autocmd ", 8) == 0)
1420 			parse_autocmd_line(line + 8);
1421 
1422 		else if (xargs.autocd == UNSET && *line == 'A'
1423 		&& strncmp(line, "Autocd=", 7) == 0) {
1424 			char opt_str[MAX_BOOL] = "";
1425 			ret = sscanf(line, "Autocd=%5s\n", opt_str);
1426 			if (ret == -1)
1427 				continue;
1428 			if (strncmp(opt_str, "true", 4) == 0)
1429 				autocd = 1;
1430 			else if (strncmp(opt_str, "false", 5) == 0)
1431 				autocd = 0;
1432 		}
1433 
1434 		else if (xargs.autojump == UNSET && *line == 'A'
1435 		&& strncmp(line, "AutoJump=", 9) == 0) {
1436 			char opt_str[MAX_BOOL] = "";
1437 			ret = sscanf(line, "AutoJump=%5s\n", opt_str);
1438 			if (ret == -1)
1439 				continue;
1440 			if (strncmp(opt_str, "true", 4) == 0)
1441 				autojump = autocd = 1;
1442 			else if (strncmp(opt_str, "false", 5) == 0)
1443 				autojump = 0;
1444 		}
1445 
1446 		else if (xargs.auto_open == UNSET && *line == 'A'
1447 		&& strncmp(line, "AutoOpen=", 9) == 0) {
1448 			char opt_str[MAX_BOOL] = "";
1449 			ret = sscanf(line, "AutoOpen=%5s\n", opt_str);
1450 			if (ret == -1)
1451 				continue;
1452 			if (strncmp(opt_str, "true", 4) == 0)
1453 				auto_open = 1;
1454 			else if (strncmp(opt_str, "false", 5) == 0)
1455 				auto_open = 0;
1456 		}
1457 
1458 #ifndef _NO_SUGGESTIONS
1459 		else if (xargs.suggestions == UNSET && *line == 'A'
1460 		&& strncmp(line, "AutoSuggestions=", 16) == 0) {
1461 			char opt_str[MAX_BOOL] = "";
1462 			ret = sscanf(line, "AutoSuggestions=%5s\n", opt_str);
1463 			if (ret == -1)
1464 				continue;
1465 			if (strncmp(opt_str, "true", 4) == 0)
1466 				suggestions = 1;
1467 			else if (strncmp(opt_str, "false", 5) == 0)
1468 				suggestions = 0;
1469 		}
1470 #endif
1471 
1472 		else if (xargs.case_sens_dirjump == UNSET && *line == 'C'
1473 		&& strncmp(line, "CaseSensitiveDirJump=", 21) == 0) {
1474 			char opt_str[MAX_BOOL] = "";
1475 			ret = sscanf(line, "CaseSensitiveDirJump=%5s\n", opt_str);
1476 
1477 			if (ret == -1)
1478 				continue;
1479 
1480 			if (strncmp(opt_str, "true", 4) == 0)
1481 				case_sens_dirjump = 1;
1482 			else if (strncmp(opt_str, "false", 5) == 0)
1483 				case_sens_dirjump = 0;
1484 		}
1485 
1486 		else if (*line == 'C'
1487 		&& strncmp(line, "CaseSensitiveSearch=", 20) == 0) {
1488 			char opt_str[MAX_BOOL] = "";
1489 			ret = sscanf(line, "CaseSensitiveSearch=%5s\n", opt_str);
1490 
1491 			if (ret == -1)
1492 				continue;
1493 
1494 			if (strncmp(opt_str, "true", 4) == 0)
1495 				case_sens_search = 1;
1496 			else if (strncmp(opt_str, "false", 5) == 0)
1497 				case_sens_search = 0;
1498 		}
1499 
1500 		else if (xargs.sensitive == UNSET && *line == 'C'
1501 		&& strncmp(line, "CaseSensitiveList=", 18) == 0) {
1502 			char opt_str[MAX_BOOL] = "";
1503 			ret = sscanf(line, "CaseSensitiveList=%5s\n",
1504 			    opt_str);
1505 			if (ret == -1)
1506 				continue;
1507 			if (strncmp(opt_str, "true", 4) == 0)
1508 				case_sensitive = 1;
1509 			else if (strncmp(opt_str, "false", 5) == 0)
1510 				case_sensitive = 0;
1511 		}
1512 
1513 		else if (xargs.case_sens_path_comp == UNSET && *line == 'C'
1514 		&& strncmp(line, "CaseSensitivePathComp=", 22) == 0) {
1515 			char opt_str[MAX_BOOL] = "";
1516 			ret = sscanf(line, "CaseSensitivePathComp=%5s\n", opt_str);
1517 			if (ret == -1)
1518 				continue;
1519 			if (strncmp(opt_str, "true", 4) == 0)
1520 				case_sens_path_comp = 1;
1521 			else if (strncmp(opt_str, "false", 5) == 0)
1522 				case_sens_path_comp = 0;
1523 		}
1524 
1525 		else if (xargs.autols == UNSET && *line == 'A'
1526 		&& strncmp(line, "AutoLs=", 7) == 0) {
1527 			char opt_str[MAX_BOOL] = "";
1528 			ret = sscanf(line, "AutoLs=%5s\n",
1529 			    opt_str);
1530 			if (ret == -1)
1531 				continue;
1532 			if (strncmp(opt_str, "true", 4) == 0)
1533 				autols = 1;
1534 			else if (strncmp(opt_str, "false", 5) == 0)
1535 				autols = 0;
1536 		}
1537 
1538 		else if (xargs.cd_on_quit == UNSET && *line == 'C'
1539 		&& strncmp(line, "CdOnQuit=", 9) == 0) {
1540 			char opt_str[MAX_BOOL] = "";
1541 			ret = sscanf(line, "CdOnQuit=%5s\n", opt_str);
1542 			if (ret == -1)
1543 				continue;
1544 			if (strncmp(opt_str, "true", 4) == 0)
1545 				cd_on_quit = 1;
1546 			else if (strncmp(opt_str, "false", 5) == 0)
1547 				cd_on_quit = 0;
1548 		}
1549 
1550 		else if (xargs.classify == UNSET && *line == 'C'
1551 		&& strncmp(line, "Classify=", 9) == 0) {
1552 			char opt_str[MAX_BOOL] = "";
1553 			ret = sscanf(line, "Classify=%5s\n", opt_str);
1554 			if (ret == -1)
1555 				continue;
1556 			if (strncmp(opt_str, "true", 4) == 0)
1557 				classify = 1;
1558 			else if (strncmp(opt_str, "false", 5) == 0)
1559 				classify = 0;
1560 		}
1561 
1562 		else if (xargs.clear_screen == UNSET && *line == 'C'
1563 		&& strncmp(line, "ClearScreen=", 12) == 0) {
1564 			char opt_str[MAX_BOOL] = "";
1565 			ret = sscanf(line, "ClearScreen=%5s\n",
1566 			    opt_str);
1567 			if (ret == -1)
1568 				continue;
1569 			if (strncmp(opt_str, "true", 4) == 0)
1570 				clear_screen = 1;
1571 			else if (strncmp(opt_str, "false", 5) == 0)
1572 				clear_screen = 0;
1573 		}
1574 
1575 		else if (!usr_cscheme && *line == 'C' && strncmp(line, "ColorScheme=", 12) == 0) {
1576 			char *opt = strchr(line, '=');
1577 			if (!opt)
1578 				continue;
1579 
1580 			size_t len = strlen(opt);
1581 			if (opt[len - 1] == '\n')
1582 				opt[len - 1] = '\0';
1583 
1584 			if (!*(++opt))
1585 				continue;
1586 
1587 			usr_cscheme = savestring(opt, len);
1588 		}
1589 
1590 		else if (*line == 'c' && strncmp(line, "cpCmd=", 6) == 0) {
1591 			int opt_num = 0;
1592 			ret = sscanf(line, "cpCmd=%d\n", &opt_num);
1593 			if (ret == -1)
1594 				continue;
1595 			if (opt_num >= 0 && opt_num <= 2)
1596 				cp_cmd = opt_num;
1597 			else /* default (sort by name) */
1598 				cp_cmd = DEF_CP_CMD;
1599 		}
1600 
1601 		else if (xargs.dirmap == UNSET && *line == 'D'
1602 		&& strncmp(line, "DirhistMap=", 11) == 0) {
1603 			char opt_str[MAX_BOOL] = "";
1604 			ret = sscanf(line, "DirhistMap=%5s\n", opt_str);
1605 			if (ret == -1)
1606 				continue;
1607 			if (strncmp(opt_str, "true", 4) == 0)
1608 				dirhist_map = 1;
1609 			else if (strncmp(opt_str, "false", 5) == 0)
1610 				dirhist_map = 0;
1611 		}
1612 
1613 		else if (xargs.disk_usage == UNSET && *line == 'D'
1614 		&& strncmp(line, "DiskUsage=", 10) == 0) {
1615 			char opt_str[MAX_BOOL] = "";
1616 			ret = sscanf(line, "DiskUsage=%5s\n", opt_str);
1617 			if (ret == -1)
1618 				continue;
1619 			if (strncmp(opt_str, "true", 4) == 0)
1620 				disk_usage = 1;
1621 			else if (strncmp(opt_str, "false", 5) == 0)
1622 				disk_usage = 0;
1623 		}
1624 
1625 		else if (*line == 'D' && strncmp(line, "DividingLineChar=", 17) == 0) {
1626 			char *opt = strchr(line, '=');
1627 			if (!opt || !*opt || !*(++opt)) {
1628 				div_line_char[0] = '\0';
1629 			} else {
1630 				char *tmp = remove_quotes(opt);
1631 				if (tmp)
1632 					xstrsncpy(div_line_char, tmp, NAME_MAX);
1633 				else
1634 					div_line_char[0] = '\0';
1635 			}
1636 		}
1637 
1638 		else if (*line == 'E' && strncmp(line, "ELNPad=", 7) == 0) {
1639 			char *opt = strchr(line, '=');
1640 			if (!opt || !*opt || !*(++opt)) {
1641 				elnpad = DEF_ELNPAD;
1642 			} else {
1643 				int ivalue = atoi(opt);
1644 				switch(ivalue) {
1645 				case NOPAD: elnpad = NOPAD; break;
1646 				case ZEROPAD: elnpad = ZEROPAD; break;
1647 				case LEFTSPACEPAD: elnpad = LEFTSPACEPAD; break;
1648 				case RIGHTSPACEPAD: elnpad = RIGHTSPACEPAD; break;
1649 				default: elnpad = DEF_ELNPAD;
1650 				}
1651 			}
1652 		}
1653 
1654 		else if (xargs.expand_bookmarks == UNSET && *line == 'E'
1655 		&& strncmp(line, "ExpandBookmarks=", 16) == 0) {
1656 			char opt_str[MAX_BOOL] = "";
1657 			ret = sscanf(line, "ExpandBookmarks=%5s\n",
1658 			    opt_str);
1659 			if (ret == -1)
1660 				continue;
1661 			if (strncmp(opt_str, "true", 4) == 0)
1662 				expand_bookmarks = 1;
1663 			else if (strncmp(opt_str, "false", 5) == 0)
1664 				expand_bookmarks = 0;
1665 		}
1666 
1667 		else if (xargs.ext == UNSET && *line == 'E'
1668 		&& strncmp(line, "ExternalCommands=", 17) == 0) {
1669 			char opt_str[MAX_BOOL] = "";
1670 			ret = sscanf(line, "ExternalCommands=%5s\n",
1671 			    opt_str);
1672 			if (ret == -1)
1673 				continue;
1674 			if (strncmp(opt_str, "true", 4) == 0)
1675 				ext_cmd_ok = 1;
1676 			else if (strncmp(opt_str, "false", 5) == 0)
1677 				ext_cmd_ok = 0;
1678 		}
1679 
1680 		else if (xargs.files_counter == UNSET && *line == 'F'
1681 		&& strncmp(line, "FilesCounter=", 13) == 0) {
1682 			char opt_str[MAX_BOOL] = "";
1683 			ret = sscanf(line, "FilesCounter=%5s\n", opt_str);
1684 			if (ret == -1)
1685 				continue;
1686 			if (strncmp(opt_str, "true", 4) == 0)
1687 				files_counter = 1;
1688 			else if (strncmp(opt_str, "false", 5) == 0)
1689 				files_counter = 0;
1690 		}
1691 
1692 		else if (!_filter && *line == 'F' && strncmp(line, "Filter=", 7) == 0) {
1693 			char *opt_str = strchr(line, '=');
1694 			if (!opt_str)
1695 				continue;
1696 			size_t len = strlen(opt_str);
1697 			if (opt_str[len - 1] == '\n')
1698 				opt_str[len - 1] = '\0';
1699 
1700 			if (!*(++opt_str))
1701 				continue;
1702 
1703 			if (*opt_str == '!') {
1704 				filter_rev = 1;
1705 				opt_str++;
1706 				len--;
1707 			} else {
1708 				filter_rev = 0;
1709 			}
1710 
1711 			_filter = savestring(opt_str, len);
1712 		}
1713 
1714 #ifndef _NO_HIGHLIGHT
1715 		else if (xargs.highlight == UNSET && *line == 'S'
1716 		&& strncmp(line, "SyntaxHighlighting=", 19) == 0) {
1717 			char opt_str[MAX_BOOL] = "";
1718 			ret = sscanf(line, "SyntaxHighlighting=%5s\n", opt_str);
1719 			if (ret == -1)
1720 				continue;
1721 			if (strncmp(opt_str, "true", 4) == 0)
1722 				highlight = 1;
1723 			else if (strncmp(opt_str, "false", 5) == 0)
1724 				highlight = 0;
1725 		}
1726 #endif /* !_NO_HIGHLIGHT */
1727 
1728 #ifndef _NO_ICONS
1729 		else if (xargs.icons == UNSET && *line == 'I'
1730 		&& strncmp(line, "Icons=", 6) == 0) {
1731 			char opt_str[MAX_BOOL] = "";
1732 			ret = sscanf(line, "Icons=%5s\n", opt_str);
1733 			if (ret == -1)
1734 				continue;
1735 			if (strncmp(opt_str, "true", 4) == 0)
1736 				icons = 1;
1737 			else if (strncmp(opt_str, "false", 5) == 0)
1738 				icons = 0;
1739 		}
1740 #endif /* !_NO_ICONS */
1741 
1742 		else if (xargs.light == UNSET && *line == 'L'
1743 		&& strncmp(line, "LightMode=", 10) == 0) {
1744 			char opt_str[MAX_BOOL] = "";
1745 			ret = sscanf(line, "LightMode=%5s\n", opt_str);
1746 			if (ret == -1)
1747 				continue;
1748 			if (strncmp(opt_str, "true", 4) == 0)
1749 				light_mode = 1;
1750 			else if (strncmp(opt_str, "false", 5) == 0)
1751 				light_mode = 0;
1752 		}
1753 
1754 		else if (xargs.ffirst == UNSET && *line == 'L'
1755 		&& strncmp(line, "ListFoldersFirst=", 17) == 0) {
1756 			char opt_str[MAX_BOOL] = "";
1757 			ret = sscanf(line, "ListFoldersFirst=%5s\n",
1758 			    opt_str);
1759 			if (ret == -1)
1760 				continue;
1761 			if (strncmp(opt_str, "true", 4) == 0)
1762 				list_folders_first = 1;
1763 			else if (strncmp(opt_str, "false", 5) == 0)
1764 				list_folders_first = 0;
1765 		}
1766 
1767 		else if (xargs.horizontal_list == UNSET && *line == 'L'
1768 		&& strncmp(line, "ListingMode=", 12) == 0) {
1769 			char *opt = strchr(line, '=');
1770 			if (!opt || !*opt || !*(++opt)) {
1771 				listing_mode = DEF_LISTING_MODE;
1772 			} else {
1773 				int ivalue = atoi(opt);
1774 				switch(ivalue) {
1775 				case VERTLIST: listing_mode = VERTLIST; break;
1776 				case HORLIST: listing_mode = HORLIST; break;
1777 				default: listing_mode = DEF_LISTING_MODE;
1778 				}
1779 			}
1780 		}
1781 
1782 		else if (xargs.longview == UNSET && *line == 'L'
1783 		&& strncmp(line, "LongViewMode=", 13) == 0) {
1784 			char opt_str[MAX_BOOL] = "";
1785 			ret = sscanf(line, "LongViewMode=%5s\n",
1786 			    opt_str);
1787 			if (ret == -1)
1788 				continue;
1789 			if (strncmp(opt_str, "true", 4) == 0)
1790 				long_view = 1;
1791 			else if (strncmp(opt_str, "false", 5) == 0)
1792 				long_view = 0;
1793 		}
1794 
1795 		else if (xargs.logs == UNSET && *line == 'L'
1796 		&& strncmp(line, "LogCmds=", 8) == 0) {
1797 			char opt_str[MAX_BOOL] = "";
1798 			ret = sscanf(line, "LogCmds=%5s\n", opt_str);
1799 			if (ret == -1)
1800 				continue;
1801 			if (strncmp(opt_str, "true", 4) == 0)
1802 				logs_enabled = 1;
1803 			else if (strncmp(opt_str, "false", 5) == 0)
1804 				logs_enabled = 0;
1805 		}
1806 
1807 		else if (xargs.max_dirhist == UNSET && *line == 'M'
1808 		&& strncmp(line, "MaxDirhist=", 11) == 0) {
1809 			int opt_num = 0;
1810 			ret = sscanf(line, "MaxDirhist=%d\n", &opt_num);
1811 			if (ret == -1)
1812 				continue;
1813 			if (opt_num >= 0)
1814 				max_dirhist = opt_num;
1815 			else /* default */
1816 				max_dirhist = DEF_MAX_DIRHIST;
1817 		}
1818 
1819 		else if (*line == 'M' && strncmp(line, "MaxFilenameLen=", 15) == 0) {
1820 			int opt_num = 0;
1821 			sscanf(line, "MaxFilenameLen=%d\n", &opt_num);
1822 			if (opt_num <= 0)
1823 				continue;
1824 			max_name_len = opt_num;
1825 		}
1826 
1827 		else if (*line == 'M' && strncmp(line, "MaxHistory=", 11) == 0) {
1828 			int opt_num = 0;
1829 			sscanf(line, "MaxHistory=%d\n", &opt_num);
1830 			if (opt_num <= 0)
1831 				continue;
1832 			max_hist = opt_num;
1833 		}
1834 
1835 		else if (*line == 'M' && strncmp(line, "MaxJumpTotalRank=", 17) == 0) {
1836 			int opt_num = 0;
1837 			ret = sscanf(line, "MaxJumpTotalRank=%d\n", &opt_num);
1838 			if (ret == -1 || opt_num < INT_MIN || opt_num > INT_MAX)
1839 				continue;
1840 			max_jump_total_rank = opt_num;
1841 		}
1842 
1843 		else if (*line == 'M' && strncmp(line, "MaxLog=", 7) == 0) {
1844 			int opt_num = 0;
1845 			sscanf(line, "MaxLog=%d\n", &opt_num);
1846 			if (opt_num <= 0)
1847 				continue;
1848 			max_log = opt_num;
1849 		}
1850 
1851 		else if (xargs.max_path == UNSET && *line == 'M'
1852 		&& strncmp(line, "MaxPath=", 8) == 0) {
1853 			int opt_num = 0;
1854 			sscanf(line, "MaxPath=%d\n", &opt_num);
1855 			if (opt_num <= 0)
1856 				continue;
1857 			max_path = opt_num;
1858 		}
1859 
1860 		else if (*line == 'M' && strncmp(line, "MaxPrintSelfiles=", 17) == 0) {
1861 			int opt_num = 0;
1862 			ret = sscanf(line, "MaxPrintSelfiles=%d\n", &opt_num);
1863 			if (ret == -1)
1864 				continue;
1865 			max_printselfiles = opt_num;
1866 		}
1867 
1868 		else if (*line == 'M' && strncmp(line, "MinFilenameTrim=", 16) == 0) {
1869 			int opt_num = 0;
1870 			ret = sscanf(line, "MinFilenameTrim=%d\n", &opt_num);
1871 			if (ret == -1)
1872 				continue;
1873 			if (opt_num > 0)
1874 				min_name_trim = opt_num;
1875 			else /* default */
1876 				min_name_trim = DEF_MIN_NAME_TRIM;
1877 		}
1878 
1879 		else if (*line == 'M' && strncmp(line, "MinJumpRank=", 12) == 0) {
1880 			int opt_num = 0;
1881 			ret = sscanf(line, "MinJumpRank=%d\n", &opt_num);
1882 			if (ret == -1 || opt_num < INT_MIN || opt_num > INT_MAX)
1883 				continue;
1884 			min_jump_rank = opt_num;
1885 		}
1886 
1887 		else if (*line == 'm' && strncmp(line, "mvCmd=", 6) == 0) {
1888 			int opt_num = 0;
1889 			ret = sscanf(line, "mvCmd=%d\n", &opt_num);
1890 			if (ret == -1)
1891 				continue;
1892 			if (opt_num == 0 || opt_num == 1)
1893 				mv_cmd = opt_num;
1894 			else /* default (sort by name) */
1895 				mv_cmd = DEF_MV_CMD;
1896 		}
1897 
1898 		else if (!opener && *line == 'O' && strncmp(line, "Opener=", 7) == 0) {
1899 			char *tmp = get_line_value(line);
1900 			if (!tmp)
1901 				continue;
1902 			opener = savestring(tmp, strlen(tmp));
1903 		}
1904 
1905 		else if (xargs.pager == UNSET && *line == 'P'
1906 		&& strncmp(line, "Pager=", 6) == 0) {
1907 			char opt_str[MAX_BOOL] = "";
1908 			ret = sscanf(line, "Pager=%5s\n", opt_str);
1909 			if (ret == -1)
1910 				continue;
1911 			if (strncmp(opt_str, "true", 4) == 0)
1912 				pager = 1;
1913 			else if (strncmp(opt_str, "false", 5) == 0)
1914 				pager = 0;
1915 		}
1916 
1917 		else if (xargs.printsel == UNSET && *line == 'P'
1918 		&& strncmp(line, "PrintSelfiles=", 14) == 0) {
1919 			char opt_str[MAX_BOOL] = "";
1920 			ret = sscanf(line, "PrintSelfiles=%5s\n", opt_str);
1921 			if (ret == -1)
1922 				continue;
1923 			if (strncmp(opt_str, "true", 4) == 0)
1924 				print_selfiles = 1;
1925 			else if (strncmp(opt_str, "false", 5) == 0)
1926 				print_selfiles = 0;
1927 		}
1928 
1929 		else if (*line == 'P' && strncmp(line, "Prompt=", 7) == 0) {
1930 			if (encoded_prompt)
1931 				free(encoded_prompt);
1932 			char *p = strchr(line, '=');
1933 			if (p && *(++p))
1934 				encoded_prompt = savestring(p, strlen(p));
1935 		}
1936 
1937 		else if (*line == 'P' && strncmp(line, "PromptStyle=", 12) == 0) {
1938 			char opt_str[8] = "";
1939 			ret = sscanf(line, "PromptStyle=%7s\n", opt_str);
1940 			if (ret == -1)
1941 				continue;
1942 			if (strncmp(opt_str, "default", 7) == 0)
1943 				prompt_style = DEF_PROMPT_STYLE;
1944 			else if (strncmp(opt_str, "custom", 6) == 0)
1945 				prompt_style = CUSTOM_PROMPT_STYLE;
1946 			else
1947 				prompt_style = DEF_PROMPT_STYLE;
1948 		}
1949 
1950 		else if (xargs.restore_last_path == UNSET && *line == 'R'
1951 		&& strncmp(line, "RestoreLastPath=", 16) == 0) {
1952 			char opt_str[MAX_BOOL] = "";
1953 			ret = sscanf(line, "RestoreLastPath=%5s\n", opt_str);
1954 			if (ret == -1)
1955 				continue;
1956 			if (strncmp(opt_str, "true", 4) == 0)
1957 				restore_last_path = 1;
1958 			else if (strncmp(opt_str, "false", 5) == 0)
1959 				restore_last_path = 0;
1960 		}
1961 
1962 		else if (*line == 'R' && strncmp(line, "RlEditMode=0", 12) == 0) {
1963 			rl_vi_editing_mode(1, 0);
1964 			/* By default, readline uses emacs editing mode */
1965 		}
1966 
1967 		else if (xargs.share_selbox == UNSET && *line == 'S'
1968 		&& strncmp(line, "ShareSelbox=", 12) == 0) {
1969 			char opt_str[MAX_BOOL] = "";
1970 			ret = sscanf(line, "ShareSelbox=%5s\n", opt_str);
1971 			if (ret == -1)
1972 				continue;
1973 			if (strncmp(opt_str, "true", 4) == 0)
1974 				share_selbox = 1;
1975 			else if (strncmp(opt_str, "false", 5) == 0)
1976 				share_selbox = 0;
1977 		}
1978 
1979 		else if (xargs.hidden == UNSET && *line == 'S'
1980 		&& strncmp(line, "ShowHiddenFiles=", 16) == 0) {
1981 			char opt_str[MAX_BOOL] = "";
1982 			ret = sscanf(line, "ShowHiddenFiles=%5s\n",
1983 			    opt_str);
1984 			if (ret == -1)
1985 				continue;
1986 			if (strncmp(opt_str, "true", 4) == 0)
1987 				show_hidden = 1;
1988 			else if (strncmp(opt_str, "false", 5) == 0)
1989 				show_hidden = 0;
1990 		}
1991 
1992 		else if (xargs.sort == UNSET && *line == 'S' && strncmp(line, "Sort=", 5) == 0) {
1993 			int opt_num = 0;
1994 			ret = sscanf(line, "Sort=%d\n", &opt_num);
1995 			if (ret == -1)
1996 				continue;
1997 			if (opt_num >= 0 && opt_num <= SORT_TYPES)
1998 				sort = opt_num;
1999 			else /* default (sort by name) */
2000 				sort = DEF_SORT;
2001 		}
2002 
2003 		else if (xargs.sort_reverse == UNSET && *line == 'S'
2004 		&& strncmp(line, "SortReverse=", 12) == 0) {
2005 			char opt_str[MAX_BOOL] = "";
2006 			ret = sscanf(line, "SortReverse=%5s\n", opt_str);
2007 			if (ret == -1)
2008 				continue;
2009 			if (strncmp(opt_str, "true", 4) == 0)
2010 				sort_reverse = 1;
2011 			else if (strncmp(opt_str, "false", 5) == 0)
2012 				sort_reverse = 0;
2013 		}
2014 
2015 		/* Check for the xargs.splash flag. If -1, it was
2016 		 * not set via command line, so that it must be
2017 		 * set here */
2018 		else if (xargs.splash == UNSET && *line == 'S'
2019 		&& strncmp(line, "SplashScreen=", 13) == 0) {
2020 			char opt_str[MAX_BOOL] = "";
2021 			ret = sscanf(line, "SplashScreen=%5s\n", opt_str);
2022 			/* According to cppcheck: "sscanf() without field
2023 			 * width limits can crash with huge input data".
2024 			 * Field width limits = %5s */
2025 			if (ret == -1)
2026 				continue;
2027 
2028 			if (strncmp(opt_str, "true", 4) == 0)
2029 				splash_screen = 1;
2030 			else if (strncmp(opt_str, "false", 5) == 0)
2031 				splash_screen = 0;
2032 		}
2033 
2034 		else if (xargs.path == UNSET && cur_ws == UNSET && *line == 'S'
2035 		&& strncmp(line, "StartingPath=", 13) == 0) {
2036 			char *tmp = get_line_value(line);
2037 			if (!tmp)
2038 				continue;
2039 
2040 			/* If starting path is not NULL, and exists, and is a
2041 			 * directory, and the user has appropriate permissions,
2042 			 * set path to starting path. If any of these conditions
2043 			 * is false, path will be set to default, that is, CWD */
2044 			if (xchdir(tmp, SET_TITLE) == 0) {
2045 				if (cur_ws < 0)
2046 					cur_ws = 0;
2047 				free(ws[cur_ws].path);
2048 				ws[cur_ws].path = savestring(tmp, strlen(tmp));
2049 			} else {
2050 				_err('w', PRINT_PROMPT, _("%s: '%s': %s. Using the "
2051 					"current working directory as starting path\n"),
2052 					PROGRAM_NAME, tmp, strerror(errno));
2053 			}
2054 		}
2055 
2056 #ifndef _NO_SUGGESTIONS
2057 		else if (*line == 'S' && strncmp(line, "SuggestFiletypeColor=", 21) == 0) {
2058 			char opt_str[MAX_BOOL] = "";
2059 			ret = sscanf(line, "SuggestFiletypeColor=%5s\n", opt_str);
2060 			if (ret == -1)
2061 				continue;
2062 			if (strncmp(opt_str, "true", 4) == 0)
2063 				suggest_filetype_color = 1;
2064 			else if (strncmp(opt_str, "false", 5) == 0)
2065 				suggest_filetype_color = 0;
2066 		}
2067 
2068 		else if (*line == 'S'
2069 		&& strncmp(line, "SuggestionStrategy=", 19) == 0) {
2070 			char opt_str[SUG_STRATS + 1] = "";
2071 			ret = sscanf(line, "SuggestionStrategy=%7s\n", opt_str);
2072 			if (ret == -1)
2073 				continue;
2074 			int fail = 0;
2075 			size_t s = 0;
2076 			for (; opt_str[s]; s++) {
2077 				if (opt_str[s] != 'a' && opt_str[s] != 'b'
2078 				&& opt_str[s] != 'c' && opt_str[s] != 'e'
2079 				&& opt_str[s] != 'f' && opt_str[s] != 'h'
2080 				&& opt_str[s] != 'j' && opt_str[s] != '-') {
2081 					fail = 1;
2082 					break;
2083 				}
2084 			}
2085 			if (fail || s != SUG_STRATS)
2086 				continue;
2087 			suggestion_strategy = savestring(opt_str, strlen(opt_str));
2088 		}
2089 #endif /* !_NO_SUGGESTIONS */
2090 
2091 		else if (xargs.fzftab == UNSET && *line == 'T'
2092 		&& strncmp(line, "TabCompletionMode=", 18) == 0) {
2093 			char opt_str[9] = "";
2094 			ret = sscanf(line, "TabCompletionMode=%8s\n", opt_str);
2095 			if (ret == -1)
2096 				continue;
2097 			if (strncmp(opt_str, "standard", 8) == 0)
2098 				fzftab = 0;
2099 			else if (strncmp(opt_str, "fzf", 3) == 0)
2100 				fzftab = 1;
2101 		}
2102 
2103 		else if (*line == 'F' && strncmp(line, "FzfTabOptions=", 14) == 0) {
2104 			char *tmp = get_line_value(line);
2105 			if (!tmp)
2106 				continue;
2107 			fzftab_options = savestring(tmp, strlen(tmp));
2108 		}
2109 
2110 		else if (*line == 'T' && strncmp(line, "TerminalCmd=", 12) == 0) {
2111 			if (term) {
2112 				free(term);
2113 				term = (char *)NULL;
2114 			}
2115 
2116 			char *opt = strchr(line, '=');
2117 			if (!opt || !*opt || !*(++opt))
2118 				continue;
2119 
2120 			char *tmp = remove_quotes(opt);
2121 			if (!tmp)
2122 				continue;
2123 
2124 			term = savestring(tmp, strlen(tmp));
2125 		}
2126 
2127 		else if (xargs.tips == UNSET && *line == 'T' && strncmp(line, "Tips=", 5) == 0) {
2128 			char opt_str[MAX_BOOL] = "";
2129 			ret = sscanf(line, "Tips=%5s\n", opt_str);
2130 			if (ret == -1)
2131 				continue;
2132 			if (strncmp(opt_str, "false", 5) == 0)
2133 				tips = 0;
2134 			else if (strncmp(opt_str, "true", 4) == 0)
2135 				tips = 1;
2136 		}
2137 
2138 #ifndef _NO_TRASH
2139 		else if (xargs.trasrm == UNSET && *line == 'T'
2140 		&& strncmp(line, "TrashAsRm=", 10) == 0) {
2141 			char opt_str[MAX_BOOL] = "";
2142 			ret = sscanf(line, "TrashAsRm=%5s\n", opt_str);
2143 			if (ret == -1)
2144 				continue;
2145 			if (strncmp(opt_str, "true", 4) == 0)
2146 				tr_as_rm = 1;
2147 			else if (strncmp(opt_str, "false", 5) == 0)
2148 				tr_as_rm = 0;
2149 		}
2150 #endif
2151 
2152 		else if (xargs.unicode == UNSET && *line == 'U'
2153 		&& strncmp(line, "Unicode=", 8) == 0) {
2154 			char opt_str[MAX_BOOL] = "";
2155 			ret = sscanf(line, "Unicode=%5s\n", opt_str);
2156 			if (ret == -1)
2157 				continue;
2158 			if (strncmp(opt_str, "true", 4) == 0)
2159 				unicode = 1;
2160 			else if (strncmp(opt_str, "false", 5) == 0)
2161 				unicode = 0;
2162 		}
2163 
2164 		else if (xargs.warning_prompt == UNSET && *line == 'W'
2165 		&& strncmp(line, "WarningPrompt=", 14) == 0) {
2166 			char opt_str[MAX_BOOL] = "";
2167 			ret = sscanf(line, "WarningPrompt=%5s\n", opt_str);
2168 			if (ret == -1)
2169 				continue;
2170 			if (strncmp(opt_str, "true", 4) == 0)
2171 				warning_prompt = 1;
2172 			else if (strncmp(opt_str, "false", 5) == 0)
2173 				warning_prompt = 0;
2174 		}
2175 
2176 		else if (*line == 'W' && strncmp(line, "WarningPromptStr=", 17) == 0) {
2177 			char *tmp = get_line_value(line);
2178 			if (!tmp)
2179 				continue;
2180 			wprompt_str = savestring(tmp, strlen(tmp));
2181 		}
2182 
2183 		else if (xargs.welcome_message == UNSET && *line == 'W'
2184 		&& strncmp(line, "WelcomeMessage=", 15) == 0) {
2185 			char opt_str[MAX_BOOL] = "";
2186 			ret = sscanf(line, "WelcomeMessage=%5s\n",
2187 			    opt_str);
2188 			if (ret == -1)
2189 				continue;
2190 			if (strncmp(opt_str, "true", 4) == 0)
2191 				welcome_message = 1;
2192 			else if (strncmp(opt_str, "false", 5) == 0)
2193 				welcome_message = 0;
2194 		}
2195 	}
2196 
2197 	close_fstream(config_fp, fd);
2198 
2199 	if (_filter) {
2200 		ret = regcomp(&regex_exp, _filter, REG_NOSUB | REG_EXTENDED);
2201 		if (ret != EXIT_SUCCESS) {
2202 			_err('w', PRINT_PROMPT, _("%s: '%s': Invalid regular "
2203 				  "expression\n"), PROGRAM_NAME, _filter);
2204 			free(_filter);
2205 			_filter = (char *)NULL;
2206 			regfree(&regex_exp);
2207 		}
2208 	}
2209 
2210 	return;
2211 }
2212 
2213 /* Set up CliFM directories and config files. Load the user's
2214  * configuration from clifmrc */
2215 void
init_config(void)2216 init_config(void)
2217 {
2218 	if (xargs.stealth_mode == 1) {
2219 		_err(0, PRINT_PROMPT, _("%s: Running in stealth mode: trash, "
2220 			"persistent selection and directory history, just as bookmarks, "
2221 			"logs and configuration files, are disabled.\n"),
2222 		    PROGRAM_NAME);
2223 		config_ok = 0;
2224 		return;
2225 	}
2226 
2227 	/* Store a pointer to the current LS_COLORS value to be used by
2228 	 * external commands */
2229 	ls_colors_bk = getenv("LS_COLORS");
2230 
2231 	if (!home_ok)
2232 		return;
2233 
2234 	define_config_file_names();
2235 	create_config_files();
2236 
2237 	if (config_ok)
2238 		read_config();
2239 
2240 	cschemes_n = get_colorschemes();
2241 	set_colors(usr_cscheme ? usr_cscheme : "default", 1);
2242 
2243 	if ((flags & GUI) && getenv("XTERM_VERSION")) {
2244 		/* If running Xterm, instruct it to send an escape code (27)
2245 		 * for Meta (Alt) key sequences. Otherwise, Alt keybindings won't
2246 		 * work */
2247 		printf("\x1b[?1036h"); /* metaSendsEscape = true */
2248 /*		printf("\x1b[?1034l"); // eightBitInput = false
2249 		printf("\x1b[>1;1m"); // modifyCursorKeys = 1
2250 		printf("\x1b[>2;1m"); // modifyFunctionKeys = 1
2251 		("\x1b[>1m" and "\x1b[>2m", reset to initial value) */
2252 	}
2253 }
2254 
2255 static void
reset_variables(void)2256 reset_variables(void)
2257 {
2258 	/* Free everything */
2259 	free(config_dir_gral);
2260 	free(config_dir);
2261 	config_dir = config_dir_gral = (char *)NULL;
2262 
2263 #ifndef _NO_TRASH
2264 	free(trash_dir);
2265 	free(trash_files_dir);
2266 	free(trash_info_dir);
2267 	trash_dir = trash_files_dir = trash_info_dir = (char *)NULL;
2268 #endif
2269 
2270 	free(bm_file);
2271 	free(log_file);
2272 	free(hist_file);
2273 	free(dirhist_file);
2274 	bm_file = log_file = hist_file = dirhist_file = (char *)NULL;
2275 
2276 	free(config_file);
2277 	free(profile_file);
2278 	free(msg_log_file);
2279 	config_file = profile_file = msg_log_file = (char *)NULL;
2280 
2281 	free(mime_file);
2282 	free(plugins_dir);
2283 	free(actions_file);
2284 	free(kbinds_file);
2285 	mime_file = plugins_dir = actions_file = kbinds_file = (char *)NULL;
2286 
2287 	free(colors_dir);
2288 	free(tmp_dir);
2289 	free(sel_file);
2290 	free(remotes_file);
2291 	tmp_dir = colors_dir = sel_file = remotes_file = (char *)NULL;
2292 
2293 #ifndef _NO_SUGGESTIONS
2294 	free(suggestion_buf);
2295 	suggestion_buf = (char *)NULL;
2296 
2297 	free(suggestion_strategy);
2298 	suggestion_strategy = (char *)NULL;
2299 #endif
2300 
2301 	free(fzftab_options);
2302 	fzftab_options = (char *)NULL;
2303 
2304 	free(wprompt_str);
2305 	wprompt_str = (char *)NULL;
2306 
2307 #ifdef AUTOCMDS_TEST
2308 	free_autocmds();
2309 #endif
2310 
2311 	free_remotes(0);
2312 
2313 	if (_filter) {
2314 		regfree(&regex_exp);
2315 		free(_filter);
2316 		_filter = (char *)NULL;
2317 	}
2318 
2319 	free(opener);
2320 	opener = (char *)NULL;
2321 
2322 	free(encoded_prompt);
2323 	encoded_prompt = (char *)NULL;
2324 
2325 	free(term);
2326 	term = (char *)NULL;
2327 
2328 	int i = (int)cschemes_n;
2329 	while (--i >= 0)
2330 		free(color_schemes[i]);
2331 	free(color_schemes);
2332 	color_schemes = (char **)NULL;
2333 	cschemes_n = 0;
2334 	free(usr_cscheme);
2335 	usr_cscheme = (char *)NULL;
2336 
2337 	free(user.shell);
2338 	user.shell = (char *)NULL;
2339 
2340 	/* Reset all variables */
2341 	auto_open = UNSET;
2342 	autocd = UNSET;
2343 	autojump = UNSET;
2344 	autols = UNSET;
2345 	case_sens_dirjump = UNSET;
2346 	case_sens_path_comp = UNSET;
2347 	case_sensitive = UNSET;
2348 	case_sens_search = UNSET;
2349 	cd_on_quit = UNSET;
2350 	check_cap = UNSET;
2351 	check_ext = UNSET;
2352 	classify = UNSET;
2353 	clear_screen = UNSET;
2354 	colorize = UNSET;
2355 	columned = UNSET;
2356 	dirhist_map = UNSET;
2357 	disk_usage = UNSET;
2358 	elnpad = UNSET;
2359 	ext_cmd_ok = UNSET;
2360 	files_counter = UNSET;
2361 	follow_symlinks = UNSET;
2362 #ifndef _NO_FZF
2363 	fzftab = UNSET;
2364 #endif
2365 #ifndef _NO_HIGHLIGHT
2366 	highlight = UNSET;
2367 #endif
2368 #ifndef _NO_ICONS
2369 	icons = UNSET;
2370 #endif
2371 	int_vars = UNSET;
2372 	light_mode = UNSET;
2373 	list_folders_first = UNSET;
2374 	listing_mode = UNSET;
2375 	logs_enabled = UNSET;
2376 	long_view = UNSET;
2377 	max_jump_total_rank = UNSET;
2378 	max_printselfiles = UNSET;
2379 	min_name_trim = UNSET;
2380 	min_jump_rank = UNSET;
2381 	no_eln = UNSET;
2382 	pager = UNSET;
2383 	print_selfiles = UNSET;
2384 	prompt_offset = UNSET;
2385 	prompt_style = UNSET;
2386 	restore_last_path = UNSET;
2387 	share_selbox = UNSET;
2388 	show_hidden = UNSET;
2389 	sort = UNSET;
2390 	splash_screen = UNSET;
2391 	tips = UNSET;
2392 	unicode = UNSET;
2393 	warning_prompt = UNSET;
2394 	welcome_message = UNSET;
2395 
2396 #ifndef _NO_SUGGESTIONS
2397 	suggestions = suggest_filetype_color = UNSET;
2398 #endif
2399 
2400 #ifndef _NO_TRASH
2401 	tr_as_rm = UNSET;
2402 	trash_ok = 1;
2403 #endif
2404 
2405 	dir_changed = 0;
2406 	dequoted = 0;
2407 	internal_cmd = 0;
2408 	is_sel = 0;
2409 	kbind_busy = 0;
2410 	mime_match = 0;
2411 	no_log = 0;
2412 	print_msg = 0;
2413 	recur_perm_error_flag = 0;
2414 	sel_is_last = 0;
2415 	shell_is_interactive = 0;
2416 	shell_terminal = 0;
2417 	sort_reverse = 0;
2418 	sort_switch = 0;
2419 
2420 	config_ok = 1;
2421 	home_ok = 1;
2422 	selfile_ok = 1;
2423 
2424 	pmsg = NOMSG;
2425 
2426 	return;
2427 }
2428 
2429 static void
check_cmd_line_options(void)2430 check_cmd_line_options(void)
2431 {
2432 #ifndef _NO_SUGGESTIONS
2433 	if (xargs.suggestions != UNSET)
2434 		suggestions = xargs.suggestions;
2435 #endif
2436 
2437 #ifndef _NO_TRASH
2438 	if (xargs.trasrm != UNSET)
2439 		tr_as_rm = xargs.trasrm;
2440 #endif
2441 
2442 #ifndef _NO_ICONS
2443 	if (xargs.icons != UNSET)
2444 		icons = xargs.icons;
2445 #endif
2446 
2447 	if (xargs.auto_open != UNSET)
2448 		auto_open = xargs.auto_open;
2449 
2450 	if (xargs.autocd != UNSET)
2451 		autocd = xargs.autocd;
2452 
2453 	if (xargs.autojump != UNSET)
2454 		autojump = xargs.autojump;
2455 	if (autojump)
2456 		autocd = 1;
2457 
2458 	if (xargs.case_sens_dirjump != UNSET)
2459 		case_sens_dirjump = xargs.case_sens_dirjump;
2460 
2461 	if (xargs.case_sens_path_comp != UNSET)
2462 		case_sens_path_comp = xargs.case_sens_path_comp;
2463 
2464 	if (xargs.autols != UNSET)
2465 		autols = xargs.autols;
2466 
2467 	if (xargs.cd_on_quit != UNSET)
2468 		cd_on_quit = xargs.cd_on_quit;
2469 
2470 	if (xargs.classify != UNSET)
2471 		classify = xargs.classify;
2472 
2473 	if (xargs.clear_screen != UNSET)
2474 		clear_screen = xargs.clear_screen;
2475 
2476 	if (xargs.dirmap != UNSET)
2477 		dirhist_map = xargs.dirmap;
2478 
2479 	if (xargs.disk_usage != UNSET)
2480 		disk_usage = xargs.disk_usage;
2481 
2482 	if (xargs.expand_bookmarks != UNSET)
2483 		expand_bookmarks = xargs.expand_bookmarks;
2484 
2485 	if (xargs.ext != UNSET)
2486 		ext_cmd_ok = xargs.ext;
2487 
2488 	if (xargs.ffirst != UNSET)
2489 		list_folders_first = xargs.ffirst;
2490 
2491 	if (xargs.files_counter != UNSET)
2492 		files_counter = xargs.files_counter;
2493 
2494 	if (xargs.hidden != UNSET)
2495 		show_hidden = xargs.hidden;
2496 
2497 	if (xargs.light != UNSET)
2498 		light_mode = xargs.light;
2499 
2500 	if (xargs.logs != UNSET)
2501 		logs_enabled = xargs.logs;
2502 
2503 	if (xargs.longview != UNSET)
2504 		long_view = xargs.longview;
2505 
2506 	if (xargs.max_dirhist != UNSET)
2507 		max_dirhist = xargs.max_dirhist;
2508 
2509 	if (xargs.max_path != UNSET)
2510 		max_path = xargs.max_path;
2511 
2512 	if (xargs.colorize != UNSET)
2513 		colorize = xargs.colorize;
2514 
2515 	if (xargs.columns != UNSET)
2516 		columned = xargs.columns;
2517 
2518 	if (xargs.noeln != UNSET)
2519 		no_eln = xargs.noeln;
2520 
2521 	if (xargs.only_dirs != UNSET)
2522 		only_dirs = xargs.only_dirs;
2523 
2524 	if (xargs.pager != UNSET)
2525 		pager = xargs.pager;
2526 
2527 	if (xargs.printsel != UNSET)
2528 		print_selfiles = xargs.printsel;
2529 
2530 	if (xargs.restore_last_path != UNSET)
2531 		restore_last_path = xargs.restore_last_path;
2532 
2533 	if (xargs.sensitive != UNSET)
2534 		case_sensitive = xargs.sensitive;
2535 
2536 	if (xargs.share_selbox != UNSET)
2537 		share_selbox = xargs.share_selbox;
2538 
2539 	if (xargs.sort != UNSET)
2540 		sort = xargs.sort;
2541 
2542 	if (xargs.sort_reverse != UNSET)
2543 		sort_reverse = xargs.sort_reverse;
2544 
2545 	if (xargs.splash != UNSET)
2546 		splash_screen = xargs.splash;
2547 
2548 	if (xargs.tips != UNSET)
2549 		tips = xargs.tips;
2550 
2551 	if (xargs.unicode != UNSET)
2552 		unicode = xargs.unicode;
2553 
2554 	if (xargs.welcome_message != UNSET)
2555 		welcome_message = xargs.welcome_message;
2556 
2557 	return;
2558 }
2559 
2560 int
reload_config(void)2561 reload_config(void)
2562 {
2563 	reset_variables();
2564 
2565 	/* Set up config files and options */
2566 	init_config();
2567 
2568 	/* If some option was not set, set it to the default value*/
2569 	check_options();
2570 	set_sel_file();
2571 	create_tmp_files();
2572 
2573 	/* If some option was set via command line, keep that value
2574 	 * for any profile */
2575 	check_cmd_line_options();
2576 
2577 	/* Free the aliases and prompt_cmds arrays to be allocated again */
2578 	int i = dirhist_total_index;
2579 	while (--i >= 0)
2580 		free(old_pwd[i]);
2581 	free(old_pwd);
2582 	old_pwd = (char **)NULL;
2583 
2584 	if (jump_db) {
2585 		for (i = 0; jump_db[i].path; i++)
2586 			free(jump_db[i].path);
2587 
2588 		free(jump_db);
2589 		jump_db = (struct jump_t *)NULL;
2590 	}
2591 	jump_n = 0;
2592 
2593 	i = (int)aliases_n;
2594 	while (--i >= 0) {
2595 		free(aliases[i].name);
2596 		free(aliases[i].cmd);
2597 	}
2598 	free(aliases);
2599 	aliases = (struct alias_t *)NULL;
2600 	aliases_n = 0;
2601 
2602 	i = (int)prompt_cmds_n;
2603 	while (--i >= 0)
2604 		free(prompt_cmds[i]);
2605 
2606 	dirhist_total_index = 0;
2607 	prompt_cmds_n = 0;
2608 
2609 	get_aliases();
2610 	get_prompt_cmds();
2611 	load_dirhist();
2612 	load_jumpdb();
2613 	load_remotes();
2614 
2615 	/* Set the current poistion of the dirhist index to the last
2616 	 * entry */
2617 	dirhist_cur_index = dirhist_total_index - 1;
2618 
2619 	dir_changed = 1;
2620 	set_env();
2621 	return EXIT_SUCCESS;
2622 }
2623