diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4588fda..79da8ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,8 +3,8 @@ project(File_Sorter_Core C)
set(CMAKE_C_STANDARD 17)
-set(SOURCE_FILES main.c ./src/config.c ./src/sorter.c ./src/logger.c)
-set(HEADER_FILES ./include/config.h ./include/sorter.h ./include/logger.h)
+set(SOURCE_FILES main.c ./src/config.c ./src/sorter.c ./src/logger.c ./src/tool/actions.c)
+set(HEADER_FILES ./include/config.h ./include/sorter.h ./include/logger.h ./include/tool/actions.h)
set(TO_INCLUDE ./include/)
add_executable(file-sorter ${SOURCE_FILES} ${HEADER_FILES})
@@ -41,7 +41,6 @@ endif ()
file(WRITE config/config.conf
[basic_config]\n
check_interval\ 3000\n
- parse_interval\ 5000\n
debug_log\ 0\n
default_dir_path\ /home/$ENV{USER}/default_sorter_path/\n
enable_default_path\ 1\n
@@ -63,7 +62,7 @@ file(WRITE service/file-sorter.service
\n
[Service]\n
Type=simple\n
- ExecStart=/bin/bash\ -c\ /usr/bin/file-sorter\n
+ ExecStart=/bin/bash\ -c\ "/home/$ENV{USER}/.local/bin/file-sorter\ --start-sorter"\n
Restart=on-failure\n
Group=$ENV{USER}\n
\n
@@ -82,4 +81,4 @@ file(WRITE autostart/file-sorter.desktop
install(FILES config/config.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_WRITE GROUP_READ WORLD_WRITE WORLD_READ DESTINATION /home/$ENV{USER}/.local/share/file_sorter/config/)
install(FILES service/file-sorter.service PERMISSIONS OWNER_EXECUTE OWNER_READ WORLD_EXECUTE WORLD_READ DESTINATION /home/$ENV{USER}/.config/systemd/user/)
install(FILES autostart/file-sorter.desktop PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE GROUP_EXECUTE GROUP_READ GROUP_WRITE WORLD_EXECUTE WORLD_READ WORLD_WRITE DESTINATION /home/$ENV{USER}/.config/autostart/)
-install(FILES build/file-sorter PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE DESTINATION /usr/bin/)
+install(FILES build/file-sorter PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE DESTINATION ~/.local/bin/)
diff --git a/README.md b/README.md
index 5ee7252..e3851f7 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,6 @@ The information is as follows.
Field | Description
--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
`check_interval` | The time ( seconds ) between checks (for new files etc).
- `parse_interval` | The time ( seconds ) to read the config file again for any changes.
`debug_log` | For debugging. To enter debug mode, the value of the debugLog field must be changed to 1.
`default_dir_path` | If a file is found outside of a folder and no specific location has been specified to which it should be moved, then it will go to default_dir_path.
`enable_default_path` | If this option is enabled, then any file that do not have a specific location to which they should be sent will be sent to the default.
@@ -118,18 +117,24 @@ locations `/home/username/ Documents/py/` and `/home/username/Documents/cpp/`.
In the example above the first part consists of the extensions `.py` and `.c` and the second part of the
locations `/home/username/Documents/py/` and `*`.
-# Tool
+# Commands
+
+Command | Description
+---------|--------------
+`file-sorter --start-sorter` | Start the sorter service
+`file-sorter --help` | Displays all available commands.
+`file-sorter --set-check-interval [value]` | Changes the value of the check interval field to the value `[value]`.
+`file-sorter --set-default-dir-path [path]` | Changes the default location to `[path]`.
+`file-sorter --set-enable-default-dir [value]` | 0:1 Enable the to transfer files in default dir.
+`file-sorter --set-debug-log [value]` | Changes the logs status based on the value `[value]`. It can get the values `1` `(debug mode)` and `0` `(normal mode)`.
+`file-sorter --set-mv-without-ext [value]` | 0:1 Enable the program to move files without extention.
+`file-sorter --add-check [path]` | Adds `[path]` to the list of locations that the program looks at.
+`file-sorter --add-target [ext] [path]` | Adds to the list the information that the program must send the file with extension `[ext]` to the location `[path]` if such a file is found.
+`file-sorter --remove-check [row number]` | Deletes the item in the line `[row_number]`, the line number appears with the command `--list-checks` or `--list-targets`.
+`file-sorter --list-checks` | Displays all locations that the program looks at.
+`file-sorter --list-targets` | Displays all the elements that describe what the program does for a file.
+`file-sorter --list-options` | Displays the program options.
-Due to the nature of this program and this config i made a tool that helps the user to do the following:
-
-- Add locations to the config check field.
-- Be able to add targets.
-- To be able to delete check and targets.
-- To be able to see the check and targets.
-- To be able to change the program settings.
-
-The tool described above can be found here:
-https://github.com/EmbeddedCat/file-sorter-terminal-tool
# Service
diff --git a/config/config.conf b/config/config.conf
index 628dba9..7ae8ee1 100644
--- a/config/config.conf
+++ b/config/config.conf
@@ -1,6 +1,5 @@
[basic_config]
check_interval 3000
-parse_interval 5000
debug_log 0
default_dir_path /home/embeddedcat/default_sorter_path/
enable_default_path 1
diff --git a/include/config.h b/include/config.h
index b2fca9b..babd39c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -6,12 +6,32 @@
#define FAILED_TO_PARSE -0x1
+/**
+ * *******************
+ * OPTIONS
+ * *******************
+ */
+#define CHECK_INT "check_interval"
+#define PARSE_INT "parse_interval"
+#define DEBUG_LOG "debug_log"
+#define DEFAULT_DIR "default_dir_path"
+#define EN_DEFAULT "enable_default_path"
+#define WITHOUT_EXT "move_files_without_ext"
+
+/**
+ * ******************
+ * LISTS
+ * ******************
+ */
+#define CHECK_LISTID "[check]"
+#define TARGET_LISTID "[targets]"
+#define EXCLUDE_LISTID "[exclude]"
+
// config options.
struct options
{
unsigned int o_check_interval; // check interval option.
- unsigned int o_parse_interval; // parse interval option.
unsigned int o_debug_log: 1; // debug log option.
char *o_default_path; // default path option.
unsigned int o_enable_default: 1; // enable default path option.
@@ -54,4 +74,6 @@ extern void reparse_config(struct config *dst);
extern void destroy_config(struct config *src);
+extern int update_config(const struct config *src);
+
#endif
diff --git a/include/tool/actions.h b/include/tool/actions.h
new file mode 100644
index 0000000..43fc5db
--- /dev/null
+++ b/include/tool/actions.h
@@ -0,0 +1,101 @@
+#ifndef ACTIONS_H
+#define ACTIONS_H
+
+// option manipulation commands.
+/**
+ * Change the value of the check interval option
+ * in config file.
+ */
+extern int set_check_interval(const char *n_value);
+
+/**
+ * Enable or disable the debug log
+ * feature. This works by changing
+ * the value of the corresponded value
+ * in config file.
+ */
+extern int set_debug_log(const char *n_state);
+
+/**
+ * Change the default dir path, where the
+ * files sent when no rule has been set.
+ */
+extern int set_default_dir_path(const char *n_path);
+
+/**
+ * Enable or disable the default dir
+ * feature. This works by changing
+ * the value of the corresponded value
+ * in config file.
+ */
+extern int set_enable_default_dir(const char *n_state);
+
+/**
+ * Enable or disable the feature to
+ * move the file without extention.
+ * @param n_state The new state 0 or 1.
+ */
+extern int set_mv_without_ext(const char *n_state);
+
+
+ // list manipulation commands.
+/**
+ * Add a new path on the check list that the core
+ * will scan for files.
+ */
+extern int add_check(const char *path);
+
+/**
+ * Add a new rule on the target list that the core
+ * checks in order to organize the files.
+ * @param args The information that the builder pass to the callback.
+ */
+extern int add_target(const char *ext, const char *path);
+
+/**
+ * Add a new rule on the exlude list that the core
+ * checks in order to exclude files.
+ */
+extern int add_exclude(const char *ext, const char *path);
+
+/**
+ * Remove a path from the check list that the core
+ * will scan for files.
+ */
+extern int remove_check(const char *row);
+
+/**
+ * Remove a rule from the target list that the core
+ * checks in order to organize the files.
+ */
+extern int remove_target(const char *row);
+
+/**
+ * Remove a rule from the exlude list that the core
+ * checks in order to exclude files.
+ */
+extern int remove_exclude(const char *row);
+
+// Show commands.
+/**
+ * Show the available options.
+ */
+extern int list_options();
+
+/**
+ * Show the list of path's in check list.
+ * @param args The information that the builder pass to the callback.
+ */
+extern int list_checks();
+
+/**
+ * Show the list of rules in target list.
+ */
+extern int list_targets();
+
+/**
+ * Show the list of rules in exclude list.
+ */
+extern int list_excludes();
+
+#endif
diff --git a/main.c b/main.c
index f4ab075..d4b649c 100644
--- a/main.c
+++ b/main.c
@@ -2,29 +2,140 @@
#include
-#include
-#include
+#include "config.h"
+#include "sorter.h"
+#include "tool/actions.h"
#else
-// TODO - include logger.
+#include
#endif
+const char usage[] = "Usage:\n \tfile-sorter [OPTION] ...\n\n"
+ "\t--start-sorter. Start the sorter service\n"
+ "\t--set-check-interval [value] Change the value of check interval.\n"
+ "\t--set-default-dir-path [path] Change the default directory path.\n"
+ "\t--set-enable-default-dir [value] 0:1 Enable the to transfer files in default dir.\n"
+ "\t--set-debug-log [value] 0:1 Change the log to debug mode (1).\n"
+ "\t--set-mv-without-ext [value] 0:1 Enable the program to move files without extention.\n"
+ "\t--add-check [path] Add new check.\n"
+ "\t--add-target [ext] [path] Add new target.\n"
+ "\t--remove-check [row number] remove check.\n"
+ "\t--remove-target [row number] remove target.\n"
+ "\t--list-checks list checks.\n"
+ "\t--list-targets list targets.\n"
+ "\t--list-options list options.\n\n\n"
+ "Each of the above commands will print an OK message on success.\n"
+ "Check https://github.com/EmbeddedCat/file-sorter-core for more information's about the project!.\n";
+
+static inline int help()
+{
+ return printf("%s\n", usage);
+}
+
int main(int argc, char *argv[])
{
#ifdef __unix__
- struct config config_p;
- // initialzize the config.
- init_config(&config_p);
-
- // parse config.
- parse_config(&config_p);
- // start procces
- start_sorter(&config_p);
+ if (argv[1] == NULL) {
+ return help();
+ } else if (!strcmp(argv[1], "--start-sorter")) {
+ struct config config_p;
+ // initialzize the config.
+ init_config(&config_p);
+ // parse config.
+ parse_config(&config_p);
+ // start procces
+ start_sorter(&config_p);
+ destroy_config(&config_p);
+ } else if (!strcmp(argv[1], "--set-check-interval")) {
+ if (argv[2] == NULL) return help();
+ if (set_check_interval(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--set-default-dir-path")) {
+ if (argv[2] == NULL) return help();
+ set_default_dir_path(argv[2]);
+ } else if (!strcmp(argv[1], "--set-enable-default-dir")) {
+ if (argv[2] == NULL) return help();
+ if (set_enable_default_dir(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--set-debug-log")) {
+ if (argv[2] == NULL) return help();
+ if (set_debug_log(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--set-mv-without-ext")) {
+ if (argv[2] == NULL) return help();
+ if (set_mv_without_ext(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--add-check")) {
+ if (argv[2] == NULL) return help();
+ if (add_check(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--add-target")) {
+ if (argv[2] == NULL) return help();
+ if (argv[3] == NULL) return help();
+ if (add_target(argv[2], argv[3]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--add-exclude")) {
+ if (argv[2] == NULL) return help();
+ if (argv[3] == NULL) return help();
+ if (add_exclude(argv[2], argv[3]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--remove-check")) {
+ if (argv[2] == NULL) return help();
+ if (remove_check(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--remove-target")) {
+ if (argv[2] == NULL) return help();
+ if (remove_target(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--remove-exclude")) {
+ if (argv[2] == NULL) return help();
+ if (remove_exclude(argv[2]) == -1) {
+ printf("Error\n");
+ } else {
+ printf("OK\n");
+ }
+ } else if (!strcmp(argv[1], "--list-options")) {
+ list_options();
+ } else if (!strcmp(argv[1], "--list-checks")) {
+ list_checks();
+ } else if (!strcmp(argv[1], "--list-targets")) {
+ list_targets();
+ } else if (!strcmp(argv[1], "--list-excludes")) {
+ list_excludes();
+ } else {
+ return help();
+ }
- destroy_config(&config_p);
#else
- // TODO - call logger and write that the oparating system is not compatiple.
+ printf("The oparation system does not support this binary.\n");
#endif
}
diff --git a/src/config.c b/src/config.c
index 6f77734..50299c0 100644
--- a/src/config.c
+++ b/src/config.c
@@ -6,8 +6,8 @@
#include
#include
-#include
-#include
+#include "config.h"
+#include "logger.h"
#define CONF_PATH "/.local/share/file_sorter/config/config.conf"
@@ -65,9 +65,7 @@ static inline unsigned int parse_int_opt(const char *conf_buff, const char *opt)
{
char *opt_a = isolate_opt(conf_buff, opt);
unsigned int opt_r = (opt_a == NULL) ? 0 : atoi(opt_a);
- if (opt_r == 0) {
- logger("An option has value of zero.", WAR);
- }
+
free(opt_a);
return opt_r; // get the int value.
}
@@ -126,6 +124,20 @@ static char **parse_list(const char *conf_buff, const char *list)
return (char **) realloc(list_r, (real_l + 1) * sizeof(char *)); // adjust the size of the list.
}
+static void update_list(const char *(*list),
+ const char *list_id,
+ FILE *conf)
+{
+ fprintf(conf, "%s\n", list_id);
+ if (list == NULL) goto empt;
+
+ for (int i = 0; list[i]; i++) {
+ if (list[i] == NULL) continue; // the case where it is NULL is when we remove an element.
+ fprintf(conf, "%s\n", list[i]);
+ }
+empt:fprintf(conf, "[done]\n\n");
+}
+
static inline void free_list(char *(**list))
{
if ((*list) == NULL) return;
@@ -145,11 +157,10 @@ void parse_config(struct config *dst)
}
dst->c_options.o_check_interval = parse_int_opt(conf_buff, "check_interval");
- dst->c_options.o_parse_interval = parse_int_opt(conf_buff, "parse_interval");
dst->c_options.o_debug_log = parse_int_opt(conf_buff, "debug_log") & 0x1;
dst->c_options.o_default_path = parse_str_opt(conf_buff, "default_dir_path");
dst->c_options.o_enable_default = parse_int_opt(conf_buff, "enable_default_path") & 0x1;
- dst->c_options.o_move_no_ext = parse_int_opt(conf_buff, "move_files_without_extention") & 0x1;
+ dst->c_options.o_move_no_ext = parse_int_opt(conf_buff, "move_files_without_ext") & 0x1;
dst->c_lists.l_check_list = parse_list(conf_buff, "[check]");
dst->c_lists.l_target_list = parse_list(conf_buff, "[targets]");
dst->c_lists.l_exclude_list = parse_list(conf_buff, "[exclude]");
@@ -159,6 +170,7 @@ void parse_config(struct config *dst)
void destroy_config(struct config *src)
{
// free the allocated space where it should.
+ // free options.
free(src->c_options.o_default_path);
src->c_options.o_default_path = NULL;
free_list(&src->c_lists.l_check_list);
@@ -172,3 +184,46 @@ void reparse_config(struct config *dst)
// reparse.
parse_config(dst);
}
+
+int update_config(const struct config *src)
+{
+ // determine the absolute path of the config.
+ char *username = getlogin();
+ char *absolute = (char *) malloc(sizeof(char) * (strlen(CONF_PATH) +
+ strlen(username) + 7));
+ if (absolute == NULL) return -1;
+
+ strcpy(absolute, "/home/");
+ strcat(absolute, username);
+ strcat(absolute, CONF_PATH);
+
+ // open the file.
+ FILE *conf = fopen(absolute, "w");
+ if (conf == NULL) return -1;
+
+ // write updated options.
+ fprintf(conf, "%s\n", "[basic_config]");
+ fprintf(conf, "%s %d\n", CHECK_INT, src->c_options.o_check_interval);
+ fprintf(conf, "%s %d\n", DEBUG_LOG, src->c_options.o_debug_log);
+ fprintf(conf, "%s %s\n", DEFAULT_DIR, src->c_options.o_default_path);
+ fprintf(conf, "%s %d\n", EN_DEFAULT, src->c_options.o_enable_default);
+ fprintf(conf, "%s %d\n\n", WITHOUT_EXT, src->c_options.o_move_no_ext);
+
+ // write updated check list.
+ update_list((const char **) src->c_lists.l_check_list,
+ CHECK_LISTID,
+ conf);
+
+ update_list((const char **) src->c_lists.l_target_list,
+ TARGET_LISTID,
+ conf);
+
+ update_list((const char **) src->c_lists.l_exclude_list,
+ EXCLUDE_LISTID,
+ conf);
+
+ free(absolute);
+ fclose(conf);
+
+ return 0;
+}
diff --git a/src/sorter.c b/src/sorter.c
index fc23a40..2bbcafe 100644
--- a/src/sorter.c
+++ b/src/sorter.c
@@ -5,26 +5,13 @@
#include
#include
-#include
-#include
+#include "sorter.h"
+#include "logger.h"
static struct config *config_file;
-static pthread_mutex_t config_lock;
#define NO_EXTENTION "noext"
-// the thread that will reparse the config file.
-static void *refresh_config(void *arg)
-{
- while (1) {
- // sleep for the configured time.
- sleep(config_file->c_options.o_parse_interval);
- pthread_mutex_lock(&config_lock);
- // reparse the config. Thread safe.
- reparse_config(config_file);
- pthread_mutex_unlock(&config_lock);
- }
-}
// get the last dot. That represents the extension of the file.
static inline char *extract_ext(const char *file_path)
@@ -167,45 +154,19 @@ static void search_files(const char *path)
closedir(dir);
}
-// the thread that will organize the files.
-static void *organize_files(void *arg)
+
+void start_sorter(struct config *src)
{
+ config_file = src;
while (1) {
// sleep for the configured time.
sleep(config_file->c_options.o_check_interval);
- pthread_mutex_lock(&config_lock);
// read check list.
+ reparse_config(src);
+
if (config_file->c_lists.l_check_list == NULL) continue;
for (int i = 0; config_file->c_lists.l_check_list[i]; i++) {
search_files(config_file->c_lists.l_check_list[i]);
}
- pthread_mutex_unlock(&config_lock);
}
}
-
-
-void start_sorter(struct config *src)
-{
- config_file = src;
- // initalize the mutex.
- pthread_mutex_init(&config_lock, NULL);
-
- pthread_t refresh_t;
- pthread_t organize_t;
- // check if the threads has been created.
- if (
- pthread_create(&refresh_t, NULL, &refresh_config, NULL) != 0
- ||
- pthread_create(&organize_t, NULL, &organize_files, NULL) != 0
- ) {
- logger("Can't create threads, shuting down..", ERROR);
- pthread_mutex_destroy(&config_lock);
- return;
- }
-
- pthread_join(refresh_t, NULL);
- pthread_join(organize_t, NULL);
-
- // destroy the mutex.
- pthread_mutex_destroy(&config_lock);
-}
diff --git a/src/tool/actions.c b/src/tool/actions.c
new file mode 100644
index 0000000..61a2ecc
--- /dev/null
+++ b/src/tool/actions.c
@@ -0,0 +1,248 @@
+#include
+#include
+#include
+
+#include "tool/actions.h"
+#include "config.h"
+
+/**
+ * This functions chagnes a value of one of
+ * the options in the config file.
+ * @param n_value The new value to write.
+ * @param wtchange The option to change.
+ */
+static int change_opt_value(const char *n_value,
+ const char *wtchange)
+{
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+ if (!strcmp(wtchange, CHECK_INT)) {
+ conf.c_options.o_check_interval = atoi(n_value);
+ if (conf.c_options.o_check_interval == 0) return -1;
+ } else if (!strcmp(wtchange, DEBUG_LOG)) {
+ conf.c_options.o_debug_log = atoi(n_value) & 0x1;
+ } else if (!strcmp(wtchange, DEFAULT_DIR)) {
+ free(conf.c_options.o_default_path);
+ conf.c_options.o_default_path = (char *) strdup(n_value);
+ // TODO - check if the path exist?
+ } else if (!strcmp(wtchange, EN_DEFAULT)){
+ conf.c_options.o_enable_default = atoi(n_value) & 0x1;
+ } else {
+ conf.c_options.o_move_no_ext = atoi(n_value) & 0x1;
+ }
+
+ if (update_config(&conf) == -1) return -1;
+ destroy_config(&conf);
+ return 0;
+}
+
+static inline size_t get_list_size(const char **list)
+{
+ if (list == NULL) return -1;
+
+ size_t size;
+ for (size = 0; list[size]; size++) {}
+
+ return size;
+}
+
+static int add_to_list(const char *element,
+ const char *list_id)
+{
+ char **tmp_list = NULL;
+ size_t list_size = 0;
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+
+ // decide what list to modify.
+ if (!strcmp(list_id, CHECK_LISTID)) {
+ tmp_list = conf.c_lists.l_check_list;
+ } else if (!strcmp(list_id, TARGET_LISTID)) {
+ tmp_list = conf.c_lists.l_target_list;
+ } else {
+ tmp_list = conf.c_lists.l_exclude_list;
+ }
+
+ // get the size of the list.
+ list_size = get_list_size((const char **) tmp_list);
+ if (list_size == -1) list_size = 1;
+
+ // add the new element.
+ tmp_list = (char **) realloc(tmp_list, sizeof(char *) * (list_size + 2));
+ tmp_list[list_size] = strdup(element);
+ tmp_list[list_size + 1] = NULL; // terminate the array with NULL.
+
+ conf.c_lists.l_check_list = tmp_list;
+
+ if (update_config(&conf) == -1) return -1;
+ destroy_config(&conf);
+ return 0;
+}
+
+static int remove_from_list(int row, const char *list_id)
+{
+ char **tmp_list = NULL;
+ size_t tmp_size = -1;
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+
+ // decide what list to modify.
+ if (!strcmp(list_id, CHECK_LISTID)) {
+ tmp_list = conf.c_lists.l_check_list;
+ } else if (!strcmp(list_id, TARGET_LISTID)) {
+ tmp_list = conf.c_lists.l_target_list;
+ } else {
+ tmp_list = conf.c_lists.l_exclude_list;
+ }
+
+ // Get the size of the list.
+ tmp_size = get_list_size((const char **) tmp_list);
+ if (tmp_size == -1 || row > tmp_size) return -1;
+
+ // O(1) oparation to remove the element.
+ free(tmp_list[row]);
+ tmp_list[row] = NULL; // Make it NULL, so the updater ignore it.
+
+ if (update_config(&conf) == -1) return -1;
+ destroy_config(&conf);
+ return 0;
+}
+
+int set_check_interval(const char *n_value)
+{
+ return change_opt_value(n_value, CHECK_INT);
+}
+
+int set_debug_log(const char *n_state)
+{
+ return change_opt_value(n_state, DEBUG_LOG);
+}
+
+int set_default_dir_path(const char *n_path)
+{
+ return change_opt_value(n_path, DEFAULT_DIR);
+}
+
+int set_enable_default_dir(const char *n_state)
+{
+ return change_opt_value(n_state, EN_DEFAULT);
+}
+
+int set_mv_without_ext(const char *n_state)
+{
+ return change_opt_value(n_state, WITHOUT_EXT);
+}
+
+int add_check(const char *path)
+{
+ return add_to_list(path, CHECK_LISTID);
+}
+
+int add_target(const char *ext, const char *path)
+{
+ int err_code = 0;
+ char *build_target = (char *) malloc(sizeof(char) *
+ (strlen(ext) +
+ strlen(path) + 2));
+ sprintf(build_target, "%s %s", ext, path);
+ err_code = add_to_list(build_target, TARGET_LISTID);
+ free(build_target);
+ return err_code;
+}
+
+int add_exclude(const char *ext, const char *path)
+{
+ int err_code = 0;
+ char *build_target = (char *) malloc(sizeof(char) *
+ (strlen(ext) +
+ strlen(path) + 2));
+ sprintf(build_target, "%s %s", ext, path);
+ err_code = add_to_list(build_target, TARGET_LISTID);
+ free(build_target);
+ return err_code;
+}
+
+int remove_check(const char *row)
+{
+ return remove_from_list(atoi(row), CHECK_LISTID);
+}
+
+int remove_target(const char *row)
+{
+ return remove_from_list(atoi(row), TARGET_LISTID);
+}
+
+int remove_exclude(const char *row)
+{
+ return remove_from_list(atoi(row), EXCLUDE_LISTID);
+}
+
+int list_options()
+{
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+ printf("%s %d\n", CHECK_INT, conf.c_options.o_check_interval);
+ printf("%s %d\n", DEBUG_LOG, conf.c_options.o_debug_log & 0x1);
+ printf("%s %s\n", DEFAULT_DIR, conf.c_options.o_default_path);
+ printf("%s %d\n", EN_DEFAULT, conf.c_options.o_enable_default);
+ printf("%s %d\n\n", WITHOUT_EXT, conf.c_options.o_move_no_ext);
+
+ destroy_config(&conf);
+ return 0;
+}
+
+int list_checks()
+{
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+ if (conf.c_lists.l_check_list == NULL) return -1;
+ for (int i = 0;
+ conf.c_lists.l_check_list[i]; i++) {
+ printf("[%d] %s\n", i, conf.c_lists.l_check_list[i]);
+ }
+
+ destroy_config(&conf);
+ return 0;
+}
+
+int list_targets()
+{
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+ if (conf.c_lists.l_target_list == NULL) return -1;
+ for (int i = 0;
+ conf.c_lists.l_target_list[i]; i++) {
+ printf("[%d] %s\n", i, conf.c_lists.l_target_list[i]);
+ }
+
+ destroy_config(&conf);
+ return 0;
+}
+
+int list_excludes()
+{
+ struct config conf;
+ init_config(&conf);
+ parse_config(&conf);
+
+ if (conf.c_lists.l_exclude_list == NULL) return -1;
+ for (int i = 0;
+ conf.c_lists.l_exclude_list[i]; i++) {
+ printf("[%d] %s\n", i, conf.c_lists.l_exclude_list[i]);
+ }
+
+ destroy_config(&conf);
+ return 0;
+}