diff --git a/src/main.c b/src/main.c index 31d5fec..873f33f 100644 --- a/src/main.c +++ b/src/main.c @@ -444,7 +444,7 @@ next_arg: error(!doesEditorExist(editorToOpen, shouldDebug), "user", "%s is either not in your path or not installed.", editorToOpen); debug("Finished parsing the attribute flags"); - if (doesBackup) { // (TODO LATER) when implementing multiple directories for vault we should verifiy this works. + if (doesBackup) { handleBackups(notesDirectoryString, pathToBackup, homedir, interval, (const char**)rsyncArgs, rsyncArgsNumber, shouldDebug); } @@ -568,11 +568,18 @@ open_note: int regexReturn = regcomp(®ex, journalRegex, 0); error(regexReturn, "program", "Regex compilation failed."); regexReturn = regexec(®ex, noteSelected, 0, NULL, 0); + + + int *journalWasUpdated = malloc(sizeof(int)); + *journalWasUpdated = 0; if (!regexReturn) { // if the regex matches -> it's a journal debug("%s is a journal. Updating it...", noteSelected); - fullPath = updateJournal(fullPath, noteSelected, timeFormat, shouldDebug); // we return the path. As if it is a divided journal we must point to the correct entry + fullPath = updateJournal(fullPath, noteSelected, timeFormat, journalWasUpdated, shouldDebug); // we return the path. As if it is a divided journal we must point to the correct entry } - if (newLineOnOpening) {//(TODO LATER) For some reason this does not applies to journals? --- it does but only if we don't create a new file/entry + if (newLineOnOpening) { + if (*journalWasUpdated) { + appendToFile(fullPath, " \n", shouldDebug); // when updating the journal it adds a \n char at the end. So appendToFile(\n) does not work. We append a (special and rare) whitespace character + \n to bypass this issue. + } appendToFile(fullPath, "\n", shouldDebug); } openEditor(fullPath, editorToOpen, shouldRender, shouldJumpToEnd, shouldDebug); @@ -586,8 +593,7 @@ note_creation: shouldChangeVault = 1; } else if (strcmp(noteSelected, "Delete vault") == 0) { const char *yesNo[] = {"No, go back to note selection.", "Yes."}; - char *answer = ncursesSelect((char **)yesNo, "Are you sure you want to delete the entire vault? This can not be undone (Use arrows or WASD, Enter to select):", 1, 1, " ", "", "", shouldDebug); // (TODO LATER) This is ugly with Select Are you sure[...] - debug("You answered: %s for deleting the vault %s", answer, vaultSelected); + char *answer = ncursesSelect((char **)yesNo, "Are you sure you want to delete the entire vault? This can not be undone (Use arrows or WASD, Enter to select):", 1, 1, " ", "", "", shouldDebug); debug("You answered: %s for deleting the vault %s", answer, vaultSelected); if (strcmp(answer, "Yes.") == 0) { // delete the vault after confirmation by the user char pathToRMRF[PATH_MAX]; diff --git a/src/notes.c b/src/notes.c index 8bd1b75..44a53fe 100644 --- a/src/notes.c +++ b/src/notes.c @@ -1,6 +1,5 @@ #include "notes.h" #include "ui.h" -#include char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, int *count, int shouldDebug) { debug("Searching %s for journals", vault); @@ -25,7 +24,6 @@ char **getJournalsFromVault(char *pathToVault, char *vault, char *journalRegex, debug("┌------------------------------------------\nDetected files and dirs from the vault"); while ((vaultEntry = readdir(vaultDirectory)) != NULL) { // we iterate over every entry from the dir. So files and dirs (. and .. included) altDebug("%s ", vaultEntry->d_name); - // (TODO LATER) check if it is a file or a dir if (vaultEntry->d_name[0] != '.') { // if the entry don't start with a dot (so hidden dirs and hidden files) regexReturn = regexec(®ex, vaultEntry->d_name, 0, NULL, 0); if (!regexReturn) { // if the regex matches @@ -51,7 +49,7 @@ char** getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int // this function is inputed a path to a vault (which was selected before) and outpus all the suitable notes (so not the hidden ones) // originally from https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/ debug("Searching %s for notes", vault); - struct dirent *vaultEntry; // (TODO LATER) change name of these variables. notesDirectory is dumb as it is the directory of vaults + struct dirent *vaultEntry; char tempPath[PATH_MAX]; snprintf(tempPath, sizeof(tempPath), "%s/%s", pathToVault, vault); // sets the full absolute path to fullPathEntry DIR *vaultDirectory = opendir(tempPath); @@ -93,8 +91,6 @@ char** getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int } char **getVaultsFromDirectory(char *dirString, int *count, int shouldDebug) { - // (TODO LATER) it might be a good idea to check if these directories exist - // (TODO LATER) expand ~ as it does not work with opendir() // this function is inputed a path to a directory (which comes usually from the config file) and outpus all the suitable directories (so not the hidden ones) which will serve as separate vaults for notes debug("Opening %s ", dirString); // originally from https://www.geeksforgeeks.org/c/c-program-list-files-sub-directories-directory/ @@ -128,7 +124,7 @@ char **getVaultsFromDirectory(char *dirString, int *count, int shouldDebug) { return dirsArray; } -char *updateJournal(char *path, char *journal, char *timeFormat, int shouldDebug) { +char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWasUpdated, int shouldDebug) { path[PATH_MAX] = '\0'; // it assures it is a string (Most cases this does nothing). But rewriting at least one bytes make the compile happy. He doesn't want to return an unchanged input. debug("Handling the journal %s", path); @@ -144,6 +140,7 @@ char *updateJournal(char *path, char *journal, char *timeFormat, int shouldDebug debug("%s is a unified journal.", path); if (!isStringInFile(path, date, shouldDebug)) { // if there is no entry for current date appendToFile(path, date, shouldDebug); + *journalWasUpdated = 1; } // if there is an entry do nothing } else if (S_ISDIR(metadata.st_mode)) { debug("%s is a divided journal.", path); @@ -207,6 +204,7 @@ char *updateJournal(char *path, char *journal, char *timeFormat, int shouldDebug fprintf(file, "%s\n", date); fclose(file); free(createEntryMessage); + *journalWasUpdated = 1; } else { debug("Today's entry (%s) already exist. We won't create a new one.", dateWithExtension); } diff --git a/src/notes.h b/src/notes.h index 9bd6b57..6502ce7 100644 --- a/src/notes.h +++ b/src/notes.h @@ -13,9 +13,10 @@ char **getNotesFromVault(char *pathToVault, char *vault, char *journalRegex, int char **getVaultsFromDirectory(char *dirString, int *count, int shouldDebug); // path is the path to the file. // journal is the name of the file. +// journalWasUpdated will be set to 1 if a new entry was created // handles both type of journal (divided and unified). // creates new entry with date. // for divided select if we want to acces to a new entry or a old one. // returns the path to the file that needs to be opened. -char *updateJournal(char *path, char *journal, char *timeFormat, int shouldDebug); +char *updateJournal(char *path, char *journal, char *timeFormat, int *journalWasUpdated, int shouldDebug); #endif diff --git a/src/ui.c b/src/ui.c index 60b482c..50b9bd6 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1,5 +1,4 @@ #include "ui.h" -#include void createNewVault(char *dirToVault, int bypass, char *bypassvalue, int shouldDebug) { int duplicateWarning = 0; // set to 1 later if the vault you tried to create already existed diff --git a/src/utils.c b/src/utils.c index 3fd1db3..73449ae 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,4 +1,5 @@ #include "utils.h" +#include const char *supportedEditor[] = {"neovim", "vim", "nano"}; const int numEditors = 3; @@ -292,27 +293,36 @@ void appendToFile(const char *path, const char *string, const int shouldDebug) { } void sanitize(char *string) { - for (size_t i = 0; i < strlen(string); i++) { - if ((!isalnum((unsigned char)string[i]) && strchr("/\\:*?\"\'<>\n\r\t", string[i])) || ((i == 0 || i == 1) && string[i] == '.')) { // replace unwanted chars by '_'. '.' is replaced if it is only the first two chars - // (TODO LATER fixe case where it "*.*", "..." and so on + size_t stringLenght = strlen(string); + for (size_t i = 0; i < stringLenght; i++) { + if ((!isalnum((unsigned char)string[i]) && strchr("~/\\:*?\"\'|!$[]{}<>\n\r\t", string[i]))) { // replace unwanted chars by '_' string[i] = '_'; } } + // removes any leading '. + size_t i = 0; + while (i < stringLenght && string[i] == '.') { + string[i++] = '_'; + } } // both functions are from https://stackoverflow.com/a/5467788 // from what i understood: // remove() can't delete directories with files // so it walks the file tree and deletes it's content before removing the directory -// (TODO LATER) this seems safe, but it's maybe a good idea to add some checks to not remove something it should not remove -int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { +int unlink_cb(const char *filePath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { (void)sb; (void)typeflag; (void)ftwbuf; int shouldDebug = 1; //normally shouldDebug should be passed to the function. However, it's to difficult here and the best it to set it to 1. - int rv = remove(fpath); - error(rv, "program", "remove() failed to delete %s", fpath); + + // some sanity checks to be sure that we don't delete something we shouldn't + error(strcmp(filePath, "") == 0, "program", "filePath is empty. Refusing to delete directory"); + error(filePath[0] == '.', "program", "%s starts with \".\". For security reasons, use absolute path and not relative path.", filePath); + + int rv = remove(filePath); + error(rv, "program", "remove() failed to delete %s", filePath); return rv; }