cex.c (35753B)
1 #include <sys/stat.h> 2 #include <sys/param.h> 3 #include <ctype.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 #include <libgen.h> 7 #include <string.h> 8 #include <time.h> 9 #include <langinfo.h> 10 #include <pwd.h> 11 #include <grp.h> 12 #include <dirent.h> 13 #include <errno.h> 14 #include <curses.h> 15 16 #include "config.h" 17 18 #define ctrl(x) ((x) & 0x1f) 19 #define arrlen(arr) (sizeof(arr)/sizeof(0[arr])) 20 21 typedef enum {OTHER, LEFT, RIGHT, UP, DOWN} Direction; 22 typedef enum {CURRENT, PARENT, CHILD} WinType; 23 typedef enum {COPY, REMOVE, MOVE} SelAction; 24 25 typedef struct _win_file { 26 char d_name[256]; 27 unsigned char d_type; 28 bool selected; 29 } WinFile; 30 31 typedef struct _dir_win { 32 WinType wintype; 33 WINDOW *window; 34 WinFile *winfiles; 35 char path[PATH_MAX]; 36 char *message; 37 int maxx; 38 int maxy; 39 int startpr; 40 int highlight; 41 int filecount; 42 bool holdupdate; 43 bool usehighlight; 44 } DirWin; 45 46 static void init_dirwins(void); 47 static void init_screen(void); 48 static void resize(void); 49 static void start(void); 50 static void wpath(const char *filename); 51 static void reset_flags(void); 52 static void set_startpr(DirWin *dirwin); 53 static void set_win_files(DirWin *dirwin); 54 static void set_win_message(DirWin *dirwin, char *message); 55 static void print_win(DirWin *dirwin); 56 static void update_child_win(void); 57 static void print_top_title(void); 58 static void print_bot_title(void); 59 static void print_content(void); 60 static void print_error(size_t size, const char *fmt, ...); 61 static void show_file_mime(void); 62 static void select_file(const char *path); 63 static void exe_selection(SelAction action, const char *askn); 64 static void clear_selected(void); 65 static void clear_search(void); 66 static void combo_key(int keypress); 67 static void combo_go(int keypress); 68 static void combo_inf(int keypress); 69 static void combo_open(int keypress); 70 static void combo_make(int keypress); 71 static void change_dir(const char *chdname, Direction direction, bool abspath); 72 static void change_parent_dir(Direction direction); 73 static void open_child(bool exec); 74 static void open_nohup_xdg(void); 75 static void search(void); 76 static void move_top(DirWin *dirwin); 77 static void move_bot(DirWin *dirwin); 78 static void move_page_up(DirWin *dirwin); 79 static void move_page_down(DirWin *dirwin); 80 static void move_up(DirWin *dirwin); 81 static void move_down(DirWin *dirwin); 82 static void next_search(void); 83 static void prev_search(void); 84 static void free_dirwin(DirWin *dirwin); 85 static void run_command(size_t size, const char *fmt, ...); 86 static void run_sudo_command(size_t size, const char *fmt, ...); 87 static void clean(void); 88 static void fatal(const char *fmt, ...); 89 static bool is_dir(DirWin *dirwin, size_t index); 90 static bool is_selected(DirWin *dirwin, size_t count); 91 static bool remove_selected(const char *sel); 92 static bool prompt_confirm(size_t size, const char *fmt, ...); 93 static int compare_file(const void *a, const void *b); 94 static int get_mime(char *buf, size_t bufsize, const char *path); 95 static int get_mime_default(char *buf, size_t bufsize, const char *mime); 96 static int read_command(char *buf, size_t bufsize, const char *cmd); 97 static int make_file(void); 98 static int make_dir(void); 99 static int make_mod(void); 100 static int make_chown(void); 101 static int sudo_chown(char *owner, char *group, long namelen); 102 static void make_access(void); 103 static void make_open_default(void); 104 static void make_mime_default(const char *mime, const char *app); 105 static int rm_file(const char *fname); 106 static int rename_file(const char *fname); 107 static char *human_readable_bytes(char *buf, intmax_t bytes); 108 static char *prompt_answer(char *buf, size_t size, const char *question); 109 static char *cpstr(char *dest, const char *src); 110 static char *get_file_info(char *buf, const char *filepath); 111 static char *get_fullpath(char *buf, DirWin *dirwin, size_t index); 112 static char *get_dirname(char *buf, const char *path); 113 static char *replace_home(char *buf, const char *path); 114 static mode_t get_st_mode(DirWin *dirwin, size_t index); 115 116 static DirWin curwin, parwin, childwin; 117 static char *userhome, *username, *editor, **selected, searchq[SEARCHLEN]; 118 static int maxy, maxx; 119 static size_t selc, searchc; 120 static bool print_bot, hide = DEFAULT_HIDE; 121 122 int 123 main(int argc, char **argv) 124 { 125 struct passwd userinf; 126 char filename[PATH_MAX]; 127 int opt; 128 bool writepath = FALSE; 129 130 while ((opt = getopt(argc, argv, "f:")) != -1) { 131 switch (opt) { 132 case 'f': 133 cpstr(filename, optarg); 134 writepath = TRUE; 135 break; 136 default: 137 fatal("Unknown option: %c\n", optopt); 138 break; 139 } 140 } 141 142 editor = getenv("EDITOR"); 143 144 userinf = *getpwuid(getuid()); 145 username = strdup(userinf.pw_name); 146 userhome = strdup(userinf.pw_dir); 147 148 init_dirwins(); 149 init_screen(); 150 151 start(); 152 153 if (writepath) 154 wpath(filename); 155 156 clean(); 157 } 158 159 void 160 init_dirwins(void) 161 { 162 curwin.wintype = CURRENT; 163 parwin.wintype = PARENT; 164 childwin.wintype = CHILD; 165 166 reset_flags(); 167 168 childwin.highlight = 0; 169 170 if (getcwd(curwin.path, PATH_MAX) == NULL) 171 fatal("getcwd() error"); 172 173 get_dirname(parwin.path, curwin.path); 174 175 set_win_files(&curwin); 176 set_win_files(&parwin); 177 178 if (curwin.winfiles != NULL && curwin.winfiles[0].d_type == DT_DIR) { 179 cpstr(childwin.path, curwin.path); 180 update_child_win(); 181 } 182 } 183 184 void 185 init_screen(void) 186 { 187 initscr(); 188 noecho(); 189 start_color(); 190 use_default_colors(); 191 keypad(stdscr, TRUE); 192 curs_set(0); 193 194 clear(); 195 cbreak(); 196 197 init_pair(COLOR_BLACK, COLOR_BLACK, -1); 198 init_pair(COLOR_RED, COLOR_RED, -1); 199 init_pair(COLOR_GREEN,COLOR_GREEN, -1); 200 init_pair(COLOR_YELLOW, COLOR_YELLOW, -1); 201 init_pair(COLOR_BLUE, COLOR_BLUE, -1); 202 init_pair(COLOR_MAGENTA, COLOR_MAGENTA, -1); 203 init_pair(COLOR_CYAN, COLOR_CYAN, -1); 204 init_pair(COLOR_WHITE, COLOR_WHITE, -1); 205 206 curwin.highlight = 0; 207 curwin.startpr = 0; 208 209 parwin.highlight = 0; 210 parwin.startpr = 0; 211 212 childwin.highlight = 0; 213 childwin.startpr = 0; 214 215 resize(); 216 217 print_top_title(); 218 print_bot_title(); 219 220 print_win(&parwin); 221 print_win(&curwin); 222 print_win(&childwin); 223 } 224 225 void 226 resize(void) 227 { 228 int startx; 229 230 getmaxyx(stdscr, maxy, maxx); 231 232 parwin.maxy = maxy-BORDER_SPACE_SIZE; 233 parwin.maxx = maxx/4-BORDER_SPACE_SIZE > 0 ? maxx/4-BORDER_SPACE_SIZE : 1; 234 startx = maxx > BORDER_SPACE_SIZE ? BORDER_SPACE_SIZE : 0; 235 parwin.window = newwin(parwin.maxy, parwin.maxx, BORDER_SPACE_SIZE, startx); 236 237 curwin.maxy = maxy-BORDER_SPACE_SIZE; 238 curwin.maxx = maxx/4-BORDER_SPACE_SIZE > 0 ? maxx/4-BORDER_SPACE_SIZE : 1; 239 startx = maxx > curwin.maxx+BORDER_SPACE_SIZE*2 ? curwin.maxx+BORDER_SPACE_SIZE*2 : 0; 240 curwin.window = newwin(curwin.maxy, curwin.maxx, BORDER_SPACE_SIZE, startx); 241 242 childwin.maxy = maxy-BORDER_SPACE_SIZE; 243 childwin.maxx = maxx/2-BORDER_SPACE_SIZE > 0 ? maxx/2-BORDER_SPACE_SIZE : 1; 244 startx = maxx > childwin.maxx+BORDER_SPACE_SIZE*2 ? childwin.maxx+BORDER_SPACE_SIZE*2 : 0; 245 childwin.window = newwin(childwin.maxy, childwin.maxx, BORDER_SPACE_SIZE, startx); 246 247 erase(); 248 refresh(); 249 250 update_child_win(); 251 } 252 253 void 254 start(void) 255 { 256 int c; 257 char chdname[PATH_MAX]; 258 259 while ((c = getch()) != KEY_QUIT) { 260 move(1, 1); 261 clrtoeol(); 262 reset_flags(); 263 switch (c) { 264 case KEY_UP: 265 case KEY_VUP: 266 move_up(&curwin); 267 update_child_win(); 268 break; 269 case KEY_DOWN: 270 case KEY_VDOWN: 271 move_down(&curwin); 272 update_child_win(); 273 break; 274 case KEY_VPUP: 275 if (is_dir(&parwin, MAX(parwin.highlight-1, 0))) 276 change_parent_dir(UP); 277 break; 278 case KEY_VPDOWN: 279 if (is_dir(&parwin, MIN(parwin.highlight+1, parwin.filecount-1))) 280 change_parent_dir(DOWN); 281 break; 282 case KEY_PPAGE: 283 case ctrl('u'): 284 move_page_up(&curwin); 285 update_child_win(); 286 break; 287 case KEY_NPAGE: 288 case ctrl('d'): 289 move_page_down(&curwin); 290 update_child_win(); 291 break; 292 case KEY_BOT: 293 move_bot(&curwin); 294 update_child_win(); 295 break; 296 case 10: 297 case KEY_VRIGHT: 298 case KEY_VRIGHT_ABS: 299 if (is_dir(&curwin, curwin.highlight)) 300 change_dir(get_fullpath(chdname, &curwin, curwin.highlight), 301 RIGHT, c == KEY_VRIGHT_ABS); 302 else if (S_ISREG(get_st_mode(&curwin, curwin.highlight))) 303 open_child(FALSE); 304 break; 305 case KEY_LEFT: 306 case KEY_VLEFT: 307 change_dir(get_dirname(chdname, curwin.path), LEFT, FALSE); 308 break; 309 case KEY_SEARCH: 310 search(); 311 update_child_win(); 312 break; 313 case KEY_NEXT_SEARCH: 314 next_search(); 315 update_child_win(); 316 break; 317 case KEY_PREV_SEARCH: 318 prev_search(); 319 update_child_win(); 320 break; 321 case KEY_SEL_FILE: 322 select_file(get_fullpath(chdname, &curwin, curwin.highlight)); 323 set_win_files(&curwin); 324 update_child_win(); 325 break; 326 case KEY_CLEAR_SEL: 327 clear_selected(); 328 set_win_files(&curwin); 329 set_win_files(&parwin); 330 update_child_win(); 331 break; 332 case KEY_CLEAR_SEARCH: 333 clear_search(); 334 set_win_files(&curwin); 335 break; 336 case KEY_CP_SEL: 337 exe_selection(COPY, NULL); 338 break; 339 case KEY_RM_SEL: 340 exe_selection(REMOVE, "Remove"); 341 break; 342 case KEY_MV_SEL: 343 exe_selection(MOVE, "Move"); 344 break; 345 case KEY_RM_FILE: 346 rm_file(curwin.winfiles[curwin.highlight].d_name); 347 set_win_files(&curwin); 348 update_child_win(); 349 break; 350 case KEY_RENAME_FILE: 351 rename_file(curwin.winfiles[curwin.highlight].d_name); 352 set_win_files(&curwin); 353 update_child_win(); 354 break; 355 case KEY_HIDE: 356 hide = hide ? FALSE : TRUE; 357 curwin.highlight = 0; 358 curwin.startpr = 0; 359 set_win_files(&curwin); 360 set_win_files(&parwin); 361 update_child_win(); 362 break; 363 case KEY_COMBO_GO: 364 case KEY_COMBO_INF: 365 case KEY_COMBO_OPEN: 366 case KEY_COMBO_MAKE: 367 combo_key(c); 368 break; 369 case KEY_RESIZE: 370 resize(); 371 break; 372 default: 373 break; 374 } 375 376 print_top_title(); 377 if (print_bot) 378 print_bot_title(); 379 print_win(&parwin); 380 print_win(&curwin); 381 print_win(&childwin); 382 } 383 } 384 385 void 386 wpath(const char *filename) 387 { 388 FILE *fptr; 389 390 if ((fptr = fopen(filename, "w")) == NULL) 391 fatal("Error opening file \"%s\"\n", filename); 392 fprintf(fptr, "%s\n", curwin.path); 393 fclose(fptr); 394 } 395 396 void 397 reset_flags(void) 398 { 399 parwin.usehighlight = FALSE; 400 curwin.usehighlight = TRUE; 401 childwin.usehighlight = TRUE; 402 403 parwin.holdupdate = FALSE; 404 curwin.holdupdate = FALSE; 405 childwin.holdupdate = FALSE; 406 407 print_bot = TRUE; 408 } 409 410 void 411 set_startpr(DirWin *dirwin) 412 { 413 if (dirwin->winfiles == NULL) { 414 dirwin->startpr = 0; 415 return; 416 } 417 418 dirwin->startpr = MAX(dirwin->highlight - dirwin->maxy/2, 0); 419 } 420 421 void 422 set_win_files(DirWin *dirwin) 423 { 424 struct dirent *ent; 425 size_t count = 0; 426 DIR *dir; 427 428 free_dirwin(dirwin); 429 430 if (dirwin->wintype == PARENT && strcmp(curwin.path, "/") == 0) 431 return; 432 433 if ((dir = opendir(dirwin->path)) == NULL) { 434 switch (errno) { 435 case EACCES: 436 set_win_message(dirwin, "No permission."); 437 return; 438 default: 439 fatal("Could not open directory: %s", dirwin->path); 440 } 441 } 442 443 if ((dirwin->winfiles = (WinFile*) malloc(sizeof(WinFile))) == NULL) 444 fatal("Fatal: failed to malloc.\n"); 445 446 while ((ent = readdir(dir)) != NULL) { 447 if (strcmp(ent->d_name, ".") == 0 448 || strcmp(ent->d_name, "..") == 0 449 || (hide && ent->d_name[0] == '.')) 450 continue; 451 if ((dirwin->winfiles = (WinFile*) realloc(dirwin->winfiles, (count+1)*(sizeof(WinFile)))) == NULL) 452 fatal("Fatal: failed to realloc.\n"); 453 cpstr(dirwin->winfiles[count].d_name, ent->d_name); 454 dirwin->winfiles[count].d_type = ent->d_type; 455 dirwin->winfiles[count].selected = is_selected(dirwin, count); 456 (count)++; 457 } 458 closedir(dir); 459 460 dirwin->filecount = count; 461 462 if (count == 0) 463 set_win_message(dirwin, "empty"); 464 else 465 qsort(dirwin->winfiles, count, sizeof(WinFile), compare_file); 466 } 467 468 bool 469 is_selected(DirWin *dirwin, size_t index) 470 { 471 char buf[PATH_MAX]; 472 473 if (selc == 0 || selected == NULL) 474 return FALSE; 475 476 get_fullpath(buf, dirwin, index); 477 478 for (size_t i = 0; i < selc; i++) { 479 if (strcmp(buf, selected[i]) == 0) 480 return TRUE; 481 } 482 483 return FALSE; 484 } 485 486 bool 487 remove_selected(const char *sel) 488 { 489 bool res = FALSE; 490 491 if (selc == 0) 492 return res; 493 494 for (size_t i = 0; i < selc; i++) { 495 if (strcmp(selected[i], sel) == 0) { 496 free(selected[i]); 497 selected[i] = selected[selc-1]; 498 res = TRUE; 499 break; 500 } 501 } 502 503 if (!res) 504 return res; 505 506 if (--(selc) == 0) { 507 free(selected); 508 selected = NULL; 509 } else if ((selected = (char**) realloc(selected, selc * sizeof(char *))) == NULL) 510 fatal("Fatal: failed to realloc.\n"); 511 512 return res; 513 } 514 515 void 516 set_win_message(DirWin *dirwin, char *message) 517 { 518 free_dirwin(dirwin); 519 dirwin->message = message; 520 } 521 522 void 523 print_win(DirWin *dirwin) 524 { 525 if (dirwin->holdupdate) 526 return; 527 528 size_t cplen, size = dirwin->maxx; 529 char *subs, name[size+1], sbuf[size+1], pathbuf[PATH_MAX]; 530 int sindex, y = 0, x = 1; 531 532 werase(dirwin->window); 533 534 set_startpr(dirwin); 535 536 if (dirwin->message != NULL) { 537 if (dirwin->wintype == CURRENT) { 538 wattron(dirwin->window, A_REVERSE); 539 mvwaddstr(dirwin->window, y, x, dirwin->message); 540 wattroff(dirwin->window, A_REVERSE); 541 } else { 542 wattron(dirwin->window, COLOR_PAIR(CHILDWIN_MESSAGE_COLOR)); 543 mvwaddstr(dirwin->window, y, x, dirwin->message); 544 wattroff(dirwin->window, COLOR_PAIR(CHILDWIN_MESSAGE_COLOR)); 545 } 546 } else if (dirwin->winfiles != NULL) { 547 while (!dirwin->usehighlight) { 548 for (int i = 0; i < dirwin->filecount; ++i) { 549 memcpy(name, dirwin->winfiles[i].d_name, size); 550 name[size] = '\0'; 551 if (strcmp(basename(curwin.path), dirwin->winfiles[i].d_name) == 0) { 552 dirwin->usehighlight = TRUE; 553 dirwin->highlight = i; 554 set_startpr(dirwin); 555 break; 556 } 557 } 558 break; 559 } 560 for (int i = dirwin->startpr; i < dirwin->filecount; ++i) { 561 mvwaddch(dirwin->window, y, x-1, ' '); 562 if (dirwin->winfiles[i].selected) { 563 wattron(dirwin->window, COLOR_PAIR(MARK_SELECTED_COLOR)); 564 mvwaddch(dirwin->window, y, x-1, '|'); 565 wattroff(dirwin->window, COLOR_PAIR(MARK_SELECTED_COLOR)); 566 } 567 memcpy(name, dirwin->winfiles[i].d_name, size); 568 name[size-1] = '\0'; 569 if (dirwin->usehighlight && dirwin->highlight == i) { 570 wattron(dirwin->window, A_REVERSE); 571 mvwaddstr(dirwin->window, y, x, name); 572 wattroff(dirwin->window, A_REVERSE); 573 } else if (dirwin->winfiles[i].d_type == DT_DIR) { 574 wattron(dirwin->window, COLOR_PAIR(DIR_COLOR)); 575 wattron(dirwin->window, A_BOLD); 576 mvwaddstr(dirwin->window, y, x, name); 577 wattroff(dirwin->window, COLOR_PAIR(DIR_COLOR)); 578 wattroff(dirwin->window, A_BOLD); 579 } else if (dirwin->winfiles[i].d_type == DT_LNK) { 580 if (access(get_fullpath(pathbuf, dirwin, i), F_OK) == 0) { 581 wattron(dirwin->window, COLOR_PAIR(LN_COLOR)); 582 mvwaddstr(dirwin->window, y, x, name); 583 wattroff(dirwin->window, COLOR_PAIR(LN_COLOR)); 584 } else { 585 wattron(dirwin->window, COLOR_PAIR(INVALID_LN_COLOR)); 586 mvwaddstr(dirwin->window, y, x, name); 587 wattroff(dirwin->window, COLOR_PAIR(INVALID_LN_COLOR)); 588 } 589 } else 590 mvwaddstr(dirwin->window, y, x, name); 591 if (dirwin->wintype == CURRENT && searchc > 0 592 && ((subs = strstr(name, searchq)) != NULL)) { 593 sindex = (int) (subs - name); 594 wattron(dirwin->window, COLOR_PAIR(SEARCH_MATCH_COLOR)); 595 if (dirwin->usehighlight && dirwin->highlight == i) 596 wattron(dirwin->window, A_REVERSE); 597 cplen = strlen(searchq); 598 memcpy(sbuf, name + sindex, cplen); 599 sbuf[cplen] = '\0'; 600 mvwaddstr(dirwin->window, y, x+sindex, sbuf); 601 wattroff(dirwin->window, COLOR_PAIR(SEARCH_MATCH_COLOR)); 602 if (dirwin->usehighlight && dirwin->highlight == i) 603 wattroff(dirwin->window, A_REVERSE); 604 } 605 y++; 606 } 607 } 608 wrefresh(dirwin->window); 609 } 610 611 void 612 update_child_win(void) 613 { 614 if (curwin.filecount <= 0) { 615 free_dirwin(&childwin); 616 return; 617 } 618 619 get_fullpath(childwin.path, &curwin, curwin.highlight); 620 621 switch (curwin.winfiles[curwin.highlight].d_type) { 622 case DT_LNK: 623 if (access(childwin.path, F_OK) != 0) { 624 set_win_message(&childwin, "Link no longer exists."); 625 break; 626 } 627 if (is_dir(&curwin, curwin.highlight)) 628 goto dir; 629 else if (S_ISREG(get_st_mode(&curwin, curwin.highlight))) 630 goto reg; 631 else 632 goto def; 633 break; 634 case DT_DIR: 635 dir: 636 set_win_files(&childwin); 637 break; 638 case DT_REG: 639 reg: 640 print_content(); 641 break; 642 default: 643 def: 644 werase(childwin.window); 645 free_dirwin(&childwin); 646 set_win_message(&childwin, "Not a regular file or directory."); 647 wrefresh(childwin.window); 648 break; 649 } 650 } 651 652 void 653 print_top_title(void) 654 { 655 move(0, 0); 656 clrtoeol(); 657 attron(COLOR_PAIR(TOP_TITLE_COLOR)); 658 printw("%s:%s/%s", username, curwin.path, curwin.winfiles[curwin.highlight].d_name); 659 attroff(COLOR_PAIR(TOP_TITLE_COLOR)); 660 } 661 662 void 663 print_bot_title(void) 664 { 665 char pathbuf[PATH_MAX], fileinf[maxx]; 666 667 get_fullpath(pathbuf, &curwin, curwin.highlight); 668 memcpy(fileinf, get_file_info(fileinf, pathbuf), maxx); 669 fileinf[maxx] = '\0'; 670 671 move(maxy-1, 0); 672 clrtoeol(); 673 674 attron(COLOR_PAIR(BOT_TITLE_COUNT_COLOR)); 675 printw("(%d/%d) ", curwin.filecount == 0 ? 0 : curwin.highlight+1, curwin.filecount); 676 attroff(COLOR_PAIR(BOT_TITLE_COUNT_COLOR)); 677 678 attron(COLOR_PAIR(BOT_TITLE_INFO_COLOR)); 679 addstr(fileinf); 680 attroff(COLOR_PAIR(BOT_TITLE_INFO_COLOR)); 681 } 682 683 char * 684 get_file_info(char *buf, const char *filepath) 685 { 686 struct stat statbuf; 687 struct passwd *usr; 688 struct tm *tm; 689 struct group *grp; 690 char mods[11], datestr[256], modfill = '-'; 691 char hrbytes[200]; 692 693 if ((stat(filepath, &statbuf)) != 0) { 694 switch (errno) { 695 case EACCES: 696 buf = "No permission."; 697 break; 698 default: 699 buf = "Retrieving filestats failed."; 700 break; 701 } 702 return buf; 703 } 704 705 if ((usr = getpwuid(statbuf.st_uid)) == NULL) { 706 buf = "Retrieving username failed."; 707 return buf; 708 } 709 if ((grp = getgrgid(statbuf.st_gid)) == NULL) { 710 buf = "Retrieving groupname failed."; 711 return buf; 712 } 713 714 mods[0] = S_ISDIR(statbuf.st_mode) ? 'd' : modfill; 715 mods[1] = statbuf.st_mode & S_IRUSR ? 'r' : modfill; 716 mods[2] = statbuf.st_mode & S_IWUSR ? 'w' : modfill; 717 mods[3] = statbuf.st_mode & S_IXUSR ? 'x' : modfill; 718 mods[4] = statbuf.st_mode & S_IRGRP ? 'r' : modfill; 719 mods[5] = statbuf.st_mode & S_IWGRP ? 'w' : modfill; 720 mods[6] = statbuf.st_mode & S_IXGRP ? 'x' : modfill; 721 mods[7] = statbuf.st_mode & S_IROTH ? 'r' : modfill; 722 mods[8] = statbuf.st_mode & S_IWOTH ? 'w' : modfill; 723 mods[9] = statbuf.st_mode & S_IXOTH ? 'x' : modfill; 724 mods[10] = '\0'; 725 726 tm = localtime(&statbuf.st_mtime); 727 strftime(datestr, sizeof(datestr), nl_langinfo(D_T_FMT), tm); 728 729 sprintf(buf, "%10.10s %s %s %s %s", 730 mods, 731 usr->pw_name, 732 grp->gr_name, 733 human_readable_bytes(hrbytes, (intmax_t) statbuf.st_size), 734 datestr); 735 736 return buf; 737 } 738 739 void 740 print_content(void) 741 { 742 FILE *fp = NULL; 743 size_t size = childwin.maxx; 744 char str[size+1], buf[PATH_MAX]; 745 int y = 0, x = 0; 746 747 werase(childwin.window); 748 free_dirwin(&childwin); 749 750 if ((fp = fopen(get_fullpath(buf, &curwin, curwin.highlight), "r")) == NULL) { 751 switch (errno) { 752 case EACCES: 753 set_win_message(&childwin, "No permission."); 754 return; 755 default: 756 fatal("Error opening file \"%s\"\n", buf); 757 } 758 } 759 760 childwin.holdupdate = TRUE; 761 762 while (fgets(str, size, fp) != NULL && y <= childwin.maxy) { 763 mvwaddstr(childwin.window, y, x, str); 764 y++; 765 } 766 767 fclose(fp); 768 wrefresh(childwin.window); 769 } 770 771 void 772 print_error(size_t size, const char *fmt, ...) 773 { 774 va_list ap; 775 char msg[size]; 776 777 va_start(ap, fmt); 778 vsnprintf(msg, size, fmt, ap); 779 va_end(ap); 780 781 move(maxy-1, 0); 782 clrtoeol(); 783 addstr(msg); 784 print_bot = FALSE; 785 } 786 787 void 788 show_file_mime(void) 789 { 790 int appsize = 256; 791 char mimebuf[MIME_MAX], appbuf[appsize], buf[MIME_MAX+appsize]; 792 793 if (get_mime(mimebuf, MIME_MAX, curwin.winfiles[curwin.highlight].d_name) != 0) 794 cpstr(mimebuf, "Can't retrieve mime."); 795 796 if (get_mime_default(appbuf, appsize, mimebuf) != 0) 797 cpstr(appbuf, "Can't retrieve default for mime."); 798 799 snprintf(buf, MIME_MAX+appsize, "%s: %s", mimebuf, appbuf); 800 801 move(1, 1); 802 clrtoeol(); 803 addstr(buf); 804 } 805 806 void 807 combo_key(int keypress) 808 { 809 int c; 810 811 move(maxy-1, maxx-1); 812 clrtoeol(); 813 addch(keypress); 814 815 halfdelay(10); 816 817 while ((c = getch()) != ERR) { 818 switch (keypress) { 819 case KEY_COMBO_GO: 820 combo_go(c); 821 break; 822 case KEY_COMBO_INF: 823 combo_inf(c); 824 break; 825 case KEY_COMBO_OPEN: 826 combo_open(c); 827 break; 828 case KEY_COMBO_MAKE: 829 combo_make(c); 830 break; 831 default: 832 break; 833 } 834 break; 835 } 836 837 cbreak(); 838 move(maxy-1, maxx-1); 839 clrtoeol(); 840 } 841 842 void 843 combo_go(int key) 844 { 845 char pathbuf[PATH_MAX]; 846 847 switch (key) { 848 case KEY_COMBO_GO_TOP: 849 move_top(&curwin); 850 update_child_win(); 851 break; 852 case KEY_COMBO_GO_HOME: 853 change_dir(userhome, OTHER, FALSE); 854 break; 855 case KEY_COMBO_GO_ACCESS: 856 change_dir(replace_home(pathbuf, LN_ACCESS_DIR), OTHER, FALSE); 857 break; 858 default: 859 break; 860 } 861 } 862 863 void 864 combo_inf(int key) 865 { 866 switch (key) { 867 case KEY_COMBO_INF_OPEN: 868 show_file_mime(); 869 break; 870 default: 871 break; 872 } 873 } 874 875 void 876 combo_open(int key) 877 { 878 char chdname[PATH_MAX]; 879 880 switch (key) { 881 case KEY_COMBO_OPEN_NOHUP_XDG: 882 if (is_dir(&curwin, curwin.highlight)) 883 change_dir(get_fullpath(chdname, &curwin, curwin.highlight), RIGHT, FALSE); 884 else if (S_ISREG(get_st_mode(&curwin, curwin.highlight))) 885 open_nohup_xdg(); 886 break; 887 case KEY_COMBO_OPEN_EXEC: 888 if (is_dir(&curwin, curwin.highlight)) 889 change_dir(get_fullpath(chdname, &curwin, curwin.highlight), RIGHT, FALSE); 890 else if (S_ISREG(get_st_mode(&curwin, curwin.highlight))) 891 open_child(TRUE); 892 break; 893 default: 894 break; 895 } 896 } 897 898 void 899 combo_make(int key) 900 { 901 switch (key) { 902 case KEY_COMBO_MAKE_FILE: 903 make_file(); 904 set_win_files(&curwin); 905 update_child_win(); 906 break; 907 case KEY_COMBO_MAKE_DIR: 908 make_dir(); 909 set_win_files(&curwin); 910 update_child_win(); 911 break; 912 case KEY_COMBO_MAKE_MOD: 913 make_mod(); 914 break; 915 case KEY_COMBO_MAKE_CHOWN: 916 make_chown(); 917 break; 918 case KEY_COMBO_MAKE_ACCESS: 919 make_access(); 920 break; 921 case KEY_COMBO_MAKE_OPEN_DEFAULT: 922 make_open_default(); 923 break; 924 default: 925 break; 926 } 927 } 928 929 void 930 change_dir(const char *chdname, Direction direction, bool abspath) 931 { 932 if (chdir(chdname) != 0) 933 return; 934 935 if (!abspath) 936 cpstr(curwin.path, chdname); 937 else if (getcwd(curwin.path, PATH_MAX) == NULL) 938 fatal("getcwd() error"); 939 940 switch (direction) { 941 case RIGHT: 942 curwin.highlight = 0; 943 break; 944 case LEFT: 945 curwin.highlight = parwin.highlight; 946 break; 947 default: 948 curwin.highlight = 0; 949 break; 950 951 } 952 953 set_win_files(&curwin); 954 955 get_dirname(parwin.path, curwin.path); 956 set_win_files(&parwin); 957 958 update_child_win(); 959 } 960 961 void 962 change_parent_dir(Direction direction) 963 { 964 char pp[PATH_MAX]; 965 966 switch (direction) { 967 case UP: 968 move_up(&parwin); 969 break; 970 case DOWN: 971 move_down(&parwin); 972 break; 973 default: 974 return; 975 } 976 977 parwin.usehighlight = TRUE; 978 curwin.highlight = 0; 979 change_dir(get_fullpath(pp, &parwin, parwin.highlight), direction, FALSE); 980 } 981 982 void 983 open_child(bool exec) 984 { 985 sigset_t set; 986 char mime[MIME_MAX], mimedefault[MIME_APP_MAX], pathbuf[PATH_MAX]; 987 bool istext; 988 989 if (curwin.message != NULL) 990 return; 991 992 if (!exec) { 993 if (get_mime(mime, MIME_MAX, curwin.winfiles[curwin.highlight].d_name) != 0) { 994 move(1, 1); 995 clrtoeol(); 996 printw("Can\'t open %s", curwin.winfiles[curwin.highlight].d_name); 997 return; 998 } 999 1000 istext = strncmp(mime, "text/", 5) == 0; 1001 1002 if (!istext && get_mime_default(mimedefault, MIME_APP_MAX, mime) != 0) { 1003 move(1, 1); 1004 clrtoeol(); 1005 printw("Can\'t open for mime %s", mime); 1006 return; 1007 } 1008 } 1009 1010 endwin(); 1011 1012 if (sigemptyset (&set) == -1) 1013 fatal("Sigemptyset failed."); 1014 if (sigaddset(&set, SIGWINCH) == -1) 1015 fatal("Sigaddset failed."); 1016 if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) 1017 fatal("Blocking sigprocmask failed."); 1018 1019 if (exec) 1020 run_command(PATH_MAX + 4, "\"./%s\"", curwin.winfiles[curwin.highlight].d_name); 1021 else 1022 run_command(PATH_MAX + 12, "%s \"%s\"", istext ? editor : "xdg-open", 1023 get_fullpath(pathbuf, &curwin, curwin.highlight)); 1024 1025 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) 1026 fatal("Unblocking sigprocmask failed."); 1027 1028 erase(); 1029 noecho(); 1030 cbreak(); 1031 1032 refresh(); 1033 wrefresh(parwin.window); 1034 wrefresh(curwin.window); 1035 wrefresh(childwin.window); 1036 update_child_win(); 1037 } 1038 1039 void 1040 open_nohup_xdg(void) 1041 { 1042 char *cmdfmt = "nohup xdg-open \"%s\" > /dev/null 2>&1 &"; 1043 size_t size = PATH_MAX + strlen(cmdfmt); 1044 1045 run_command(size, cmdfmt, curwin.winfiles[curwin.highlight].d_name); 1046 } 1047 1048 void 1049 search(void) 1050 { 1051 int c, y, x; 1052 1053 clear_search(); 1054 1055 move(maxy-1, 0); 1056 clrtoeol(); 1057 1058 attron(COLOR_PAIR(PROMPT_COLOR)); 1059 addstr("Search name? "); 1060 attroff(COLOR_PAIR(PROMPT_COLOR)); 1061 1062 echo(); 1063 curs_set(1); 1064 1065 getyx(stdscr, y, x); 1066 1067 while ((c = mvwgetch(stdscr, y, x)) != 10) { 1068 switch (c) { 1069 case KEY_BACKSPACE: 1070 if (searchc > 0) { 1071 searchq[--(searchc)] = '\0'; 1072 move(y, --x); 1073 clrtoeol(); 1074 } 1075 break; 1076 default: 1077 if (searchc < SEARCHLEN) { 1078 searchq[(searchc)++] = c; 1079 move(y, ++x); 1080 } 1081 break; 1082 } 1083 print_win(&curwin); 1084 } 1085 noecho(); 1086 curs_set(0); 1087 } 1088 1089 void 1090 move_top(DirWin *dirwin) 1091 { 1092 dirwin->highlight = 0; 1093 } 1094 1095 void 1096 move_bot(DirWin *dirwin) 1097 { 1098 dirwin->highlight = MAX(dirwin->filecount-1, 0); 1099 } 1100 1101 void 1102 move_page_up(DirWin *dirwin) 1103 { 1104 dirwin->highlight = MAX(dirwin->highlight - dirwin->maxy/2, 0); 1105 } 1106 1107 void 1108 move_page_down(DirWin *dirwin) 1109 { 1110 dirwin->highlight = MIN(dirwin->highlight + dirwin->maxy/2, 1111 MAX(dirwin->filecount-1, 0)); 1112 } 1113 1114 void 1115 move_up(DirWin *dirwin) 1116 { 1117 if (dirwin->highlight > 0) 1118 dirwin->highlight--; 1119 } 1120 1121 void 1122 move_down(DirWin *dirwin) 1123 { 1124 if (dirwin->highlight < dirwin->filecount-1) 1125 dirwin->highlight++; 1126 } 1127 1128 void 1129 next_search(void) 1130 { 1131 if (searchc == 0) 1132 return; 1133 1134 for (int i = curwin.highlight; i < MAX(curwin.filecount-1, 0); i++) { 1135 if ((strstr(curwin.winfiles[i+1].d_name, searchq) != NULL)) { 1136 curwin.highlight = i+1; 1137 return; 1138 } 1139 } 1140 } 1141 1142 void 1143 prev_search(void) 1144 { 1145 if (searchc == 0) 1146 return; 1147 1148 for (int i = curwin.highlight; i > 0; i--) { 1149 if ((strstr(curwin.winfiles[i-1].d_name, searchq) != NULL)) { 1150 curwin.highlight = i-1; 1151 return; 1152 } 1153 } 1154 } 1155 1156 void 1157 free_dirwin(DirWin *dirwin) 1158 { 1159 if (dirwin->winfiles != NULL) 1160 free(dirwin->winfiles); 1161 dirwin->filecount = 0; 1162 dirwin->winfiles = NULL; 1163 dirwin->message = NULL; 1164 } 1165 1166 void 1167 clean(void) 1168 { 1169 wclear(curwin.window); 1170 wclear(parwin.window); 1171 wclear(childwin.window); 1172 1173 free(username); 1174 free(userhome); 1175 1176 clear(); 1177 1178 delwin(parwin.window); 1179 delwin(curwin.window); 1180 delwin(childwin.window); 1181 delwin(stdscr); 1182 1183 free_dirwin(&curwin); 1184 free_dirwin(&parwin); 1185 free_dirwin(&childwin); 1186 1187 clear_selected(); 1188 1189 endwin(); 1190 } 1191 1192 void 1193 fatal(const char *fmt, ...) 1194 { 1195 va_list ap; 1196 1197 va_start(ap, fmt); 1198 vfprintf(stderr, fmt, ap); 1199 va_end(ap); 1200 1201 clean(); 1202 1203 exit(EXIT_FAILURE); 1204 } 1205 1206 bool 1207 is_dir(DirWin *dirwin, size_t index) 1208 { 1209 if (dirwin->filecount <= 0) 1210 return FALSE; 1211 1212 if (dirwin->winfiles[index].d_type == DT_DIR) 1213 return TRUE; 1214 1215 return S_ISDIR(get_st_mode(dirwin, index)); 1216 } 1217 1218 mode_t 1219 get_st_mode(DirWin *dirwin, size_t index) 1220 { 1221 struct stat statbuf; 1222 char linkpath[PATH_MAX], abspath[PATH_MAX]; 1223 1224 get_fullpath(linkpath, dirwin, index); 1225 if (lstat(realpath(linkpath, abspath), &statbuf) >= 0) 1226 return statbuf.st_mode; 1227 1228 return -1; 1229 } 1230 1231 char * 1232 human_readable_bytes(char *buf, intmax_t bytes) 1233 { 1234 double dblBytes = bytes; 1235 int power = SIZE_DECIMAL_FORMAT ? 1000 : 1024; 1236 char *suffix[] = {"B", "KB", "MB", "GB", "TB"}; 1237 size_t length = arrlen(suffix); 1238 size_t i = 0; 1239 1240 if (bytes > power) 1241 for (i = 0; (bytes / power) > 0 && i < length-1; i++, bytes /= power) 1242 dblBytes = bytes / (double) power; 1243 1244 sprintf(buf, "%.02lf%s", dblBytes, suffix[i]); 1245 1246 return buf; 1247 } 1248 1249 char * 1250 prompt_answer(char *buf, size_t size, const char *question) 1251 { 1252 move(maxy-1, 0); 1253 clrtoeol(); 1254 1255 attron(COLOR_PAIR(PROMPT_COLOR)); 1256 addstr(question); 1257 attroff(COLOR_PAIR(PROMPT_COLOR)); 1258 1259 echo(); 1260 curs_set(1); 1261 getnstr(buf, size); 1262 noecho(); 1263 curs_set(0); 1264 1265 return buf; 1266 } 1267 1268 bool 1269 prompt_confirm(size_t size, const char *fmt, ...) 1270 { 1271 char response[1], question[size]; 1272 va_list ap; 1273 1274 va_start(ap, fmt); 1275 vsnprintf(question, size, fmt, ap); 1276 va_end(ap); 1277 1278 prompt_answer(response, 1, question); 1279 1280 return strcasecmp(response, "y") == 0; 1281 } 1282 1283 int 1284 compare_file(const void *a, const void *b) 1285 { 1286 int typecompare; 1287 const WinFile *ma = a; 1288 const WinFile *mb = b; 1289 1290 if ((typecompare = ma->d_type - mb->d_type) == 0) 1291 return strcmp(ma->d_name, mb->d_name); 1292 1293 return typecompare; 1294 } 1295 1296 int 1297 get_mime(char *buf, size_t bufsize, const char *path) 1298 { 1299 char *cmdfmt = "xdg-mime query filetype \"%s\""; 1300 size_t size = PATH_MAX + strlen(cmdfmt); 1301 char cmd[size]; 1302 1303 snprintf(cmd, size, cmdfmt, path); 1304 1305 return read_command(buf, bufsize, cmd); 1306 } 1307 1308 int 1309 get_mime_default(char *buf, size_t bufsize, const char *mime) 1310 { 1311 char *cmdfmt = "xdg-mime query default \"%s\""; 1312 size_t cmdsize = MIME_MAX + strlen(cmdfmt); 1313 char cmd[cmdsize]; 1314 1315 snprintf(cmd, cmdsize, cmdfmt, mime); 1316 1317 return read_command(buf, bufsize, cmd); 1318 } 1319 1320 int 1321 read_command(char *buf, size_t bufsize, const char *cmd) 1322 { 1323 FILE *file; 1324 1325 if ((file = popen(cmd, "r")) == NULL) { 1326 buf = NULL; 1327 return 1; 1328 } 1329 1330 if (fgets(buf, bufsize, file) == NULL) { 1331 buf = NULL; 1332 pclose(file); 1333 return 2; 1334 } 1335 1336 buf[strlen(buf)-1] = '\0'; 1337 1338 pclose(file); 1339 1340 return 0; 1341 } 1342 1343 void 1344 run_command(size_t size, const char *fmt, ...) 1345 { 1346 va_list ap; 1347 char cmd[size]; 1348 1349 va_start(ap, fmt); 1350 vsnprintf(cmd, size, fmt, ap); 1351 va_end(ap); 1352 1353 system(cmd); 1354 } 1355 1356 void 1357 run_sudo_command(size_t size, const char *fmt, ...) 1358 { 1359 va_list ap; 1360 char cmd[size], *msg; 1361 sigset_t set; 1362 1363 if (!USE_SUDO_COMMANDS) { 1364 msg = "Requires sudo command but USE_SUDO_COMMANDS is disabled."; 1365 print_error(strlen(msg), msg); 1366 return; 1367 } 1368 1369 endwin(); 1370 1371 if (sigemptyset (&set) == -1) 1372 fatal("Sigemptyset failed."); 1373 if (sigaddset(&set, SIGWINCH) == -1) 1374 fatal("Sigaddset failed."); 1375 if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) 1376 fatal("Blocking sigprocmask failed."); 1377 1378 va_start(ap, fmt); 1379 vsnprintf(cmd, size, fmt, ap); 1380 va_end(ap); 1381 1382 system(cmd); 1383 1384 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) 1385 fatal("Unblocking sigprocmask failed."); 1386 1387 erase(); 1388 refresh(); 1389 wrefresh(parwin.window); 1390 wrefresh(curwin.window); 1391 wrefresh(childwin.window); 1392 } 1393 1394 int 1395 make_dir(void) 1396 { 1397 char name[PATH_MAX]; 1398 1399 prompt_answer(name, PATH_MAX, "Name of directory? "); 1400 return mkdir(name, 0755); 1401 } 1402 1403 int 1404 make_file(void) 1405 { 1406 FILE *fptr; 1407 char name[PATH_MAX]; 1408 1409 prompt_answer(name, PATH_MAX, "Name of file? "); 1410 1411 if (strlen(name) > 0) { 1412 if ((fptr = fopen(name, "w")) == NULL) 1413 fatal("Error opening file \"%s\"\n", name); 1414 fclose(fptr); 1415 } 1416 return 0; 1417 } 1418 1419 int 1420 rm_file(const char *fname) 1421 { 1422 char *msg, *rmdirfmt = "rm -rf \"%s\"", *pfmt = "Remove %s? (y/N) "; 1423 int res = 0; 1424 size_t cmdsize = PATH_MAX + strlen(rmdirfmt), psize = strlen(pfmt) + strlen(fname); 1425 1426 if (prompt_confirm(psize, pfmt, fname)) { 1427 if (is_dir(&curwin, curwin.highlight)) 1428 run_command(cmdsize, rmdirfmt, fname); 1429 else 1430 res = remove(fname); 1431 curwin.highlight = curwin.highlight > 0 ? curwin.highlight -1 : 0; 1432 } 1433 1434 if (res != 0) { 1435 switch (errno) { 1436 case EACCES: 1437 msg = "No permission."; 1438 break; 1439 case EEXIST: 1440 case ENOTEMPTY: 1441 msg = "Directory is not empty."; 1442 break; 1443 default: 1444 msg = "Could not remove file."; 1445 break; 1446 } 1447 print_error(strlen(msg), msg); 1448 } 1449 1450 return res; 1451 } 1452 1453 int 1454 rename_file(const char *fname) 1455 { 1456 char name[PATH_MAX]; 1457 1458 prompt_answer(name, PATH_MAX, "New name? "); 1459 1460 if (strlen(name) > 0) 1461 return rename(fname, name); 1462 1463 return 0; 1464 } 1465 1466 int 1467 make_mod(void) 1468 { 1469 char name[3]; 1470 bool isvalid; 1471 1472 prompt_answer(name, 3, "File mods (numeric)? "); 1473 1474 if (strlen(name) == 3) { 1475 isvalid = TRUE; 1476 for (int i = 0; i < 3; i++) { 1477 if (!isdigit(name[i])) 1478 isvalid = FALSE; 1479 } 1480 if (isvalid) 1481 chmod(curwin.winfiles[curwin.highlight].d_name, strtol(name, NULL, 8)); 1482 else 1483 return -1; 1484 } 1485 1486 return 0; 1487 } 1488 1489 int 1490 make_chown(void) 1491 { 1492 struct passwd *usr; 1493 struct group *grp; 1494 long len = sysconf(_SC_LOGIN_NAME_MAX); 1495 char owner[len], group[len], *err; 1496 1497 prompt_answer(owner, len, "Owner name? "); 1498 1499 if ((usr = getpwnam(owner)) == NULL) { 1500 err = "No results found for owner %s."; 1501 print_error(strlen(err) + len, err, owner); 1502 return -1; 1503 } 1504 1505 prompt_answer(group, len, "Group name? "); 1506 1507 if ((grp = getgrnam(group)) == NULL) { 1508 err = "No results found for group %s."; 1509 print_error(strlen(err) + len, err, group); 1510 return -1; 1511 } 1512 1513 if ((chown(curwin.winfiles[curwin.highlight].d_name, usr->pw_uid, grp->gr_gid)) != 0) { 1514 switch (errno) { 1515 case EACCES: 1516 case EPERM: 1517 sudo_chown(owner, group, len); 1518 break; 1519 default: 1520 err = "Error during chown: %d."; 1521 print_error(strlen(err), err, errno); 1522 return errno; 1523 } 1524 } 1525 return 0; 1526 } 1527 1528 int 1529 sudo_chown(char *owner, char *group, long namelen) 1530 { 1531 size_t cmdsize; 1532 char pathbuf[PATH_MAX], *cmdfmt = "sudo chown %s:%s %s"; 1533 1534 cmdsize = namelen*2 + PATH_MAX + strlen(cmdfmt); 1535 run_sudo_command(cmdsize, cmdfmt, owner, group, get_fullpath(pathbuf, &curwin, curwin.highlight)); 1536 1537 return 0; 1538 } 1539 1540 void 1541 make_access(void) 1542 { 1543 char pathbuf[PATH_MAX], *cmdfmt = "ln -s \"%s\" \"%s\"", *pfmt = "Make access \"%s\"? (y/N) "; 1544 size_t cmdsize = PATH_MAX + strlen(cmdfmt), psize = strlen(pfmt) + PATH_MAX; 1545 1546 if (prompt_confirm(psize, pfmt, curwin.winfiles[curwin.highlight].d_name)) 1547 run_command(cmdsize, cmdfmt, get_fullpath(pathbuf, &curwin, curwin.highlight), LN_ACCESS_DIR); 1548 } 1549 1550 void 1551 make_open_default(void) 1552 { 1553 int appsize = 256, qsize = MIME_MAX+25; 1554 char mime[MIME_MAX], question[qsize], app[appsize]; 1555 1556 if (get_mime(mime, MIME_MAX, curwin.winfiles[curwin.highlight].d_name) != 0) 1557 cpstr(mime, "Can't retrieve mime."); 1558 1559 snprintf(question, qsize, "Application for mime %s?", mime); 1560 1561 prompt_answer(app, appsize, question); 1562 1563 if (strlen(app) > 0) 1564 make_mime_default(mime, app); 1565 } 1566 1567 void 1568 make_mime_default(const char *mime, const char *app) 1569 { 1570 char *cmdfmt = "xdg-mime default \"%s\" \"%s\""; 1571 size_t cmdsize = MIME_MAX + 256 + strlen(cmdfmt); 1572 1573 run_command(cmdsize, cmdfmt, app, mime); 1574 } 1575 1576 void 1577 exe_selection(SelAction action, const char *askn) 1578 { 1579 char *pfmt = "%s selection (%d files) ? (y/N) "; 1580 size_t cmdsize = PATH_MAX*2 + 20; 1581 1582 if (selected == NULL || selc == 0) 1583 return; 1584 1585 if (askn != NULL && !prompt_confirm(strlen(pfmt) + strlen(askn) + 5, pfmt, askn, selc)) 1586 return; 1587 1588 switch (action) { 1589 case COPY: 1590 for (size_t i = 0; i <selc; i++) 1591 run_command(cmdsize, "cp -rf \"%s\" \"%s\"", selected[i], curwin.path); 1592 break; 1593 case REMOVE: 1594 for (size_t i = 0; i <selc; i++) 1595 run_command(cmdsize, "rm -rf \"%s\"", selected[i]); 1596 break; 1597 case MOVE: 1598 for (size_t i = 0; i <selc; i++) 1599 run_command(cmdsize, "mv \"%s\" \"%s\"", selected[i], curwin.path); 1600 break; 1601 default: 1602 break; 1603 } 1604 1605 clear_selected(); 1606 curwin.highlight = 0; 1607 set_win_files(&curwin); 1608 set_win_files(&parwin); 1609 update_child_win(); 1610 } 1611 1612 void 1613 select_file(const char *path) 1614 { 1615 if (selc == 0 && ((selected = (char**) malloc(sizeof(char *)))) == NULL) 1616 fatal("Fatal: failed to malloc selected.\n"); 1617 1618 if (remove_selected(path)) 1619 return; 1620 1621 if ((selected = (char**) realloc(selected, (selc+1) * sizeof(char *))) == NULL) 1622 fatal("Fatal: failed to realloc.\n"); 1623 1624 selected[selc] = strdup(path); 1625 (selc)++; 1626 } 1627 1628 void 1629 clear_selected(void) 1630 { 1631 for (size_t i = 0; i < selc; i++) 1632 free(selected[i]); 1633 1634 free(selected); 1635 selected = NULL; 1636 selc = 0; 1637 } 1638 1639 void 1640 clear_search(void) 1641 { 1642 for (int i = 0; i < SEARCHLEN; i++) 1643 searchq[i] = '\0'; 1644 searchc = 0; 1645 } 1646 1647 char * 1648 cpstr(char *dest, const char *src) 1649 { 1650 size_t cplen = strlen(src); 1651 memcpy(dest, src, cplen); 1652 dest[cplen] = '\0'; 1653 return dest; 1654 } 1655 1656 char * 1657 get_fullpath(char *buf, DirWin *dirwin, size_t index) 1658 { 1659 index = MIN(index, dirwin->filecount-1); 1660 index = MAX(index, 0); 1661 size_t len; 1662 1663 if (strcmp(dirwin->path, "/") == 0) 1664 snprintf(buf, PATH_MAX, "/%s", dirwin->winfiles[index].d_name); 1665 else { 1666 len = PATH_MAX + arrlen(dirwin->winfiles[index].d_name); 1667 snprintf(buf, len, "%s/%s", dirwin->path, dirwin->winfiles[index].d_name); 1668 } 1669 1670 return buf; 1671 } 1672 1673 char * 1674 replace_home(char *buf, const char *path) 1675 { 1676 char *envv = "$HOME"; 1677 1678 if ((strstr(path, envv) != NULL)) { 1679 cpstr(buf, userhome); 1680 strcat(buf, path + strlen(envv)); 1681 } 1682 return buf; 1683 } 1684 1685 char * 1686 get_dirname(char *buf, const char *path) 1687 { 1688 cpstr(buf, path); 1689 dirname(buf); 1690 return buf; 1691 }