From b9b143ddaff272fa207eef8d952f5800a10957f6 Mon Sep 17 00:00:00 2001 From: nots1dd Date: Thu, 29 Aug 2024 18:20:53 +0530 Subject: [PATCH] [REFACTOR] CHANGELOG v2.5 --- CHANGELOG/v2_5.md | 9 + CMakeLists.txt | 2 +- debug/CMakeLists.txt | 2 +- debug/meson.build | 3 +- include/cursesutils.h | 42 ++--- include/inodeinfo.h | 44 +++++ lfm.c | 349 +---------------------------------- meson.build | 3 +- src/cursesutils.c | 378 +++++++++++++++++++------------------- src/inodeinfo.c | 410 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 683 insertions(+), 559 deletions(-) create mode 100644 CHANGELOG/v2_5.md create mode 100644 include/inodeinfo.h create mode 100644 src/inodeinfo.c diff --git a/CHANGELOG/v2_5.md b/CHANGELOG/v2_5.md new file mode 100644 index 0000000..fd0971e --- /dev/null +++ b/CHANGELOG/v2_5.md @@ -0,0 +1,9 @@ +# CHANGE TYPE: MINOR + +## Summary of Changes + +-> Mostly refactor commits are ongoing + +-> Created a new header `inodeinfo.h` + +-> Respective debug and default CMakeLists.txt and meson.build files are updated accordingly diff --git a/CMakeLists.txt b/CMakeLists.txt index c134fa6..97fb232 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ include_directories(${SDL2_MIXER_INCLUDE_DIRS}) include_directories(${CMAKE_SOURCE_DIR}) # Add the executable -add_executable(litefm lfm.c src/cursesutils.c src/filepreview.c src/dircontrol.c src/archivecontrol.c src/clipboard.c src/logging.c src/signalhandling.c src/highlight.c src/hashtable.c src/arg_helpers.c src/musicpreview.c) +add_executable(litefm lfm.c src/cursesutils.c src/filepreview.c src/dircontrol.c src/archivecontrol.c src/clipboard.c src/logging.c src/signalhandling.c src/highlight.c src/hashtable.c src/arg_helpers.c src/musicpreview.c src/inodeinfo.c) # Link required libraries target_link_libraries(litefm ${CURSES_LIBRARIES} ${LIBARCHIVE_LIBRARIES} ${LIBYAML_LIBRARIES} ${SDL2_LIBRARIES} ${SDL2_MIXER_LIBRARIES}) diff --git a/debug/CMakeLists.txt b/debug/CMakeLists.txt index 4bac432..e5c5e91 100644 --- a/debug/CMakeLists.txt +++ b/debug/CMakeLists.txt @@ -62,7 +62,7 @@ include_directories(${SDL2_MIXER_INCLUDE_DIRS}) include_directories(${CMAKE_SOURCE_DIR}) # Add the executable -add_executable(litefm ../lfm.c ../src/cursesutils.c ../src/filepreview.c ../src/dircontrol.c ../src/archivecontrol.c ../src/clipboard.c ../src/logging.c ../src/signalhandling.c ../src/highlight.c ../src/hashtable.c ../src/arg_helpers.c ../src/musicpreview.c) +add_executable(litefm ../lfm.c ../src/cursesutils.c ../src/filepreview.c ../src/dircontrol.c ../src/archivecontrol.c ../src/clipboard.c ../src/logging.c ../src/signalhandling.c ../src/highlight.c ../src/hashtable.c ../src/arg_helpers.c ../src/musicpreview.c ../src/inodeinfo.c) # Link required libraries target_link_libraries(litefm ${CURSES_LIBRARIES} ${LIBARCHIVE_LIBRARIES} ${LIBYAML_LIBRARIES} ${SDL2_LIBRARIES} ${SDL2_MIXER_LIBRARIES}) diff --git a/debug/meson.build b/debug/meson.build index ea616c2..3e0a6c5 100644 --- a/debug/meson.build +++ b/debug/meson.build @@ -50,7 +50,8 @@ src_files = files( '../src/highlight.c', '../src/hashtable.c', '../src/arg_helpers.c', - '../src/musicpreview.c' + '../src/musicpreview.c', + '../src/inodeinfo.c' ) # UNCOMMENT LINES 59, 60, 68, 69 to ENABLE ASAN Memory leak VERBOSE output diff --git a/include/cursesutils.h b/include/cursesutils.h index 85d2ad7..052785c 100644 --- a/include/cursesutils.h +++ b/include/cursesutils.h @@ -48,20 +48,20 @@ /* COLOR PAIRS DEF */ -#define FILE_COLOR_PAIR 1 -#define DIR_COLOR_PAIR 2 -#define ARCHIVE_COLOR_PAIR 3 -#define AUDIO_COLOR_PAIR 4 -#define IMAGE_COLOR_PAIR 5 -#define SYMLINK_COLOR_PAIR 6 -#define AQUA_COLOR_PAIR 7 -#define VIOLET_COLOR_PAIR 8 -#define DARK_BG_COLOR_PAIR 9 -#define MAGENTA_COLOR_PAIR 10 -#define SPECIAL_COLOR_PAIR 11 -#define ERROR_COLOR_PAIR 12 -#define CUSTOM_COLOR_PAIR 13 -#define TITLE_COLOR_PAIR 14 +#define FILE_COLOR_PAIR 1 +#define DIR_COLOR_PAIR 2 +#define ARCHIVE_COLOR_PAIR 3 +#define AUDIO_COLOR_PAIR 4 +#define IMAGE_COLOR_PAIR 5 +#define SYMLINK_COLOR_PAIR 6 +#define AQUA_COLOR_PAIR 7 +#define VIOLET_COLOR_PAIR 8 +#define DARK_BG_COLOR_PAIR 9 +#define MAGENTA_COLOR_PAIR 10 +#define SPECIAL_COLOR_PAIR 11 +#define ERROR_COLOR_PAIR 12 +#define CUSTOM_COLOR_PAIR 13 +#define TITLE_COLOR_PAIR 14 #define HIGHLIGHT_COLOR_PAIR 15 /* COMPRESSION OPTIONS COLOR PAIR + MISC DEF */ @@ -69,14 +69,14 @@ #define STEP_SELECT_FORMAT 0 #define STEP_SELECT_ACTION 1 -#define COMP_COLOR_TITLE 31 -#define COMP_COLOR_HIGHLIGHT 32 -#define COMP_COLOR_NORMAL 33 -#define COMP_COLOR_FOOTER 34 +#define COMP_COLOR_TITLE 31 +#define COMP_COLOR_HIGHLIGHT 32 +#define COMP_COLOR_NORMAL 33 +#define COMP_COLOR_FOOTER 34 -#define OPTION_TAR 1 -#define OPTION_ZIP 2 -#define OPTION_EXIT 0 +#define OPTION_TAR 1 +#define OPTION_ZIP 2 +#define OPTION_EXIT 0 // Function Prototypes void show_message(WINDOW* win, const char* message); diff --git a/include/inodeinfo.h b/include/inodeinfo.h new file mode 100644 index 0000000..48f41b6 --- /dev/null +++ b/include/inodeinfo.h @@ -0,0 +1,44 @@ +// // // // // // +// // +// LITE FM // +// // +// // // // // // + +/* + * --------------------------------------------------------------------------- + * File: inodeinfo.h + * Description: Displaying of each inode's info onto the info_win, + * all its functions, both popup and main window logic + * + * Author: Siddharth Karanam + * Created: <29/08/24> + * + * Copyright: 2024 nots1dd. All rights reserved. + * + * License: + * + * Notes: inodeinfo also has the function `truncate_symlink_name`. + * It made sense as the function is only required in two areas; + * in string search, and for proper file info retreival + * + * Revision History: + * <29/08/24> - Initial creation and function declarations added. + * + * --------------------------------------------------------------------------- + */ + +#ifndef INODE_INFO_H +#define INODE_INFO_H + +#include +#include +#include +#include + +#define MAX_ITEM_NAME_LENGTH 80 + +void get_file_info_popup(WINDOW* main_win, const char* path, const char* filename); +void get_file_info(WINDOW* info_win, const char* path, const char* filename); +void truncate_symlink_name(char* name); + +#endif diff --git a/lfm.c b/lfm.c index fc705f8..fc2b9a8 100644 --- a/lfm.c +++ b/lfm.c @@ -26,13 +26,13 @@ * * Revision History: * <31/07/24> - Initial creation and function declarations added. + * <29/08/24> - Refactoring * * --------------------------------------------------------------------------- */ #include #include -#include /* LITEFM DEDICATED HEADERS */ @@ -48,6 +48,7 @@ #include "include/hashtable.h" #include "include/arg_helpers.h" #include "include/musicpreview.h" +#include "include/inodeinfo.h" #define MAX_ITEMS 1024 #define MAX_HISTORY 256 @@ -75,17 +76,6 @@ const char * err_message[] = { " " }; -const char *denied_message[] = { -" .__ __. ______ _______. __ __ ", -" | \\ | | / __ \\ / || | | | ", -" | \\| | | | | | | (----`| | | | ", -" | . ` | | | | | \\ \\ | | | | ", -" | |\\ | | `--' | .----) | | `--' | __ ", -" |__| \\__| \\______/ |_______/ \\______/ (__)", -" " -}; - - typedef struct { char name[NAME_MAX]; int is_dir; @@ -98,8 +88,6 @@ typedef struct { } DirHistory; -void truncate_symlink_name(char *name); - void list_dir(WINDOW *win, const char *path, FileItem items[], int *count, int show_hidden) { DIR *dir; struct dirent *entry; @@ -315,22 +303,6 @@ void print_items(WINDOW *win, FileItem items[], int count, int highlight, } } -/* - * TRUNCATING A SYMLINK NAME IS NECESSARY AS THE ITEM NAME MIGHT HAVE - * THE STRING QUERY WE ARE LOOKING FOR, - * - * EXAMPLE: LIB64 ->LIB - * IF I WANT TO SEARCH FOR LIB, I SHOULD GO TO THE ITEM THAT ACTUALLY - * HAS THE STRING `LIB`, AND NOT A SYMLINK OF IT. - * -*/ -void truncate_symlink_name(char *name) { - char *arrow = strstr(name, " ->"); - if (arrow) { - *arrow = '\0'; // Truncate the name at the " -> " point - } -} - int find_item(const char *query, FileItem items[], int item_count, int *start_index, int direction) { char lower_query[NAME_MAX]; for (int i = 0; query[i] && i < NAME_MAX; i++) { @@ -409,323 +381,6 @@ int find_item(const char *query, FileItem items[], int item_count, int *start_in return -1; // Not found } -void get_file_info_popup(WINDOW * main_win, - const char * path, - const char * filename) { - struct stat file_stat; - char full_path[PATH_MAX]; - snprintf(full_path, PATH_MAX, "%s/%s", path, filename); - - // Get file information - if (stat(full_path, & file_stat) == -1) { - log_message(LOG_LEVEL_ERROR, "Error retrieving file information for `%s`", full_path); - show_message(main_win, "Error retrieving file information."); - return; - } - - // Create a new window for displaying file information - int info_win_height = 13; - int info_win_width = (COLS / 3) + 4; - int info_win_y = (LINES - info_win_height) / 2; - int info_win_x = (COLS - info_win_width) / 2; - - WINDOW * info_win = newwin(info_win_height, info_win_width, info_win_y, info_win_x); - draw_3d_info_win(info_win, info_win_y, info_win_x, info_win_height, info_win_width, 1, 2); - box(info_win, 0, 0); - - // Display file information with colors - colorLine(info_win, "File Information: ", 1, 1, 2); /* colorLine params: win, string, color_pair, x, y */ - colorLine(info_win, "Name: ", 3, 3, 2); - - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%s", filename); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - colorLine(info_win, "Size: ", 3, 4, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%s", format_file_size(file_stat.st_size)); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - const char * file_ext = strrchr(filename, '.'); - colorLine(info_win, "File Type: ", 3, 5, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - if (file_ext != NULL) { - wprintw(info_win, "%s", determine_file_type(full_path)); - } else { - wprintw(info_win, "none"); - } - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - colorLine(info_win, "Last Modified: ", 3, 6, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - char mod_time[20]; - strftime(mod_time, sizeof(mod_time), "%Y-%m-%d %H:%M:%S", localtime( & file_stat.st_mtime)); - wprintw(info_win, "%s", mod_time); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - colorLine(info_win, "Permissions: ", 3, 7, 2); - print_permissions(info_win, &file_stat); - - colorLine(info_win, "Inode: ", 3, 8, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%lu", file_stat.st_ino); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - // Additional file attributes can be displayed here - struct passwd * pwd = getpwuid(file_stat.st_uid); - wattron(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); - mvwprintw(info_win, 9, 2, "Owner: "); - wattroff(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%s (%d)", pwd -> pw_name, file_stat.st_uid); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - colorLine(info_win, "Press any key to close this window.", 2, info_win_height - 2, 2); - wrefresh(info_win); - - wgetch(info_win); // Wait for user input - wclear(info_win); // Clear info window before deleting - delwin(info_win); // Delete info window - - // Refresh the main window to ensure no artifacts remain - wrefresh(main_win); -} - -void get_file_info(WINDOW *info_win, const char *path, const char *filename) { - werase(info_win); - struct stat file_stat; - char full_path[PATH_MAX]; - char truncated_file_name[MAX_ITEM_NAME_LENGTH + 4]; // +4 for ellipsis and space - char symlink_target[PATH_MAX]; - ssize_t len; - - snprintf(full_path, PATH_MAX, "%s/%s", path, filename); - truncate_symlink_name(full_path); - - // Get file information using lstat to handle symlinks - if (lstat(full_path, &file_stat) == -1) { - log_message(LOG_LEVEL_ERROR, "Error retrieving file information for %s", full_path); - show_message(info_win, "Error retrieving file/dir info."); - box(info_win, 0, 0); - wrefresh(info_win); - return; - } - - if (access(full_path, R_OK) != 0) { - log_message(LOG_LEVEL_ERROR, "Access denied for %s", full_path); - int denied_message_size = sizeof(denied_message) / sizeof(denied_message[0]); - for (int j = 0; j < denied_message_size; j++) { - mvwprintw(info_win, j + 3, 2, "%s", denied_message[j]); - } - show_message(info_win, "Access denied for you!"); - box(info_win, 0, 0); - wrefresh(info_win); - return; - } - - // Truncate the filename if necessary - if (strlen(filename) > MAX_ITEM_NAME_LENGTH) { - snprintf(truncated_file_name, sizeof(truncated_file_name), "%.80s...", filename); - } else { - snprintf(truncated_file_name, sizeof(truncated_file_name), "%s", filename); - } - - // Display file information - wattron(info_win, A_BOLD); - mvwprintw(info_win, 1, 2, "File/Dir Information:"); - wattroff(info_win, A_BOLD); - - clearLine(info_win, 3, 2); - colorLine(info_win, "Name: ", 3, 3, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%s", truncated_file_name); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - clearLine(info_win, 4, 2); - colorLine(info_win, "Size: ", 3, 4, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%s", format_file_size(file_stat.st_size)); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - const char *file_ext = strrchr(filename, '.'); - clearLine(info_win, 5, 2); - colorLine(info_win, "Inode Type: ", 3, 5, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - if (!S_ISDIR(file_stat.st_mode)) { - wprintw(info_win, "%s", determine_file_type(full_path)); - } else { - wprintw(info_win, "Directory"); - } - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - char mod_time[20]; - strftime(mod_time, sizeof(mod_time), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); - clearLine(info_win, 6, 2); - colorLine(info_win, "Last Modified: ", 3, 6, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%s", mod_time); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - colorLine(info_win, "Inode: ", 3, 7, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, "%lu", file_stat.st_ino); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - clearLine(info_win, 8, 2); - colorLine(info_win, "Group: ", 3, 8, 2); - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - struct group *grp = getgrgid(file_stat.st_gid); - if (grp != NULL) { - wprintw(info_win, "%s", grp->gr_name); - } else { - wprintw(info_win, "Unknown"); - } - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - - clearLine(info_win, 9, 2); - colorLine(info_win, "Type: ", 3, 9, 2); - wattron(info_win, COLOR_PAIR(IMAGE_COLOR_PAIR)); - if (S_ISREG(file_stat.st_mode)) { - wprintw(info_win, "Regular File"); - - // Check if the file is an archive - if (file_ext != NULL && (strcmp(file_ext, ".zip") == 0 || strcmp(file_ext, ".7z") == 0 || strcmp(file_ext, ".tar") == 0 || strcmp(file_ext, ".gz") == 0)) { - // Display archive contents - display_archive_contents(info_win, full_path, file_ext); - } - } else if (S_ISDIR(file_stat.st_mode)) { - wattron(info_win, COLOR_PAIR(SPECIAL_COLOR_PAIR)); - wprintw(info_win, "Directory"); - wattroff(info_win, COLOR_PAIR(SPECIAL_COLOR_PAIR)); - - // Horizontal Layout for Parent Directories and Subdirectories - wattron(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); - mvwprintw(info_win, 12, 2, " Parent Directories: "); - mvwprintw(info_win, 12, getmaxx(info_win) / 2, " Children: "); - wattroff(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); - - char parent_dir[PATH_MAX]; - char current_path[PATH_MAX]; - strncpy(current_path, path, sizeof(current_path)); - current_path[sizeof(current_path) - 1] = '\0'; // Ensure null termination - char *parent_dir_ptr = dirname(current_path); - - // Make a copy of the parent directory path to avoid modifying the original path - strncpy(parent_dir, parent_dir_ptr, sizeof(parent_dir)); - parent_dir[sizeof(parent_dir) - 1] = '\0'; // Ensure null termination - int line = 13; - int sub_dir_line = 13; - int max_y, max_x; - getmaxyx(info_win, max_y, max_x); - - // Print parent directories on the left - DIR *dir = opendir(parent_dir); - struct dirent *entry; - if (dir != NULL) { - wattron(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); - mvwprintw(info_win, 10, 2, " Parent Directories: "); - wattroff(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); - - int col = 2; // Starting column - wattron(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); - while ((entry = readdir(dir)) != NULL) { - if (entry->d_type == DT_DIR) { - // Exclude the current directory and the special entries "." and ".." - if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && entry->d_name[0] != '.') { - // Truncate directory name if necessary - char truncated_dir_name[MAX_ITEM_NAME_LENGTH + 4]; // +4 for ellipsis and space - if (strlen(entry->d_name) > MAX_ITEM_NAME_LENGTH) { - snprintf(truncated_dir_name, sizeof(truncated_dir_name), "%.40s...", entry->d_name); - } else { - snprintf(truncated_dir_name, sizeof(truncated_dir_name), "%s", entry->d_name); - } - // Print the directory name - mvwprintw(info_win, line++, 2, "%s", truncated_dir_name); - } - } - } - closedir(dir); - wattroff(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); - } else { - show_message(info_win, "Error opening parent directory."); - } - - // Print subdirectories and files on the right - dir = opendir(full_path); - if (dir != NULL) { - while ((entry = readdir(dir)) != NULL && sub_dir_line < max_y - 1) { - if (entry->d_type == DT_DIR) { - if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // Truncate directory name if necessary - char truncated_sub_dir_name[MAX_ITEM_NAME_LENGTH + 4]; - if (strlen(entry->d_name) > MAX_ITEM_NAME_LENGTH) { - snprintf(truncated_sub_dir_name, sizeof(truncated_sub_dir_name), "%.40s...", entry->d_name); - } else { - snprintf(truncated_sub_dir_name, sizeof(truncated_sub_dir_name), "%s", entry->d_name); - } - wattron(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); - mvwprintw(info_win, sub_dir_line++, max_x / 2, " %s", truncated_sub_dir_name); - wattroff(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); - } - } - } - rewinddir(dir); - while ((entry = readdir(dir)) != NULL && sub_dir_line < max_y - 1) { - if (entry->d_type != DT_DIR) { - // Truncate file name if necessary - char truncated_file_name[MAX_ITEM_NAME_LENGTH + 4]; - if (strlen(entry->d_name) + sub_dir_line > MAX_ITEM_NAME_LENGTH) { - snprintf(truncated_file_name, sizeof(truncated_file_name), "%.40s...", entry->d_name); - } else { - snprintf(truncated_file_name, sizeof(truncated_file_name), "%s", entry->d_name); - } - wattron(info_win, A_BOLD | COLOR_PAIR(FILE_COLOR_PAIR)); - mvwprintw(info_win, sub_dir_line++, max_x / 2, " %s", truncated_file_name); - wattroff(info_win, A_BOLD | COLOR_PAIR(FILE_COLOR_PAIR)); - } - } - closedir(dir); - } else { - show_message(info_win, "Error opening directory."); - } - } else if (S_ISLNK(file_stat.st_mode)) { - wattron(info_win, COLOR_PAIR(SYMLINK_COLOR_PAIR)); - wprintw(info_win, "Symbolic Link"); - - // Read the symlink target - len = readlink(full_path, symlink_target, sizeof(symlink_target) - 1); - if (len != -1) { - symlink_target[len] = '\0'; // Null-terminate the string - wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - wprintw(info_win, " to %s", symlink_target); - wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); - } else { - show_message(info_win, "Error reading symlink target."); - } - wattroff(info_win, COLOR_PAIR(SYMLINK_COLOR_PAIR)); - } else if (S_ISFIFO(file_stat.st_mode)) { - wprintw(info_win, "FIFO"); - } else if (S_ISCHR(file_stat.st_mode)) { - wprintw(info_win, "Character Device"); - } else if (S_ISBLK(file_stat.st_mode)) { - wprintw(info_win, "Block Device"); - } else if (S_ISSOCK(file_stat.st_mode)) { - wprintw(info_win, "Socket"); - } else { - wprintw(info_win, "Unknown"); - } - wattroff(info_win, COLOR_PAIR(IMAGE_COLOR_PAIR)); - - clearLine(info_win, 10, 2); - wattron(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); - mvwprintw(info_win, 10, 2, "Permissions: "); - wattroff(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); - print_permissions(info_win, &file_stat); - - box(info_win, 0, 0); - wrefresh(info_win); -} - void refreshMainWin(WINDOW *win, WINDOW *info_win, FileItem items[], int item_count, int highlight, const char *current_path, int show_hidden, int scroll_position, int height, int info_height, int info_width, int info_starty, int info_startx) { check_term_size(win, info_win); werase(win); diff --git a/meson.build b/meson.build index d46b461..9a41633 100644 --- a/meson.build +++ b/meson.build @@ -50,7 +50,8 @@ src_files = files( 'src/highlight.c', 'src/hashtable.c', 'src/arg_helpers.c', - 'src/musicpreview.c' + 'src/musicpreview.c', + 'src/inodeinfo.c' ) # Executable target diff --git a/src/cursesutils.c b/src/cursesutils.c index 777e204..1479381 100644 --- a/src/cursesutils.c +++ b/src/cursesutils.c @@ -62,216 +62,220 @@ void colorLine(WINDOW* win, const char* info, int colorpair, int x, int y) int show_compression_options(WINDOW* parent_win) { - WINDOW* options_win; - int choice; - int highlight = 0; - int c; - int step = STEP_SELECT_FORMAT; // 0 for selecting format, 1 for selecting action - - // Define window size and position - int win_height = 10; - int win_width = 40; - int win_y = (LINES - win_height) / 2; - int win_x = (COLS - win_width) / 2; - - // Create a new window for displaying options - options_win = newwin(win_height, win_width, win_y, win_x); - box(options_win, 0, 0); - keypad(options_win, TRUE); // Enable special keys (e.g., arrow keys) - draw_3d_info_win(options_win, win_y, win_x, win_height, win_width, 2, 4); - - // Define colors - init_pair(COMP_COLOR_TITLE, COLOR_BLACK, COLOR_BLUE); // Title - init_pair(COMP_COLOR_HIGHLIGHT, COLOR_BLACK, COLOR_GREEN); // Highlighted option - init_pair(COMP_COLOR_NORMAL, COLOR_WHITE, COLOR_BLACK); // Normal text - init_pair(COMP_COLOR_FOOTER, COLOR_RED, COLOR_BLACK); // Footer text + WINDOW* options_win; + int choice; + int highlight = 0; + int c; + int step = STEP_SELECT_FORMAT; // 0 for selecting format, 1 for selecting action + + // Define window size and position + int win_height = 10; + int win_width = 40; + int win_y = (LINES - win_height) / 2; + int win_x = (COLS - win_width) / 2; + + // Create a new window for displaying options + options_win = newwin(win_height, win_width, win_y, win_x); + box(options_win, 0, 0); + keypad(options_win, TRUE); // Enable special keys (e.g., arrow keys) + draw_3d_info_win(options_win, win_y, win_x, win_height, win_width, 2, 4); + + // Define colors + init_pair(COMP_COLOR_TITLE, COLOR_BLACK, COLOR_BLUE); // Title + init_pair(COMP_COLOR_HIGHLIGHT, COLOR_BLACK, COLOR_GREEN); // Highlighted option + init_pair(COMP_COLOR_NORMAL, COLOR_WHITE, COLOR_BLACK); // Normal text + init_pair(COMP_COLOR_FOOTER, COLOR_RED, COLOR_BLACK); // Footer text + + const char* top_options[] = {"TAR (.tar)", "ZIP (.zip)"}; + const char* bottom_options[] = {"COMPRESS", "EXIT"}; + + int num_top_options = sizeof(top_options) / sizeof(top_options[0]); + int num_bottom_options = sizeof(bottom_options) / sizeof(bottom_options[0]); + char title_buf[60]; - const char* top_options[] = {"TAR (.tar)", "ZIP (.zip)"}; - const char* bottom_options[] = {"COMPRESS", "EXIT"}; + while (1) + { + // Clear the window + werase(options_win); - int num_top_options = sizeof(top_options) / sizeof(top_options[0]); - int num_bottom_options = sizeof(bottom_options) / sizeof(bottom_options[0]); - char title_buf[60]; + // Draw the box again + box(options_win, 0, 0); - while (1) + if (step == STEP_SELECT_FORMAT) { - // Clear the window - werase(options_win); - - // Draw the box again - box(options_win, 0, 0); - - if (step == STEP_SELECT_FORMAT) + // Display title + wattron(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); + mvwprintw(options_win, 1, (win_width - strlen(" Compression format: ")) / 2, + " Compression format: "); + wattroff(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); + + // Display top options + for (int i = 0; i < num_top_options; ++i) + { + if (i == highlight) { - // Display title - wattron(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); - mvwprintw(options_win, 1, (win_width - strlen(" Compression format: ")) / 2, - " Compression format: "); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); - - // Display top options - for (int i = 0; i < num_top_options; ++i) - { - if (i == highlight) - { - wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); - } - else - { - wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - } - mvwprintw(options_win, i + 3, (win_width - strlen(top_options[i])) / 2, " %s ", - top_options[i]); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); - } + wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); + } + else + { + wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + } + mvwprintw(options_win, i + 3, (win_width - strlen(top_options[i])) / 2, " %s ", + top_options[i]); + wattroff(options_win, + COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); + } - // Display bottom options - int bottom_y = win_height - 2; - int left_x = 2; - int right_x = win_width - strlen(bottom_options[1]) - 2; + // Display bottom options + int bottom_y = win_height - 2; + int left_x = 2; + int right_x = win_width - strlen(bottom_options[1]) - 2; - // Left bottom option (COMPRESS) - wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - mvwprintw(options_win, bottom_y, left_x, "%s", bottom_options[0]); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + // Left bottom option (COMPRESS) + wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + mvwprintw(options_win, bottom_y, left_x, "%s", bottom_options[0]); + wattroff(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - // Right bottom option (EXIT) - wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - mvwprintw(options_win, bottom_y, right_x, "%s", bottom_options[1]); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + // Right bottom option (EXIT) + wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + mvwprintw(options_win, bottom_y, right_x, "%s", bottom_options[1]); + wattroff(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - // Refresh and wait for user input - wrefresh(options_win); - c = wgetch(options_win); + // Refresh and wait for user input + wrefresh(options_win); + c = wgetch(options_win); - switch (c) - { - case KEY_UP: - if (highlight > 0) - { - highlight--; - } - break; - case KEY_DOWN: - if (highlight < num_top_options - 1) - { - highlight++; - } - break; - case 10: // Enter key - step = STEP_SELECT_ACTION; // Move to next step - snprintf(title_buf, 60, " Select %s action: ", top_options[highlight]); - choice = highlight + OPTION_TAR; // Assign OPTION_TAR (1) or OPTION_ZIP (2) - highlight = num_top_options; // Set default highlight to COMPRESS - break; - case 27: // ESC key - delwin(options_win); - refresh(); // Refresh the main window to ensure no artifacts remain - return -1; - } + switch (c) + { + case KEY_UP: + if (highlight > 0) + { + highlight--; + } + break; + case KEY_DOWN: + if (highlight < num_top_options - 1) + { + highlight++; + } + break; + case 10: // Enter key + step = STEP_SELECT_ACTION; // Move to next step + snprintf(title_buf, 60, " Select %s action: ", top_options[highlight]); + choice = highlight + OPTION_TAR; // Assign OPTION_TAR (1) or OPTION_ZIP (2) + highlight = num_top_options; // Set default highlight to COMPRESS + break; + case 27: // ESC key + delwin(options_win); + refresh(); // Refresh the main window to ensure no artifacts remain + return -1; + } + } + else if (step == STEP_SELECT_ACTION) + { + // Display title + wattron(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); + mvwprintw(options_win, 1, (win_width - strlen(title_buf)) / 2, title_buf); + wattroff(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); + + // Display top options + for (int i = 0; i < num_top_options; ++i) + { + if (i == highlight) + { + wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); } - else if (step == STEP_SELECT_ACTION) + else { - // Display title - wattron(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); - mvwprintw(options_win, 1, (win_width - strlen(title_buf)) / 2, title_buf); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_TITLE)); + wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + } + mvwprintw(options_win, i + 3, (win_width - strlen(top_options[i])) / 2, " %s ", + top_options[i]); + wattroff(options_win, + COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); + } - // Display top options - for (int i = 0; i < num_top_options; ++i) - { - if (i == highlight) - { - wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); - } - else - { - wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - } - mvwprintw(options_win, i + 3, (win_width - strlen(top_options[i])) / 2, " %s ", - top_options[i]); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); - } + // Display bottom options + int bottom_y = win_height - 2; + int left_x = 2; + int right_x = win_width - strlen(bottom_options[1]) - 2; - // Display bottom options - int bottom_y = win_height - 2; - int left_x = 2; - int right_x = win_width - strlen(bottom_options[1]) - 2; + // Left bottom option (COMPRESS) + if (highlight == num_top_options) + { + wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); + } + else + { + wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + } + mvwprintw(options_win, bottom_y, left_x, " %s ", bottom_options[0]); + wattroff(options_win, + COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); - // Left bottom option (COMPRESS) - if (highlight == num_top_options) - { - wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); - } - else - { - wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - } - mvwprintw(options_win, bottom_y, left_x, " %s ", bottom_options[0]); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); + // Right bottom option (EXIT) + if (highlight == num_top_options + 1) + { + wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); + } + else + { + wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); + } + mvwprintw(options_win, bottom_y, right_x, "%s", bottom_options[1]); + wattroff(options_win, + COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); - // Right bottom option (EXIT) - if (highlight == num_top_options + 1) + // Refresh and wait for user input + wrefresh(options_win); + c = wgetch(options_win); + + switch (c) + { + case KEY_LEFT: + if (highlight == num_top_options + 1) + { + highlight = num_top_options; // Move to COMPRESS + } + break; + case KEY_RIGHT: + if (highlight == num_top_options) + { + highlight = num_top_options + 1; // Move to EXIT + } + break; + case 10: // Enter key + if (highlight == num_top_options) + { + // Handle compression logic + delwin(options_win); + refresh(); // Refresh the main window to ensure no artifacts remain + if (choice == OPTION_TAR) { - wattron(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | A_BOLD); + return OPTION_TAR; // return 1 (compression type: tar) } else { - wattron(options_win, COLOR_PAIR(COMP_COLOR_NORMAL)); - } - mvwprintw(options_win, bottom_y, right_x, "%s", bottom_options[1]); - wattroff(options_win, COLOR_PAIR(COMP_COLOR_HIGHLIGHT) | COLOR_PAIR(COMP_COLOR_NORMAL) | A_BOLD); - - // Refresh and wait for user input - wrefresh(options_win); - c = wgetch(options_win); - - switch (c) - { - case KEY_LEFT: - if (highlight == num_top_options + 1) - { - highlight = num_top_options; // Move to COMPRESS - } - break; - case KEY_RIGHT: - if (highlight == num_top_options) - { - highlight = num_top_options + 1; // Move to EXIT - } - break; - case 10: // Enter key - if (highlight == num_top_options) - { - // Handle compression logic - delwin(options_win); - refresh(); // Refresh the main window to ensure no artifacts remain - if (choice == OPTION_TAR) - { - return OPTION_TAR; // return 1 (compression type: tar) - } - else - { - return OPTION_ZIP; // return 2 (compression type: zip) - } - } - else if (highlight == num_top_options + 1) - { - delwin(options_win); - refresh(); // Refresh the main window to ensure no artifacts remain - return OPTION_EXIT; // Indicate "EXIT" was chosen - } - break; - case 27: // ESC key - delwin(options_win); - refresh(); // Refresh the main window to ensure no artifacts remain - return -1; + return OPTION_ZIP; // return 2 (compression type: zip) } - } + } + else if (highlight == num_top_options + 1) + { + delwin(options_win); + refresh(); // Refresh the main window to ensure no artifacts remain + return OPTION_EXIT; // Indicate "EXIT" was chosen + } + break; + case 27: // ESC key + delwin(options_win); + refresh(); // Refresh the main window to ensure no artifacts remain + return -1; + } } + } - delwin(options_win); - wrefresh(parent_win); + delwin(options_win); + wrefresh(parent_win); } void show_term_message(const char* message, int err) diff --git a/src/inodeinfo.c b/src/inodeinfo.c new file mode 100644 index 0000000..fc25f98 --- /dev/null +++ b/src/inodeinfo.c @@ -0,0 +1,410 @@ + +#include "../include/inodeinfo.h" +#include "../include/cursesutils.h" +#include "../include/filepreview.h" +#include "../include/logging.h" + +const char* denied_message[] = {" .__ __. ______ _______. __ __ ", + " | \\ | | / __ \\ / || | | | ", + " | \\| | | | | | | (----`| | | | ", + " | . ` | | | | | \\ \\ | | | | ", + " | |\\ | | `--' | .----) | | `--' | __ ", + " |__| \\__| \\______/ |_______/ \\______/ (__)", + " "}; + +void get_file_info_popup(WINDOW* main_win, const char* path, const char* filename) +{ + struct stat file_stat; + char full_path[PATH_MAX]; + snprintf(full_path, PATH_MAX, "%s/%s", path, filename); + + // Get file information + if (stat(full_path, &file_stat) == -1) + { + log_message(LOG_LEVEL_ERROR, "Error retrieving file information for `%s`", full_path); + show_message(main_win, "Error retrieving file information."); + return; + } + + // Create a new window for displaying file information + int info_win_height = 13; + int info_win_width = (COLS / 3) + 4; + int info_win_y = (LINES - info_win_height) / 2; + int info_win_x = (COLS - info_win_width) / 2; + + WINDOW* info_win = newwin(info_win_height, info_win_width, info_win_y, info_win_x); + draw_3d_info_win(info_win, info_win_y, info_win_x, info_win_height, info_win_width, 1, 2); + box(info_win, 0, 0); + + // Display file information with colors + colorLine(info_win, "File Information: ", 1, 1, + 2); /* colorLine params: win, string, color_pair, x, y */ + colorLine(info_win, "Name: ", 3, 3, 2); + + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%s", filename); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + colorLine(info_win, "Size: ", 3, 4, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%s", format_file_size(file_stat.st_size)); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + const char* file_ext = strrchr(filename, '.'); + colorLine(info_win, "File Type: ", 3, 5, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + if (file_ext != NULL) + { + wprintw(info_win, "%s", determine_file_type(full_path)); + } + else + { + wprintw(info_win, "none"); + } + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + colorLine(info_win, "Last Modified: ", 3, 6, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + char mod_time[20]; + strftime(mod_time, sizeof(mod_time), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); + wprintw(info_win, "%s", mod_time); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + colorLine(info_win, "Permissions: ", 3, 7, 2); + print_permissions(info_win, &file_stat); + + colorLine(info_win, "Inode: ", 3, 8, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%lu", file_stat.st_ino); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + // Additional file attributes can be displayed here + struct passwd* pwd = getpwuid(file_stat.st_uid); + wattron(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); + mvwprintw(info_win, 9, 2, "Owner: "); + wattroff(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%s (%d)", pwd->pw_name, file_stat.st_uid); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + colorLine(info_win, "Press any key to close this window.", 2, info_win_height - 2, 2); + wrefresh(info_win); + + wgetch(info_win); // Wait for user input + wclear(info_win); // Clear info window before deleting + delwin(info_win); // Delete info window + + // Refresh the main window to ensure no artifacts remain + wrefresh(main_win); +} + +void get_file_info(WINDOW* info_win, const char* path, const char* filename) +{ + werase(info_win); + struct stat file_stat; + char full_path[PATH_MAX]; + char truncated_file_name[MAX_ITEM_NAME_LENGTH + 4]; // +4 for ellipsis and space + char symlink_target[PATH_MAX]; + ssize_t len; + + snprintf(full_path, PATH_MAX, "%s/%s", path, filename); + truncate_symlink_name(full_path); + + // Get file information using lstat to handle symlinks + if (lstat(full_path, &file_stat) == -1) + { + log_message(LOG_LEVEL_ERROR, "Error retrieving file information for %s", full_path); + show_message(info_win, "Error retrieving file/dir info."); + box(info_win, 0, 0); + wrefresh(info_win); + return; + } + + if (access(full_path, R_OK) != 0) + { + log_message(LOG_LEVEL_ERROR, "Access denied for %s", full_path); + int denied_message_size = sizeof(denied_message) / sizeof(denied_message[0]); + for (int j = 0; j < denied_message_size; j++) + { + mvwprintw(info_win, j + 3, 2, "%s", denied_message[j]); + } + show_message(info_win, "Access denied for you!"); + box(info_win, 0, 0); + wrefresh(info_win); + return; + } + + // Truncate the filename if necessary + if (strlen(filename) > MAX_ITEM_NAME_LENGTH) + { + snprintf(truncated_file_name, sizeof(truncated_file_name), "%.80s...", filename); + } + else + { + snprintf(truncated_file_name, sizeof(truncated_file_name), "%s", filename); + } + + // Display file information + wattron(info_win, A_BOLD); + mvwprintw(info_win, 1, 2, "File/Dir Information:"); + wattroff(info_win, A_BOLD); + + clearLine(info_win, 3, 2); + colorLine(info_win, "Name: ", 3, 3, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%s", truncated_file_name); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + clearLine(info_win, 4, 2); + colorLine(info_win, "Size: ", 3, 4, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%s", format_file_size(file_stat.st_size)); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + const char* file_ext = strrchr(filename, '.'); + clearLine(info_win, 5, 2); + colorLine(info_win, "Inode Type: ", 3, 5, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + if (!S_ISDIR(file_stat.st_mode)) + { + wprintw(info_win, "%s", determine_file_type(full_path)); + } + else + { + wprintw(info_win, "Directory"); + } + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + char mod_time[20]; + strftime(mod_time, sizeof(mod_time), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); + clearLine(info_win, 6, 2); + colorLine(info_win, "Last Modified: ", 3, 6, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%s", mod_time); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + colorLine(info_win, "Inode: ", 3, 7, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, "%lu", file_stat.st_ino); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + clearLine(info_win, 8, 2); + colorLine(info_win, "Group: ", 3, 8, 2); + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + struct group* grp = getgrgid(file_stat.st_gid); + if (grp != NULL) + { + wprintw(info_win, "%s", grp->gr_name); + } + else + { + wprintw(info_win, "Unknown"); + } + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + + clearLine(info_win, 9, 2); + colorLine(info_win, "Type: ", 3, 9, 2); + wattron(info_win, COLOR_PAIR(IMAGE_COLOR_PAIR)); + if (S_ISREG(file_stat.st_mode)) + { + wprintw(info_win, "Regular File"); + + // Check if the file is an archive + if (file_ext != NULL && (strcmp(file_ext, ".zip") == 0 || strcmp(file_ext, ".7z") == 0 || + strcmp(file_ext, ".tar") == 0 || strcmp(file_ext, ".gz") == 0)) + { + // Display archive contents + display_archive_contents(info_win, full_path, file_ext); + } + } + else if (S_ISDIR(file_stat.st_mode)) + { + wattron(info_win, COLOR_PAIR(SPECIAL_COLOR_PAIR)); + wprintw(info_win, "Directory"); + wattroff(info_win, COLOR_PAIR(SPECIAL_COLOR_PAIR)); + + // Horizontal Layout for Parent Directories and Subdirectories + wattron(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); + mvwprintw(info_win, 12, 2, " Parent Directories: "); + mvwprintw(info_win, 12, getmaxx(info_win) / 2, " Children: "); + wattroff(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); + + char parent_dir[PATH_MAX]; + char current_path[PATH_MAX]; + strncpy(current_path, path, sizeof(current_path)); + current_path[sizeof(current_path) - 1] = '\0'; // Ensure null termination + char* parent_dir_ptr = dirname(current_path); + + // Make a copy of the parent directory path to avoid modifying the original path + strncpy(parent_dir, parent_dir_ptr, sizeof(parent_dir)); + parent_dir[sizeof(parent_dir) - 1] = '\0'; // Ensure null termination + int line = 13; + int sub_dir_line = 13; + int max_y, max_x; + getmaxyx(info_win, max_y, max_x); + + // Print parent directories on the left + DIR* dir = opendir(parent_dir); + struct dirent* entry; + if (dir != NULL) + { + wattron(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); + mvwprintw(info_win, 10, 2, " Parent Directories: "); + wattroff(info_win, A_BOLD | COLOR_PAIR(DARK_BG_COLOR_PAIR)); + + int col = 2; // Starting column + wattron(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); + while ((entry = readdir(dir)) != NULL) + { + if (entry->d_type == DT_DIR) + { + // Exclude the current directory and the special entries "." and ".." + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && + entry->d_name[0] != '.') + { + // Truncate directory name if necessary + char truncated_dir_name[MAX_ITEM_NAME_LENGTH + 4]; // +4 for ellipsis and space + if (strlen(entry->d_name) > MAX_ITEM_NAME_LENGTH) + { + snprintf(truncated_dir_name, sizeof(truncated_dir_name), "%.40s...", entry->d_name); + } + else + { + snprintf(truncated_dir_name, sizeof(truncated_dir_name), "%s", entry->d_name); + } + // Print the directory name + mvwprintw(info_win, line++, 2, "%s", truncated_dir_name); + } + } + } + closedir(dir); + wattroff(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); + } + else + { + show_message(info_win, "Error opening parent directory."); + } + + // Print subdirectories and files on the right + dir = opendir(full_path); + if (dir != NULL) + { + while ((entry = readdir(dir)) != NULL && sub_dir_line < max_y - 1) + { + if (entry->d_type == DT_DIR) + { + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) + { + // Truncate directory name if necessary + char truncated_sub_dir_name[MAX_ITEM_NAME_LENGTH + 4]; + if (strlen(entry->d_name) > MAX_ITEM_NAME_LENGTH) + { + snprintf(truncated_sub_dir_name, sizeof(truncated_sub_dir_name), "%.40s...", + entry->d_name); + } + else + { + snprintf(truncated_sub_dir_name, sizeof(truncated_sub_dir_name), "%s", entry->d_name); + } + wattron(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); + mvwprintw(info_win, sub_dir_line++, max_x / 2, " %s", truncated_sub_dir_name); + wattroff(info_win, A_BOLD | COLOR_PAIR(DIR_COLOR_PAIR)); + } + } + } + rewinddir(dir); + while ((entry = readdir(dir)) != NULL && sub_dir_line < max_y - 1) + { + if (entry->d_type != DT_DIR) + { + // Truncate file name if necessary + char truncated_file_name[MAX_ITEM_NAME_LENGTH + 4]; + if (strlen(entry->d_name) + sub_dir_line > MAX_ITEM_NAME_LENGTH) + { + snprintf(truncated_file_name, sizeof(truncated_file_name), "%.40s...", entry->d_name); + } + else + { + snprintf(truncated_file_name, sizeof(truncated_file_name), "%s", entry->d_name); + } + wattron(info_win, A_BOLD | COLOR_PAIR(FILE_COLOR_PAIR)); + mvwprintw(info_win, sub_dir_line++, max_x / 2, " %s", truncated_file_name); + wattroff(info_win, A_BOLD | COLOR_PAIR(FILE_COLOR_PAIR)); + } + } + closedir(dir); + } + else + { + show_message(info_win, "Error opening directory."); + } + } + else if (S_ISLNK(file_stat.st_mode)) + { + wattron(info_win, COLOR_PAIR(SYMLINK_COLOR_PAIR)); + wprintw(info_win, "Symbolic Link"); + + // Read the symlink target + len = readlink(full_path, symlink_target, sizeof(symlink_target) - 1); + if (len != -1) + { + symlink_target[len] = '\0'; // Null-terminate the string + wattron(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + wprintw(info_win, " to %s", symlink_target); + wattroff(info_win, COLOR_PAIR(AUDIO_COLOR_PAIR)); + } + else + { + show_message(info_win, "Error reading symlink target."); + } + wattroff(info_win, COLOR_PAIR(SYMLINK_COLOR_PAIR)); + } + else if (S_ISFIFO(file_stat.st_mode)) + { + wprintw(info_win, "FIFO"); + } + else if (S_ISCHR(file_stat.st_mode)) + { + wprintw(info_win, "Character Device"); + } + else if (S_ISBLK(file_stat.st_mode)) + { + wprintw(info_win, "Block Device"); + } + else if (S_ISSOCK(file_stat.st_mode)) + { + wprintw(info_win, "Socket"); + } + else + { + wprintw(info_win, "Unknown"); + } + wattroff(info_win, COLOR_PAIR(IMAGE_COLOR_PAIR)); + + clearLine(info_win, 10, 2); + wattron(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); + mvwprintw(info_win, 10, 2, "Permissions: "); + wattroff(info_win, COLOR_PAIR(ARCHIVE_COLOR_PAIR)); + print_permissions(info_win, &file_stat); + + box(info_win, 0, 0); + wrefresh(info_win); +} + +/* + * TRUNCATING A SYMLINK NAME IS NECESSARY AS THE ITEM NAME MIGHT HAVE + * THE STRING QUERY WE ARE LOOKING FOR, + * + * EXAMPLE: LIB64 ->LIB + * IF I WANT TO SEARCH FOR LIB, I SHOULD GO TO THE ITEM THAT ACTUALLY + * HAS THE STRING `LIB`, AND NOT A SYMLINK OF IT. + * + */ +void truncate_symlink_name(char* name) +{ + char* arrow = strstr(name, " ->"); + if (arrow) + { + *arrow = '\0'; // Truncate the name at the " -> " point + } +}