565 lines
15 KiB
C
565 lines
15 KiB
C
/*
|
|
|
|
File: askloc.c
|
|
|
|
Copyright (C) 1998-2009 Christophe GRENIER <grenier@cgsecurity.org>
|
|
|
|
This software is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write the Free Software Foundation, Inc., 51
|
|
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_NCURSES
|
|
#include <stdio.h>
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef HAVE_TIME_H
|
|
#include <time.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_CYGWIN_H
|
|
#include <sys/cygwin.h>
|
|
#endif
|
|
#ifdef HAVE_DIRENT_H
|
|
#include <dirent.h>
|
|
#endif
|
|
#include "types.h"
|
|
#include "common.h"
|
|
#include "intrf.h"
|
|
#include "intrfn.h"
|
|
#include "list.h"
|
|
#include "dir.h"
|
|
#include "askloc.h"
|
|
#include "log.h"
|
|
|
|
extern const char *monstr[];
|
|
|
|
#define INTER_DIR (LINES-25+16)
|
|
#define Y_DIR 8
|
|
|
|
#ifdef __MINGW32__
|
|
#define SPATH_SEP "\\"
|
|
#define PATH_SEP '\\'
|
|
#else
|
|
#define SPATH_SEP "/"
|
|
#define PATH_SEP '/'
|
|
#endif
|
|
#if defined(__CYGWIN__)
|
|
/* /cygdrive/c/ */
|
|
#define CYGDRIVE_LEN 9
|
|
#endif
|
|
|
|
#define ASK_LOCATION_WAITKEY 0
|
|
#define ASK_LOCATION_UPDATE 1
|
|
#define ASK_LOCATION_NEWDIR 2
|
|
#define ASK_LOCATION_QUIT 3
|
|
|
|
static void set_parent_directory(char *dst_directory);
|
|
static void dir_aff_entry(WINDOW *window, file_info_t *file_info);
|
|
static int aff_txt(int line, WINDOW *window, const char *_format, ...) __attribute__ ((format (printf, 3, 4)));
|
|
|
|
#if defined(DJGPP) || defined(__OS2__)
|
|
void get_dos_drive_list(struct td_list_head *list);
|
|
|
|
void get_dos_drive_list(struct td_list_head *list)
|
|
{
|
|
int i;
|
|
for(i='a';i<='z';i++)
|
|
{
|
|
file_info_t *new_drive;
|
|
new_drive=(file_info_t*)MALLOC(sizeof(*new_drive));
|
|
new_drive->name[0]=i;
|
|
new_drive->name[1]=':';
|
|
new_drive->name[2]=PATH_SEP;
|
|
new_drive->name[3]='\0';
|
|
new_drive->stat.st_mode=LINUX_S_IFDIR|LINUX_S_IRWXUGO;
|
|
td_list_add_tail(&new_drive->list, list);
|
|
}
|
|
}
|
|
#endif
|
|
static void set_parent_directory(char *dst_directory)
|
|
{
|
|
int i;
|
|
int last_sep=-1;
|
|
for(i=0;dst_directory[i]!='\0';i++)
|
|
if(dst_directory[i]==PATH_SEP)
|
|
last_sep=i;
|
|
#ifdef __CYGWIN__
|
|
if(memcmp(dst_directory, "/cygdrive", 9)==0)
|
|
{
|
|
if(last_sep > CYGDRIVE_LEN)
|
|
dst_directory[last_sep]='\0';
|
|
else
|
|
dst_directory[CYGDRIVE_LEN]='\0';
|
|
}
|
|
else if(last_sep>0)
|
|
dst_directory[last_sep]='\0';
|
|
else if(last_sep==0 && dst_directory[1]=='\0')
|
|
strcpy(dst_directory, "/cygdrive");
|
|
else
|
|
{
|
|
dst_directory[0]=PATH_SEP;
|
|
dst_directory[1]='\0';
|
|
}
|
|
#elif defined(DJGPP) || defined(__OS2__)
|
|
if(last_sep > 2 )
|
|
dst_directory[last_sep]='\0'; /* subdirectory */
|
|
else if(last_sep == 2 && dst_directory[3]!='\0')
|
|
dst_directory[3]='\0'; /* root directory */
|
|
else
|
|
dst_directory[0]='\0'; /* drive list */
|
|
#else
|
|
if(last_sep>0)
|
|
dst_directory[last_sep]='\0';
|
|
else
|
|
{
|
|
dst_directory[0]=PATH_SEP;
|
|
dst_directory[1]='\0';
|
|
}
|
|
#endif
|
|
}
|
|
|
|
char *ask_location(const char*msg, const char *src_dir, const char *dst_org)
|
|
{
|
|
char dst_directory[4096];
|
|
char *res=NULL;
|
|
int quit;
|
|
WINDOW *window=newwin(0,0,0,0); /* full screen */
|
|
aff_copy_short(window);
|
|
if(dst_org != NULL)
|
|
strncpy(dst_directory, dst_org, sizeof(dst_directory));
|
|
else
|
|
td_getcwd(dst_directory, sizeof(dst_directory));
|
|
do
|
|
{
|
|
DIR* dir;
|
|
static file_info_t dir_list = {
|
|
.list = TD_LIST_HEAD_INIT(dir_list.list),
|
|
.name = {0}
|
|
};
|
|
wmove(window,5,0);
|
|
wclrtoeol(window); /* before addstr for BSD compatibility */
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
|
|
waddstr(window,"Directory listing in progress...");
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | COLOR_PAIR(0));
|
|
wrefresh(window);
|
|
#if defined(DJGPP) || defined(__OS2__)
|
|
if(dst_directory[0]=='\0')
|
|
{
|
|
get_dos_drive_list(&dir_list.list);
|
|
dir=NULL;
|
|
}
|
|
else
|
|
dir=opendir(dst_directory);
|
|
#else
|
|
dir=opendir(dst_directory);
|
|
#endif
|
|
if(dir==NULL)
|
|
{
|
|
log_info("opendir(%s) failed\n", dst_directory);
|
|
strncpy(dst_directory, SPATH_SEP, sizeof(dst_directory));
|
|
dir=opendir(dst_directory);
|
|
}
|
|
if(dir==NULL)
|
|
{
|
|
td_getcwd(dst_directory, sizeof(dst_directory));
|
|
dir=opendir(dst_directory);
|
|
}
|
|
if(dir==NULL)
|
|
return NULL;
|
|
{
|
|
file_info_t *file_info;
|
|
file_info=(file_info_t*)MALLOC(sizeof(*file_info));
|
|
while(1)
|
|
{
|
|
char current_file[4096];
|
|
struct dirent *dir_entrie;
|
|
dir_entrie=readdir(dir);
|
|
if(dir_entrie==NULL)
|
|
break;
|
|
/* hide filename beginning by '.' except '.' and '..' */
|
|
if(dir_entrie->d_name[0]=='.' &&
|
|
!dir_entrie->d_name[1]=='\0' &&
|
|
!(dir_entrie->d_name[1]=='.' && dir_entrie->d_name[2]=='\0'))
|
|
continue;
|
|
if(strlen(dst_directory)+1+strlen(file_info->name)+1<=sizeof(current_file)
|
|
#ifdef __CYGWIN__
|
|
&& (memcmp(dst_directory, "/cygdrive", 9)!=0 ||
|
|
(dst_directory[9]!='\0' && dst_directory[10]!='\0') ||
|
|
dir_entrie->d_name[0]!='.')
|
|
#endif
|
|
)
|
|
{
|
|
strcpy(current_file,dst_directory);
|
|
#if defined(DJGPP) || defined(__OS2__)
|
|
if(current_file[0]!='\0'&¤t_file[1]!='\0'&¤t_file[2]!='\0'&¤t_file[3]!='\0')
|
|
#else
|
|
if(current_file[1]!='\0')
|
|
#endif
|
|
strcat(current_file,SPATH_SEP);
|
|
strcat(current_file,dir_entrie->d_name);
|
|
#ifdef HAVE_LSTAT
|
|
if(lstat(current_file,&file_info->stat)==0)
|
|
#else
|
|
if(stat(current_file,&file_info->stat)==0)
|
|
#endif
|
|
{
|
|
#if defined(DJGPP) || defined(__OS2__)
|
|
/* If the C library doesn't use posix definition, st_mode need to be fixed */
|
|
if(S_ISDIR(file_info->stat.st_mode))
|
|
file_info->stat.st_mode=LINUX_S_IFDIR|LINUX_S_IRWXUGO;
|
|
else
|
|
file_info->stat.st_mode=LINUX_S_IFREG|LINUX_S_IRWXUGO;
|
|
#endif
|
|
#ifdef __CYGWIN__
|
|
/* Fix Drive list */
|
|
if(memcmp(dst_directory, "/cygdrive", 9)==0 && (dst_directory[10]=='\0' || dst_directory[11]=='\0'))
|
|
{
|
|
file_info->stat.st_mode=LINUX_S_IFDIR|LINUX_S_IRWXUGO;
|
|
file_info->stat.st_mtime=0;
|
|
file_info->stat.st_uid=0;
|
|
file_info->stat.st_gid=0;
|
|
}
|
|
#endif
|
|
strncpy(file_info->name,dir_entrie->d_name,sizeof(file_info->name));
|
|
td_list_add_sorted(&file_info->list, &dir_list.list, filesort);
|
|
file_info=(file_info_t*)MALLOC(sizeof(*file_info));
|
|
}
|
|
}
|
|
}
|
|
free(file_info);
|
|
closedir(dir);
|
|
}
|
|
if(dir_list.list.next!=&dir_list.list)
|
|
{
|
|
struct td_list_head *current_file=dir_list.list.next;
|
|
int offset=0;
|
|
int pos_num=0;
|
|
int old_LINES=LINES;
|
|
do
|
|
{
|
|
int dst_directory_ok=0;
|
|
if(old_LINES!=LINES)
|
|
{ /* Screen size has changed, reset to initial values */
|
|
current_file=dir_list.list.next;
|
|
offset=0;
|
|
pos_num=0;
|
|
old_LINES=LINES;
|
|
}
|
|
aff_copy_short(window);
|
|
wmove(window,4,0);
|
|
wprintw(window,"Keys: ");
|
|
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
|
|
waddstr(window, "Arrow");
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | COLOR_PAIR(0));
|
|
wprintw(window," keys to select another directory");
|
|
wmove(window, 5, 6);
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
|
|
waddstr(window, "C");
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | COLOR_PAIR(0));
|
|
wprintw(window, " when the destination is correct");
|
|
wmove(window, 6, 6);
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
|
|
waddstr(window, "Q");
|
|
if(has_colors())
|
|
wbkgdset(window,' ' | COLOR_PAIR(0));
|
|
waddstr(window," to quit");
|
|
{
|
|
struct td_list_head *file_walker = NULL;
|
|
int i=0;
|
|
td_list_for_each(file_walker,&dir_list.list)
|
|
{
|
|
if(i++<offset)
|
|
continue;
|
|
{
|
|
file_info_t *file_info;
|
|
file_info=td_list_entry(file_walker, file_info_t, list);
|
|
wmove(window, Y_DIR - 1 + i - offset, 0);
|
|
wclrtoeol(window); /* before addstr for BSD compatibility */
|
|
if(file_walker==current_file)
|
|
{
|
|
wattrset(window, A_REVERSE);
|
|
waddstr(window, ">");
|
|
dir_aff_entry(window,file_info);
|
|
wattroff(window, A_REVERSE);
|
|
}
|
|
else
|
|
{
|
|
wprintw(window, " ");
|
|
dir_aff_entry(window,file_info);
|
|
}
|
|
}
|
|
if(offset+INTER_DIR<=i)
|
|
break;
|
|
}
|
|
wmove(window, Y_DIR + INTER_DIR, 4);
|
|
wclrtoeol(window);
|
|
if(file_walker!=&dir_list.list && file_walker->next!=&dir_list.list)
|
|
wprintw(window, "Next");
|
|
}
|
|
aff_txt(2, window, msg, src_dir);
|
|
wmove(window,7,0);
|
|
wclrtoeol(window); /* before addstr for BSD compatibility */
|
|
if(strcmp(dst_directory,".")==0)
|
|
{
|
|
wprintw(window, "Current directory");
|
|
dst_directory_ok=1;
|
|
}
|
|
else
|
|
{
|
|
#ifdef __CYGWIN__
|
|
if(memcmp(dst_directory, "/cygdrive", 9)!=0 ||
|
|
(dst_directory[9]!='\0' && dst_directory[10]!='\0'))
|
|
{
|
|
char beautifull_dst_directory[4096];
|
|
if(cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, dst_directory, beautifull_dst_directory, sizeof(beautifull_dst_directory))==0)
|
|
wprintw(window, "Directory %s", beautifull_dst_directory);
|
|
else
|
|
wprintw(window, "Directory %s", dst_directory);
|
|
dst_directory_ok=1;
|
|
}
|
|
#elif defined(DJGPP) || defined(__OS2__)
|
|
if(strlen(dst_directory)>0)
|
|
{
|
|
wprintw(window, "Directory %s", dst_directory);
|
|
dst_directory_ok=1;
|
|
}
|
|
#else
|
|
wprintw(window, "Directory %s", dst_directory);
|
|
dst_directory_ok=1;
|
|
#endif
|
|
}
|
|
wrefresh(window);
|
|
do
|
|
{
|
|
int command=wgetch(window);
|
|
quit=ASK_LOCATION_WAITKEY;
|
|
#if defined(KEY_MOUSE) && defined(ENABLE_MOUSE)
|
|
if(command==KEY_MOUSE)
|
|
{
|
|
MEVENT event;
|
|
if(getmouse(&event) == OK)
|
|
{ /* When the user clicks left mouse button */
|
|
if((event.bstate & BUTTON1_CLICKED) || (event.bstate & BUTTON1_DOUBLE_CLICKED))
|
|
{
|
|
if(event.y >= Y_DIR && event.y < Y_DIR + INTER_DIR)
|
|
{
|
|
const int pos_num_old=pos_num;
|
|
/* Disk selection */
|
|
while(pos_num > event.y - (Y_DIR - offset) && current_file->prev!=&dir_list.list)
|
|
{
|
|
current_file=current_file->prev;
|
|
pos_num--;
|
|
}
|
|
while(pos_num < event.y - (Y_DIR - offset) && current_file->next!=&dir_list.list)
|
|
{
|
|
current_file=current_file->next;
|
|
pos_num++;
|
|
}
|
|
quit=ASK_LOCATION_UPDATE;
|
|
if(((event.bstate & BUTTON1_CLICKED) && pos_num==pos_num_old) ||
|
|
(event.bstate & BUTTON1_DOUBLE_CLICKED))
|
|
command=KEY_ENTER;
|
|
}
|
|
#if 0
|
|
else if(file_walker!=&dir_list.list && file_walker->next!=&dir_list.list)
|
|
{
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
switch(command)
|
|
{
|
|
case 'y':
|
|
case 'Y':
|
|
case 'c':
|
|
case 'C':
|
|
if(dst_directory_ok>0)
|
|
{
|
|
res=strdup(dst_directory);
|
|
quit=ASK_LOCATION_QUIT;
|
|
}
|
|
break;
|
|
case 'n':
|
|
case 'N':
|
|
case 'q':
|
|
case 'Q':
|
|
res=NULL;
|
|
quit=ASK_LOCATION_QUIT;
|
|
break;
|
|
case KEY_UP:
|
|
case '8':
|
|
if(current_file->prev!=&dir_list.list)
|
|
{
|
|
current_file=current_file->prev;
|
|
pos_num--;
|
|
quit=ASK_LOCATION_UPDATE;
|
|
}
|
|
break;
|
|
case KEY_DOWN:
|
|
case '2':
|
|
if(current_file->next!=&dir_list.list)
|
|
{
|
|
current_file=current_file->next;
|
|
pos_num++;
|
|
quit=ASK_LOCATION_UPDATE;
|
|
}
|
|
break;
|
|
case KEY_PPAGE:
|
|
{
|
|
int i;
|
|
for(i=0; i<INTER_DIR-1 && current_file->prev!=&dir_list.list; i++)
|
|
{
|
|
current_file=current_file->prev;
|
|
pos_num--;
|
|
quit=ASK_LOCATION_UPDATE;
|
|
}
|
|
}
|
|
break;
|
|
case KEY_NPAGE:
|
|
{
|
|
int i;
|
|
for(i=0; i<INTER_DIR-1 && current_file->next!=&dir_list.list; i++)
|
|
{
|
|
current_file=current_file->next;
|
|
pos_num++;
|
|
quit=ASK_LOCATION_UPDATE;
|
|
}
|
|
}
|
|
break;
|
|
case KEY_LEFT:
|
|
case '4':
|
|
set_parent_directory(dst_directory);
|
|
quit=ASK_LOCATION_NEWDIR;
|
|
break;
|
|
case KEY_RIGHT:
|
|
case '\r':
|
|
case '\n':
|
|
case '6':
|
|
case KEY_ENTER:
|
|
#ifdef PADENTER
|
|
case PADENTER:
|
|
#endif
|
|
{
|
|
file_info_t *file_info;
|
|
file_info=td_list_entry(current_file, file_info_t, list);
|
|
if(current_file!=&dir_list.list &&
|
|
(LINUX_S_ISDIR(file_info->stat.st_mode) || LINUX_S_ISLNK(file_info->stat.st_mode)))
|
|
if(current_file!=&dir_list.list)
|
|
{
|
|
if(strcmp(file_info->name,".")==0)
|
|
{
|
|
}
|
|
else if(strcmp(file_info->name,"..")==0)
|
|
{
|
|
set_parent_directory(dst_directory);
|
|
quit=ASK_LOCATION_NEWDIR;
|
|
}
|
|
else if(strlen(dst_directory)+1+strlen(file_info->name)+1<=sizeof(dst_directory))
|
|
{
|
|
#if defined(DJGPP) || defined(__OS2__)
|
|
if(dst_directory[0]!='\0'&&dst_directory[1]!='\0'&&dst_directory[2]!='\0'&&dst_directory[3]!='\0')
|
|
#else
|
|
if(dst_directory[1]!='\0')
|
|
#endif
|
|
strcat(dst_directory,SPATH_SEP);
|
|
strcat(dst_directory,file_info->name);
|
|
quit=ASK_LOCATION_NEWDIR;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
if(pos_num<offset)
|
|
offset=pos_num;
|
|
if(pos_num>=offset+INTER_DIR)
|
|
offset=pos_num-INTER_DIR+1;
|
|
} while(quit==ASK_LOCATION_WAITKEY && old_LINES==LINES);
|
|
} while(quit==ASK_LOCATION_UPDATE || old_LINES!=LINES);
|
|
delete_list_file_info(&dir_list.list);
|
|
}
|
|
else
|
|
{
|
|
set_parent_directory(dst_directory);
|
|
quit=ASK_LOCATION_NEWDIR;
|
|
}
|
|
} while(quit==ASK_LOCATION_NEWDIR);
|
|
delwin(window);
|
|
(void) clearok(stdscr, TRUE);
|
|
#ifdef HAVE_TOUCHWIN
|
|
touchwin(stdscr);
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
static void dir_aff_entry(WINDOW *window, file_info_t *file_info)
|
|
{
|
|
struct tm *tm_p;
|
|
char str[11];
|
|
char datestr[80];
|
|
if(file_info->stat.st_mtime!=0)
|
|
{
|
|
tm_p = localtime(&file_info->stat.st_mtime);
|
|
snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
|
|
tm_p->tm_mday, monstr[tm_p->tm_mon],
|
|
1900 + tm_p->tm_year, tm_p->tm_hour,
|
|
tm_p->tm_min);
|
|
/* May have to use %d instead of %e */
|
|
} else {
|
|
strncpy(datestr, " ",sizeof(datestr));
|
|
}
|
|
mode_string(file_info->stat.st_mode,str);
|
|
wprintw(window, "%s %5u %5u ",
|
|
str, (unsigned int)file_info->stat.st_uid, (unsigned int)file_info->stat.st_gid);
|
|
wprintw(window, "%7llu", (long long unsigned int)file_info->stat.st_size);
|
|
/* screen may overlap due to long filename */
|
|
wprintw(window, " %s %s", datestr, file_info->name);
|
|
}
|
|
|
|
static int aff_txt(int line, WINDOW *window, const char *_format, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap,_format);
|
|
line=vaff_txt(line, window, _format, ap);
|
|
va_end(ap);
|
|
return line;
|
|
}
|
|
|
|
#endif
|