|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include "ascii_ctype.h"
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include "HttpDir.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
#include "LsCache.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "DirColors.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static bool token_eq(const char *buf,int len,const char *token)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int token_len=strlen(token);
|
|
Packit |
8f70b4 |
if(len
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
return !strncasecmp(buf,token,token_len)
|
|
Packit |
8f70b4 |
&& (token_len==len || !is_ascii_alnum(buf[token_len]));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static bool find_value(const char *scan,const char *more,const char *name,xstring& store)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(is_ascii_space(*scan))
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
if(scan>=more)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!is_ascii_alnum(*scan))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool match=token_eq(scan,more-scan,name);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
while(is_ascii_alnum(*scan))
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
if(scan>=more)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(*scan!='=')
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
char quote=0;
|
|
Packit |
8f70b4 |
if(*scan=='"' || *scan=='\'')
|
|
Packit |
8f70b4 |
quote=*scan++;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(match)
|
|
Packit |
8f70b4 |
store.set("");
|
|
Packit |
8f70b4 |
while(scan
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(match)
|
|
Packit |
8f70b4 |
store.append(*scan);
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(match)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(scan>=more)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(quote)
|
|
Packit |
8f70b4 |
scan++; // skip closing quotation mark.
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if 0 // unused
|
|
Packit |
8f70b4 |
static
|
|
Packit |
8f70b4 |
const char *strncasestr(const char *buf,int len,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int str_len=strlen(str);
|
|
Packit |
8f70b4 |
while(len>=str_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strncasecmp(buf,str,str_len))
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
buf++;
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static
|
|
Packit |
8f70b4 |
const char *find_eol(const char *buf,int len,bool eof,int *eol_size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *real_eol=find_char(buf,len,'\n');
|
|
Packit |
8f70b4 |
// check if the tag after eol is or
|
|
Packit |
8f70b4 |
while(real_eol)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *scan=real_eol+1;
|
|
Packit |
8f70b4 |
while(scan
|
|
Packit |
8f70b4 |
scan++; // skip space
|
|
Packit |
8f70b4 |
if(scan
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(scan+5>buf+len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!eof)
|
|
Packit |
8f70b4 |
real_eol=0;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(strncasecmp(scan,"
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
real_eol=find_char(scan,len-(scan-buf),'\n');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *less=find_char(buf,len,'<');;
|
|
Packit |
8f70b4 |
const char *more=0;
|
|
Packit |
8f70b4 |
if(less)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int rest=len-(less+1-buf);
|
|
Packit |
8f70b4 |
more=find_char(less+1,rest,'>');
|
|
Packit |
8f70b4 |
if(more
|
|
Packit |
8f70b4 |
&& !token_eq(less+1,rest,"br")
|
|
Packit |
8f70b4 |
&& !token_eq(less+1,rest,"/tr")
|
|
Packit |
8f70b4 |
&& !token_eq(less+1,rest,"tr"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// if the tag is finished and not BR nor /TR nor TR, ignore it.
|
|
Packit |
8f70b4 |
less=0;
|
|
Packit |
8f70b4 |
more=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// is real_eol past the tag?
|
|
Packit |
8f70b4 |
if(real_eol && less && real_eol>less)
|
|
Packit |
8f70b4 |
real_eol=0; // then ignore it.
|
|
Packit |
8f70b4 |
// real_eol not found?
|
|
Packit |
8f70b4 |
if(!real_eol)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// BR or /TR found?
|
|
Packit |
8f70b4 |
if(less && more)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*eol_size=more-less+1;
|
|
Packit |
8f70b4 |
return less;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*eol_size=0;
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
return buf+len;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*eol_size=1;
|
|
Packit |
8f70b4 |
if(real_eol>buf && real_eol[-1]=='\r')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
real_eol--;
|
|
Packit |
8f70b4 |
(*eol_size)++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return real_eol;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* This function replaces & < > " to appropriate characters */
|
|
Packit |
8f70b4 |
static void decode_amps(xstring& s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static const struct pair
|
|
Packit |
8f70b4 |
{ char str[7]; char ch; }
|
|
Packit |
8f70b4 |
table[]={
|
|
Packit |
8f70b4 |
{ "&", '&' },
|
|
Packit |
8f70b4 |
{ "<", '<' },
|
|
Packit |
8f70b4 |
{ ">", '>' },
|
|
Packit |
8f70b4 |
{ """, '"' },
|
|
Packit |
8f70b4 |
{ "", 0 }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
const struct pair *scan;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(const char *a=s; a; a=strchr(a,'&'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(scan=table; scan->ch; scan++)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=strlen(scan->str);
|
|
Packit |
8f70b4 |
if(!strncmp(a,scan->str,len))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
s.set_substr(a-s,len,&scan->ch,1);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
a++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class file_info
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
long long size;
|
|
Packit |
8f70b4 |
int year,month,day,hour,minute,second;
|
|
Packit |
8f70b4 |
xstring_c sym_link;
|
|
Packit |
8f70b4 |
bool is_sym_link;
|
|
Packit |
8f70b4 |
bool is_directory;
|
|
Packit |
8f70b4 |
char month_name[32];
|
|
Packit |
8f70b4 |
char size_str[32];
|
|
Packit |
8f70b4 |
char perms[12];
|
|
Packit |
8f70b4 |
char user[32];
|
|
Packit |
8f70b4 |
char group[32];
|
|
Packit |
8f70b4 |
int nlink;
|
|
Packit |
8f70b4 |
time_t date;
|
|
Packit |
8f70b4 |
int date_prec;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void clear();
|
|
Packit |
8f70b4 |
bool validate();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
file_info()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
is_directory=false;
|
|
Packit |
8f70b4 |
clear();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
void file_info::clear()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size=-1;
|
|
Packit |
8f70b4 |
year=-1;
|
|
Packit |
8f70b4 |
month=-1;
|
|
Packit |
8f70b4 |
day=0;
|
|
Packit |
8f70b4 |
hour=-1;
|
|
Packit |
8f70b4 |
minute=-1;
|
|
Packit |
8f70b4 |
second=-1;
|
|
Packit |
8f70b4 |
month_name[0]=0;
|
|
Packit |
8f70b4 |
size_str[0]=0;
|
|
Packit |
8f70b4 |
perms[0]=0;
|
|
Packit |
8f70b4 |
sym_link.set(0);
|
|
Packit |
8f70b4 |
is_sym_link=false;
|
|
Packit |
8f70b4 |
user[0]=0;
|
|
Packit |
8f70b4 |
group[0]=0;
|
|
Packit |
8f70b4 |
nlink=0;
|
|
Packit |
8f70b4 |
date=NO_DATE;
|
|
Packit |
8f70b4 |
date_prec=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool file_info::validate()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(year!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// server's y2000 problem :)
|
|
Packit |
8f70b4 |
if(year<37)
|
|
Packit |
8f70b4 |
year+=2000;
|
|
Packit |
8f70b4 |
else if(year<100)
|
|
Packit |
8f70b4 |
year+=1900;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(day<1 || day>31 || hour<-1 || hour>23 || minute<-1 || minute>59
|
|
Packit |
8f70b4 |
|| (month==-1 && !is_ascii_alnum(month_name[0])))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#undef debug
|
|
Packit |
8f70b4 |
#define debug(str) Log::global->Format(10,"* %s\n",str)
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static bool try_apache_listing(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// usual apache listing: DD-Mon-YYYY hh:mm size
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%2d-%3s-%4d %2d:%2d %30s",
|
|
Packit |
8f70b4 |
&info.day,info.month_name,&info.year,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,info.size_str);
|
|
Packit |
8f70b4 |
if(n==6 && (info.size_str[0]=='-' || is_ascii_digit(info.size_str[0])))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug("apache listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_apache_listing_iso(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// apache listing with ISO time: YYYY-MM-DD hh:mm size
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%4d-%2d-%2d %2d:%2d %30s",
|
|
Packit |
8f70b4 |
&info.year,&info.month,&info.day,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,info.size_str);
|
|
Packit |
8f70b4 |
if(n==6 && (info.size_str[0]=='-' || is_ascii_digit(info.size_str[0])))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug("apache listing matched (ISO time)");
|
|
Packit |
8f70b4 |
info.month--;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_apache_listing_unusual(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// unusual apache listing: size DD-Mon-YYYY
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%30s %2d-%3s-%d",
|
|
Packit |
8f70b4 |
info.size_str,&info.day,info.month_name,&info.year);
|
|
Packit |
8f70b4 |
if(n==4 && (info.size_str[0]=='-' || is_ascii_digit(info.size_str[0])))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug("unusual apache listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_netscape_proxy(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char size_unit[7];
|
|
Packit |
8f70b4 |
char week_day[4];
|
|
Packit |
8f70b4 |
// Netscape-Proxy 2.53
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%lld %6s %3s %3s %d %2d:%2d:%2d %4d",
|
|
Packit |
8f70b4 |
&info.size,size_unit,week_day,
|
|
Packit |
8f70b4 |
info.month_name,&info.day,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,&info.second,&info.year);
|
|
Packit |
8f70b4 |
if(n==9)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strcasecmp(size_unit,"bytes")
|
|
Packit |
8f70b4 |
|| !strcasecmp(size_unit,"byte"))
|
|
Packit |
8f70b4 |
snprintf(info.size_str,sizeof(info.size_str),"%lld",info.size);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
snprintf(info.size_str,sizeof(info.size_str),"%lld%s",info.size,size_unit);
|
|
Packit |
8f70b4 |
info.size=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
debug("Netscape-Proxy 2.53 listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
n=sscanf(str,"%3s %3s %d %2d:%2d:%2d %4d %30s",
|
|
Packit |
8f70b4 |
week_day,info.month_name,&info.day,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,&info.second,&info.year,info.size_str);
|
|
Packit |
8f70b4 |
if(n==7 || (n==8 && !is_ascii_digit(info.size_str[0])))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
strcpy(info.size_str,"-");
|
|
Packit |
8f70b4 |
if(!info.is_directory)
|
|
Packit |
8f70b4 |
info.is_sym_link=true;
|
|
Packit |
8f70b4 |
debug("Netscape-Proxy 2.53 listing matched (dir/symlink)");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_squid_eplf(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char week_day[4];
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%3s %3s %d %2d:%2d:%2d %4d %30s",
|
|
Packit |
8f70b4 |
week_day,info.month_name,&info.day,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,&info.second,&info.year,info.size_str);
|
|
Packit |
8f70b4 |
if(n==8) // maybe squid's EPLF listing.
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// no symlinks here.
|
|
Packit |
8f70b4 |
debug("squid EPLF listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_mini_proxy(file_info &info,const char *buf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char PM[3];
|
|
Packit |
8f70b4 |
// Mini-Proxy web server.
|
|
Packit |
8f70b4 |
if(7==sscanf(buf,"%d/%d/%d %d:%d %2s %30s",
|
|
Packit |
8f70b4 |
&info.month,&info.day,&info.year,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,PM,info.size_str))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strcasecmp(PM,"PM"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.hour+=12;
|
|
Packit |
8f70b4 |
if(info.hour==24)
|
|
Packit |
8f70b4 |
info.hour=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!is_ascii_digit(info.size_str[0]))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strcasecmp(info.size_str,"<dir>"))
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
strcpy(info.size_str,"-");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
info.month--;
|
|
Packit |
8f70b4 |
debug("Mini-Proxy web server listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_apache_unixlike(file_info &info,const char *buf,
|
|
Packit |
8f70b4 |
const char *more,const char *more1,xstring& info_string)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// Apache Unix-like listing (from apache proxy):
|
|
Packit |
8f70b4 |
// Perms Nlnk user [group] size Mon DD (YYYY or hh:mm)
|
|
Packit |
8f70b4 |
char year_or_time[6];
|
|
Packit |
8f70b4 |
int consumed;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int n=sscanf(buf,"%11s %d %31s %31s %lld %3s %2d %5s%n",info.perms,&info.nlink,
|
|
Packit |
8f70b4 |
info.user,info.group,&info.size,info.month_name,&info.day,
|
|
Packit |
8f70b4 |
year_or_time,&consumed);
|
|
Packit |
8f70b4 |
if(n==4) // bsd-like listing without group?
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.group[0]=0;
|
|
Packit |
8f70b4 |
n=sscanf(buf,"%11s %d %31s %lld %3s %2d %5s%n",info.perms,&info.nlink,
|
|
Packit |
8f70b4 |
info.user,&info.size,info.month_name,&info.day,year_or_time,&consumed);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(n>=7 && -1!=parse_perms(info.perms+1)
|
|
Packit |
8f70b4 |
&& -1!=(info.month=parse_month(info.month_name))
|
|
Packit |
8f70b4 |
&& -1!=parse_year_or_time(year_or_time,&info.year,&info.hour,&info.minute))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
snprintf(info.size_str,sizeof(info.size_str),"%lld",info.size);
|
|
Packit |
8f70b4 |
if(info.perms[0]=='d')
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
else if(info.perms[0]=='l')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.is_sym_link=true;
|
|
Packit |
8f70b4 |
char *str=string_alloca(more1-more);
|
|
Packit |
8f70b4 |
memcpy(str,more+1,more1-more-4);
|
|
Packit |
8f70b4 |
str[more1-more-4]=0;
|
|
Packit |
8f70b4 |
str=strstr(str," -> ");
|
|
Packit |
8f70b4 |
if(str)
|
|
Packit |
8f70b4 |
info.sym_link.set(str+4);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
info_string.nset(buf,consumed);
|
|
Packit |
8f70b4 |
debug("apache ftp over http proxy listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static bool try_roxen(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// Roxen listing ([size] {kb/Mb} application/octet-stream YYYY-MM-DD)
|
|
Packit |
8f70b4 |
// or (directory YYYY-MM-DD)
|
|
Packit |
8f70b4 |
char size_mod[6];
|
|
Packit |
8f70b4 |
long size_mod_i=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
str=strchr(str+(*str=='\n'),'\n');
|
|
Packit |
8f70b4 |
if(!str)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%26s %5s %*[a-z0-9/-] %4d-%2d-%2d",info.size_str,size_mod,
|
|
Packit |
8f70b4 |
&info.year,&info.month,&info.day);
|
|
Packit |
8f70b4 |
if(n==5)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strncmp(size_mod,"byte",4))
|
|
Packit |
8f70b4 |
size_mod_i=1;
|
|
Packit |
8f70b4 |
else if(!strcmp(size_mod,"kb"))
|
|
Packit |
8f70b4 |
size_mod_i=1024;
|
|
Packit |
8f70b4 |
else if(!strcmp(size_mod,"Mb"))
|
|
Packit |
8f70b4 |
size_mod_i=1024*1024;
|
|
Packit |
8f70b4 |
else if(!strcmp(size_mod,"Gb"))
|
|
Packit |
8f70b4 |
size_mod_i=1024*1024*1024;
|
|
Packit |
8f70b4 |
if(size_mod_i)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *old_size_str=alloca_strdup(info.size_str);
|
|
Packit |
8f70b4 |
snprintf(info.size_str,sizeof(info.size_str),"%s%s",old_size_str,size_mod);
|
|
Packit |
8f70b4 |
debug("Roxen web server listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
strcpy(info.size_str,"-");
|
|
Packit |
8f70b4 |
n=sscanf(str," directory %4d-%2d-%2d",&info.year,&info.month,&info.day);
|
|
Packit |
8f70b4 |
if(n==3)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug("Roxen web server listing matched (directory)");
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static bool try_squid_ftp(file_info &info,const char *str,char *str_with_tags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char year_or_time[6];
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// squid's ftp listing: Mon DD (YYYY or hh:mm) [size]
|
|
Packit |
8f70b4 |
int n=sscanf(str,"%3s %2d %5s %30s",info.month_name,&info.day,year_or_time,info.size_str);
|
|
Packit |
8f70b4 |
if(n<3)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(!is_ascii_digit(info.size_str[0]))
|
|
Packit |
8f70b4 |
strcpy(info.size_str,"-");
|
|
Packit |
8f70b4 |
if(-1==parse_year_or_time(year_or_time,&info.year,&info.hour,&info.minute))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(-1==parse_month(info.month_name))
|
|
Packit |
8f70b4 |
return false; // be strict.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *ptr;
|
|
Packit |
8f70b4 |
ptr=strstr(str_with_tags," ->
|
|
Packit |
8f70b4 |
if(ptr)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.is_sym_link=true;
|
|
Packit |
8f70b4 |
char *sym_link=ptr+13;
|
|
Packit |
8f70b4 |
ptr=strchr(sym_link,'"');
|
|
Packit |
8f70b4 |
if(!ptr)
|
|
Packit |
8f70b4 |
info.sym_link.unset();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*ptr=0;
|
|
Packit |
8f70b4 |
info.sym_link.set(url::decode(sym_link));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
debug("squid ftp listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static bool try_wwwoffle_ftp(file_info &info,const char *buf,
|
|
Packit |
8f70b4 |
const char *ext,xstring& info_string)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// Perms Nlnk user [group] size Mon DD (YYYY or hh:mm)
|
|
Packit |
8f70b4 |
char year_or_time[6];
|
|
Packit |
8f70b4 |
int consumed;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int n=sscanf(buf,"%11s %d %31s %31s %lld %3s %2d %5s%n",info.perms,&info.nlink,
|
|
Packit |
8f70b4 |
info.user,info.group,&info.size,info.month_name,&info.day,
|
|
Packit |
8f70b4 |
year_or_time,&consumed);
|
|
Packit |
8f70b4 |
if(n==4) // bsd-like listing without group?
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.group[0]=0;
|
|
Packit |
8f70b4 |
n=sscanf(buf,"%11s %d %31s %lld %3s %2d %5s%n",info.perms,&info.nlink,
|
|
Packit |
8f70b4 |
info.user,&info.size,info.month_name,&info.day,year_or_time,&consumed);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(n>=7 && -1!=parse_perms(info.perms+1)
|
|
Packit |
8f70b4 |
&& -1!=(info.month=parse_month(info.month_name))
|
|
Packit |
8f70b4 |
&& -1!=parse_year_or_time(year_or_time,&info.year,&info.hour,&info.minute))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
snprintf(info.size_str,sizeof(info.size_str),"%lld",info.size);
|
|
Packit |
8f70b4 |
if(info.perms[0]=='d')
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
else if(info.perms[0]=='l')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.is_sym_link=true;
|
|
Packit |
8f70b4 |
const char *p=strstr(ext,"-> ");
|
|
Packit |
8f70b4 |
if(p)
|
|
Packit |
8f70b4 |
info.sym_link.set(p+6);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
info_string.nset(buf,consumed);
|
|
Packit |
8f70b4 |
debug("wwwoffle ftp over http proxy listing matched");
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// 4096 Jun 25 23:48Directory| ***
|
|
Packit |
8f70b4 |
// 4096 Jun 23 2002Directory| ***
|
|
Packit |
8f70b4 |
// 50 Jul 9 18:37Symbolic Link| ***
|
|
Packit |
8f70b4 |
// 217 Jun 3 06:01Plain Text| ***
|
|
Packit |
8f70b4 |
// 40419 Jul 6 13:06Hypertext Markup Language| ***
|
|
Packit |
8f70b4 |
// 14289850 Jul 16 17:04Windows Bitmap| ***
|
|
Packit |
8f70b4 |
// 6668926 Jul 17 16:01Binary Executable| ***
|
|
Packit |
8f70b4 |
static bool try_csm_proxy(file_info &info,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int n;
|
|
Packit |
8f70b4 |
int status = false;
|
|
Packit |
8f70b4 |
char additional_file_info[33];
|
|
Packit |
8f70b4 |
int has_additional_file_info = false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
memset(additional_file_info, '\0', sizeof (additional_file_info));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// try to match hour:minute
|
|
Packit |
8f70b4 |
if (5 <= (n = sscanf(str,"%lld %3s %d %2d:%2d%32s",
|
|
Packit |
8f70b4 |
&info.size, info.month_name, &info.day, &info.hour, &info.minute, additional_file_info))) {
|
|
Packit |
8f70b4 |
status = true;
|
|
Packit |
8f70b4 |
if (6 == n)
|
|
Packit |
8f70b4 |
has_additional_file_info = true;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
// try to match year instead of hour:minute
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
if (4 <= (n = sscanf(str,"%lld %3s %d %4d%32s",
|
|
Packit |
8f70b4 |
&info.size, info.month_name, &info.day, &info.year, additional_file_info))) {
|
|
Packit |
8f70b4 |
status = true;
|
|
Packit |
8f70b4 |
if (5 == n)
|
|
Packit |
8f70b4 |
has_additional_file_info = true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if (status) {
|
|
Packit |
8f70b4 |
debug("csm_proxy listing matched");
|
|
Packit |
8f70b4 |
snprintf(info.size_str,sizeof(info.size_str),"%lld",info.size);
|
|
Packit |
8f70b4 |
if (has_additional_file_info && additional_file_info[0]) {
|
|
Packit |
8f70b4 |
if (!strncasecmp("Symbolic Link",additional_file_info,13)) {
|
|
Packit |
8f70b4 |
info.is_sym_link = true;
|
|
Packit |
8f70b4 |
} else if (!strncasecmp("Directory",additional_file_info,9)) {
|
|
Packit |
8f70b4 |
info.is_directory = true;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
// fprintf(stderr, "try_csm_proxy: |%s|\n", additional_file_info);
|
|
Packit |
8f70b4 |
Log::global->Format(10,
|
|
Packit |
8f70b4 |
"* try_csm_proxy: unknown file type '%s'\n",
|
|
Packit |
8f70b4 |
additional_file_info);
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return status;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// 2004-Oct-19 02:10:26 0.2K application/octet-stream
|
|
Packit |
8f70b4 |
static bool try_lighttpd_listing(file_info &info,char *str_with_tags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
info.clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(str_with_tags[0]=='/') {
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
str_with_tags++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *next=strstr(str_with_tags,"\"m\">");
|
|
Packit |
8f70b4 |
if(!next)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
next+=4;
|
|
Packit |
8f70b4 |
const char *end=strchr(next,'<');
|
|
Packit |
8f70b4 |
if(!end)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
xstring datetime(next,end-next);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
next=strstr(end,"\"s\">");
|
|
Packit |
8f70b4 |
if(!next)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
next+=4;
|
|
Packit |
8f70b4 |
end=strchr(next,'<');
|
|
Packit |
8f70b4 |
if(!end)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
xstring size(next,end-next);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int n=sscanf(datetime,"%4d-%3s-%2d %2d:%2d:%2d",
|
|
Packit |
8f70b4 |
&info.year,info.month_name,&info.day,
|
|
Packit |
8f70b4 |
&info.hour,&info.minute,&info.second);
|
|
Packit |
8f70b4 |
if(n!=6)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(is_ascii_digit(size[0])) {
|
|
Packit |
8f70b4 |
strncpy(info.size_str,size,sizeof(info.size_str));
|
|
Packit |
8f70b4 |
info.size_str[sizeof(info.size_str)-1]=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
debug("lighttpd listing matched");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// this procedure is highly inefficient in some cases,
|
|
Packit |
8f70b4 |
// esp. when it has to return for more data many times.
|
|
Packit |
8f70b4 |
static int parse_html(const char *buf,int buf_len,bool eof,const Ref<Buffer>& list,
|
|
Packit |
8f70b4 |
FileSet *set,FileSet *all_links,const ParsedURL *prefix,xstring_c *base_href,
|
|
Packit |
8f70b4 |
LsOptions *lsopt=0, int color = 0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *end=buf+buf_len;
|
|
Packit |
8f70b4 |
const char *less=find_char(buf,buf_len,'<');
|
|
Packit |
8f70b4 |
int eol_len=0;
|
|
Packit |
8f70b4 |
int skip_len=0;
|
|
Packit |
8f70b4 |
const char *eol;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
eol=find_eol(buf,buf_len,eof,&eol_len);
|
|
Packit |
8f70b4 |
if(eol)
|
|
Packit |
8f70b4 |
skip_len=eol-buf+eol_len;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(less==0)
|
|
Packit |
8f70b4 |
return skip_len;
|
|
Packit |
8f70b4 |
if(skip_len>0 && eol
|
|
Packit |
8f70b4 |
return skip_len;
|
|
Packit |
8f70b4 |
if(end-less-1>=3 && less[1]=='!' && less[2]=='-' && less[3]=='-')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// found comment
|
|
Packit |
8f70b4 |
if(end-less-4<3)
|
|
Packit |
8f70b4 |
return less-buf;
|
|
Packit |
8f70b4 |
const char *scan=less+4;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *eoc=find_char(scan,end-scan,'>');
|
|
Packit |
8f70b4 |
if(!eoc)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof) // unterminated comment.
|
|
Packit |
8f70b4 |
return buf_len;
|
|
Packit |
8f70b4 |
return less-buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(eoc>=less+4+2 && eoc[-1]=='-' && eoc[-2]=='-')
|
|
Packit |
8f70b4 |
return eoc+1-buf;
|
|
Packit |
8f70b4 |
scan=eoc+1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// FIXME: a > sign can be inside quoted value. (?)
|
|
Packit |
8f70b4 |
const char *more=find_char(less+1,end-less-1,'>');
|
|
Packit |
8f70b4 |
if(more==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
return buf_len;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// we have found a tag
|
|
Packit |
8f70b4 |
int tag_len=more-buf+1;
|
|
Packit |
8f70b4 |
if(more-less<3)
|
|
Packit |
8f70b4 |
return tag_len; // too small
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(less[1]=='/' || less[1]=='!')
|
|
Packit |
8f70b4 |
return tag_len;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring link_target;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static const struct tag_link
|
|
Packit |
8f70b4 |
{ const char *tag, *link; }
|
|
Packit |
8f70b4 |
tag_list[]={
|
|
Packit |
8f70b4 |
/* taken from wget-1.5.3: */
|
|
Packit |
8f70b4 |
/* NULL-terminated list of tags and modifiers someone would want to
|
|
Packit |
8f70b4 |
follow -- feel free to edit to suit your needs: */
|
|
Packit |
8f70b4 |
{ "a", "href" },
|
|
Packit |
8f70b4 |
{ "img", "src" },
|
|
Packit |
8f70b4 |
{ "img", "href" },
|
|
Packit |
8f70b4 |
{ "body", "background" },
|
|
Packit |
8f70b4 |
{ "frame", "src" },
|
|
Packit |
8f70b4 |
{ "iframe", "src" },
|
|
Packit |
8f70b4 |
{ "fig", "src" },
|
|
Packit |
8f70b4 |
{ "overlay", "src" },
|
|
Packit |
8f70b4 |
{ "applet", "code" },
|
|
Packit |
8f70b4 |
{ "script", "src" },
|
|
Packit |
8f70b4 |
{ "source", "src" },
|
|
Packit |
8f70b4 |
{ "embed", "src" },
|
|
Packit |
8f70b4 |
{ "bgsound", "src" },
|
|
Packit |
8f70b4 |
{ "area", "href" },
|
|
Packit |
8f70b4 |
{ "img", "lowsrc" },
|
|
Packit |
8f70b4 |
{ "input", "src" },
|
|
Packit |
8f70b4 |
{ "layer", "src" },
|
|
Packit |
8f70b4 |
{ "table", "background" },
|
|
Packit |
8f70b4 |
{ "th", "background" },
|
|
Packit |
8f70b4 |
{ "td", "background" },
|
|
Packit |
8f70b4 |
{ "link", "href" },
|
|
Packit |
8f70b4 |
/* Tags below this line are treated specially. */
|
|
Packit |
8f70b4 |
{ "base", "href" },
|
|
Packit |
8f70b4 |
{ "meta", "content" },
|
|
Packit |
8f70b4 |
{ NULL, NULL }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FIXME: a tag can have many links.
|
|
Packit |
8f70b4 |
const struct tag_link *tag_scan;
|
|
Packit |
8f70b4 |
for(tag_scan=tag_list; tag_scan->tag; tag_scan++)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(token_eq(less+1,end-less-1,tag_scan->tag))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(find_value(less+1+strlen(tag_scan->tag),more,
|
|
Packit |
8f70b4 |
tag_scan->link,link_target))
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(tag_scan->tag==0)
|
|
Packit |
8f70b4 |
return tag_len; // not interesting
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *prefix_proto=0;
|
|
Packit |
8f70b4 |
if(prefix)
|
|
Packit |
8f70b4 |
prefix_proto=prefix->proto;
|
|
Packit |
8f70b4 |
if(!xstrcmp(prefix_proto,"hftp"))
|
|
Packit |
8f70b4 |
prefix_proto++;
|
|
Packit |
8f70b4 |
bool hftp=!xstrcmp(prefix_proto,"ftp");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// ok, found the target.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
decode_amps(link_target); // decode all & and similar
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// inherit the protocol if omitted
|
|
Packit |
8f70b4 |
if(link_target.begins_with("//") && prefix && prefix->proto) {
|
|
Packit |
8f70b4 |
xstring& new_link=xstring::get_tmp("")
|
|
Packit |
8f70b4 |
.append_url_encoded(prefix->proto,URL_UNSAFE,0)
|
|
Packit |
8f70b4 |
.append(':').append(link_target);
|
|
Packit |
8f70b4 |
link_target.swap(new_link);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(hftp)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// workaround proxy bugs.
|
|
Packit |
8f70b4 |
const char *t=strstr(link_target,";type=");
|
|
Packit |
8f70b4 |
if(t && t[6] && t[7]=='/' && t[8]==0)
|
|
Packit |
8f70b4 |
link_target.truncate(t-link_target);
|
|
Packit |
8f70b4 |
const char *p=link_target+url::path_index(link_target);
|
|
Packit |
8f70b4 |
if(p[0]=='/' && p[1]=='/')
|
|
Packit |
8f70b4 |
link_target.set_substr(p-link_target+1,1,"%2F");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Log::global->Format(10,"Found tag %s, link_target=%s\n",tag_scan->tag,link_target.get());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!strcasecmp(tag_scan->tag,"base"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(base_href)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
base_href->set(link_target);
|
|
Packit |
8f70b4 |
Log::global->Format(10,"Using base href=%s\n",base_href->get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return tag_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!strcasecmp(tag_scan->tag,"meta"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// skip 0; URL=
|
|
Packit |
8f70b4 |
link_target.rtrim();
|
|
Packit |
8f70b4 |
const char *scan=link_target;
|
|
Packit |
8f70b4 |
while(*scan && is_ascii_digit(*scan))
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
if(*scan!=';')
|
|
Packit |
8f70b4 |
return tag_len;
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
while(*scan && is_ascii_space(*scan))
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
if(strncasecmp(scan,"URL=",4))
|
|
Packit |
8f70b4 |
return tag_len;
|
|
Packit |
8f70b4 |
scan+=4;
|
|
Packit |
8f70b4 |
int len=link_target.length()-(scan-link_target);
|
|
Packit |
8f70b4 |
if(link_target[0]=='\'')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// FIXME: maybe a more complex value parser is required.
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
if(len>0 && scan[len-1]=='\'')
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
link_target.nset(scan,len);
|
|
Packit |
8f70b4 |
Log::global->Format(10,"Extracted `%s' from META tag\n",link_target.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool icon=false;
|
|
Packit |
8f70b4 |
if(!strcasecmp(tag_scan->tag,"img")
|
|
Packit |
8f70b4 |
&& !strcasecmp(tag_scan->link,"src"))
|
|
Packit |
8f70b4 |
icon=true;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool a_href=false;
|
|
Packit |
8f70b4 |
if(!strcasecmp(tag_scan->tag,"a")
|
|
Packit |
8f70b4 |
&& !strcasecmp(tag_scan->link,"href"))
|
|
Packit |
8f70b4 |
a_href=true;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// check if the target is a relative and not a cgi
|
|
Packit |
8f70b4 |
if(strchr(link_target,'?'))
|
|
Packit |
8f70b4 |
return tag_len; // cgi
|
|
Packit |
8f70b4 |
link_target.truncate_at('#'); // strip the anchor
|
|
Packit |
8f70b4 |
if(link_target.length()==0)
|
|
Packit |
8f70b4 |
return tag_len; // no target ?
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// netscape internal icons
|
|
Packit |
8f70b4 |
if(icon && !strncasecmp(link_target,"internal-gopher",15))
|
|
Packit |
8f70b4 |
return tag_len;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(link_target[0]=='/' && link_target[1]=='~')
|
|
Packit |
8f70b4 |
link_target.set_substr(0,1,0,0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool base_href_applied=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
parse_url_again:
|
|
Packit |
8f70b4 |
ParsedURL link_url(link_target,/*proto_required=*/true);
|
|
Packit |
8f70b4 |
if(link_url.proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!prefix)
|
|
Packit |
8f70b4 |
return tag_len; // no way
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(xstrcmp(link_url.proto,prefix_proto)
|
|
Packit |
8f70b4 |
|| xstrcmp(link_url.host,prefix->host)
|
|
Packit |
8f70b4 |
|| xstrcmp(link_url.user,prefix->user)
|
|
Packit |
8f70b4 |
|| xstrcmp(link_url.port,prefix->port))
|
|
Packit |
8f70b4 |
return tag_len; // no match
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *scan_link=link_target;
|
|
Packit |
8f70b4 |
while(*scan_link)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(scan_link>link_target && *scan_link==':')
|
|
Packit |
8f70b4 |
return tag_len; // special url, like mailto:
|
|
Packit |
8f70b4 |
if(!is_ascii_alpha(*scan_link))
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
scan_link++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(*link_target!='/' && base_href && *base_href && !base_href_applied)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *base_end=strrchr(*base_href,'/');
|
|
Packit |
8f70b4 |
if(base_end)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
link_target.set_substr(0,0,*base_href,(base_end+1-*base_href));
|
|
Packit |
8f70b4 |
base_href_applied=true;
|
|
Packit |
8f70b4 |
goto parse_url_again;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// ok, it is good relative link
|
|
Packit |
8f70b4 |
if(link_url.path==0)
|
|
Packit |
8f70b4 |
link_target.set("/");
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
link_target.set(link_url.path);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(link_target[0]=='/' && link_target[1]=='/' && hftp)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// workaround for apache proxy.
|
|
Packit |
8f70b4 |
link_target.set_substr(0,1,0,0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
file_info info;
|
|
Packit |
8f70b4 |
info.is_directory=(link_target.last_char()=='/');
|
|
Packit |
8f70b4 |
if(link_target.length()>1)
|
|
Packit |
8f70b4 |
link_target.chomp('/');
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccess::Path::Optimize(link_target,(link_target[0]=='/' && link_target[1]=='~'));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(prefix)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *p_path_c=prefix->path;
|
|
Packit |
8f70b4 |
if(p_path_c==0)
|
|
Packit |
8f70b4 |
p_path_c="~";
|
|
Packit |
8f70b4 |
char *p_path=alloca_strdup(p_path_c);
|
|
Packit |
8f70b4 |
int p_len=strlen(p_path);
|
|
Packit |
8f70b4 |
if(p_len>1 && p_path[p_len-1]=='/')
|
|
Packit |
8f70b4 |
p_path[--p_len]=0;
|
|
Packit |
8f70b4 |
if(p_len==1 && p_path[0]=='/' && link_target[0]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(link_target.length()>1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// strip leading slash
|
|
Packit |
8f70b4 |
link_target.set_substr(0,1,0,0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(p_len>0 && !strncmp(link_target,p_path,p_len))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(link_target[p_len]=='/')
|
|
Packit |
8f70b4 |
link_target.set_substr(0,p_len+1,0,0);
|
|
Packit |
8f70b4 |
else if(link_target[p_len]==0)
|
|
Packit |
8f70b4 |
link_target.set(".");
|
|
Packit |
8f70b4 |
if(link_target[0]=='.' && link_target[1]=='/')
|
|
Packit |
8f70b4 |
link_target.set_substr(0,2,0,0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// try ..
|
|
Packit |
8f70b4 |
const char *rslash=strrchr(p_path,'/');
|
|
Packit |
8f70b4 |
if(rslash)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
p_len=rslash-p_path;
|
|
Packit |
8f70b4 |
if(p_len>0 && !strncmp(link_target,p_path,p_len)
|
|
Packit |
8f70b4 |
&& link_target[p_len]==0)
|
|
Packit |
8f70b4 |
link_target.set("..");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *type=strstr(link_target,";type=");
|
|
Packit |
8f70b4 |
if(type && type[6] && !type[7])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!all_links || all_links->FindByName(xstring::get_tmp(link_target,type-link_target)))
|
|
Packit |
8f70b4 |
return tag_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(link_target.length()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
link_target.set(".");
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool show_in_list=true;
|
|
Packit |
8f70b4 |
if(icon && (link_target[0]=='/' || link_target[0]=='~'))
|
|
Packit |
8f70b4 |
show_in_list=false; // makes apache listings look better.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
skip_len=tag_len;
|
|
Packit |
8f70b4 |
// try to find file info
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *more1;
|
|
Packit |
8f70b4 |
char *str,*str_with_tags, *str2;
|
|
Packit |
8f70b4 |
xstring line_add;
|
|
Packit |
8f70b4 |
xstring info_string;
|
|
Packit |
8f70b4 |
int type;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!a_href)
|
|
Packit |
8f70b4 |
goto add_file_no_info; // only tags can have useful info.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// try to extract file information
|
|
Packit |
8f70b4 |
more1=more;
|
|
Packit |
8f70b4 |
find_a_end:
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
more1++;
|
|
Packit |
8f70b4 |
more1=find_char(more1,end-more1,'>');
|
|
Packit |
8f70b4 |
if(!more1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
goto add_file_no_info;
|
|
Packit |
8f70b4 |
if(end-more>2*1024) // too long a-href
|
|
Packit |
8f70b4 |
goto add_file_no_info;
|
|
Packit |
8f70b4 |
return 0; // no full a-href yet
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!strncasecmp(more1-3,"
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// get a whole line in buffer if possible.
|
|
Packit |
8f70b4 |
eol=find_eol(more1+1,end-more1-1,eof,&eol_len);
|
|
Packit |
8f70b4 |
if(!eol)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!eof && end-more<=2*1024)
|
|
Packit |
8f70b4 |
return 0; // no full line yet
|
|
Packit |
8f70b4 |
eol=end;
|
|
Packit |
8f70b4 |
eol_len=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// little workaround for squid's ftp listings
|
|
Packit |
8f70b4 |
if(more1[1]==' ' && eol-more1>more-less+10
|
|
Packit |
8f70b4 |
&& !strncmp(more1+2,less,more-less+1))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
more1=more1+2+(more-less);
|
|
Packit |
8f70b4 |
goto find_a_end;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(more1[1]==' ')
|
|
Packit |
8f70b4 |
more1++;
|
|
Packit |
8f70b4 |
while(more1+1+2
|
|
Packit |
8f70b4 |
more1+=2;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// the buffer is not null-terminated, so we need this
|
|
Packit |
8f70b4 |
str=string_alloca(eol-more1);
|
|
Packit |
8f70b4 |
memcpy(str,more1+1,eol-more1-1);
|
|
Packit |
8f70b4 |
str[eol-more1-1]=0;
|
|
Packit |
8f70b4 |
str_with_tags=alloca_strdup(str);
|
|
Packit |
8f70b4 |
remove_tags(str);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(try_apache_listing(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
if(try_apache_listing_iso(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
if(try_apache_listing_unusual(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
if(try_netscape_proxy(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
if(try_squid_eplf(info,str) && info.validate())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// skip rest of line, because there may be another href to link target.
|
|
Packit |
8f70b4 |
skip_len=eol-buf+eol_len;
|
|
Packit |
8f70b4 |
goto got_info;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(try_lighttpd_listing(info,str_with_tags) && info.validate())
|
|
Packit |
8f70b4 |
goto got_info;
|
|
Packit |
8f70b4 |
if(try_mini_proxy(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
if(try_apache_unixlike(info,str,more,more1,info_string)
|
|
Packit |
8f70b4 |
&& info.validate())
|
|
Packit |
8f70b4 |
goto got_info;
|
|
Packit |
8f70b4 |
if(try_roxen(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
if(try_squid_ftp(info,str,str_with_tags) && info.validate())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// skip rest of line, because there may be href to link target.
|
|
Packit |
8f70b4 |
skip_len=eol-buf+eol_len;
|
|
Packit |
8f70b4 |
goto got_info;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// wwwoffle
|
|
Packit |
8f70b4 |
str2=string_alloca(less-buf+1);
|
|
Packit |
8f70b4 |
memcpy(str2,buf,less-buf);
|
|
Packit |
8f70b4 |
str2[less-buf]=0;
|
|
Packit |
8f70b4 |
if(try_wwwoffle_ftp(info,str2,str,info_string)
|
|
Packit |
8f70b4 |
&& info.validate())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// skip rest of line, because there may be href to link target.
|
|
Packit |
8f70b4 |
skip_len=eol-buf+eol_len;
|
|
Packit |
8f70b4 |
goto got_info;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(try_csm_proxy(info,str) && info.validate()) goto got_info;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
add_file_no_info:
|
|
Packit |
8f70b4 |
if(!list || !show_in_list)
|
|
Packit |
8f70b4 |
goto info_done;
|
|
Packit |
8f70b4 |
line_add.vset(info.is_directory?"drwxr-xr-x":"-rw-r--r--"," -- ",link_target.get(),NULL);
|
|
Packit |
8f70b4 |
goto append_type_maybe;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
got_info:
|
|
Packit |
8f70b4 |
if(info.month==-1)
|
|
Packit |
8f70b4 |
info.month=parse_month(info.month_name);
|
|
Packit |
8f70b4 |
if(info.month>=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
snprintf(info.month_name,sizeof(info.month_name),"%02d",info.month+1);
|
|
Packit |
8f70b4 |
if(info.year==-1)
|
|
Packit |
8f70b4 |
info.year=guess_year(info.month,info.day,info.hour,info.minute);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(info.year!=-1 && info.month!=-1 && info.day!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct tm tm;
|
|
Packit |
8f70b4 |
memset(&tm,0,sizeof(tm));
|
|
Packit |
8f70b4 |
tm.tm_year=info.year-1900;
|
|
Packit |
8f70b4 |
tm.tm_mon=info.month;
|
|
Packit |
8f70b4 |
tm.tm_mday=info.day;
|
|
Packit |
8f70b4 |
tm.tm_hour=12;
|
|
Packit |
8f70b4 |
info.date_prec=43200;
|
|
Packit |
8f70b4 |
if(info.hour!=-1 && info.minute!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
tm.tm_hour=info.hour;
|
|
Packit |
8f70b4 |
tm.tm_min=info.minute;
|
|
Packit |
8f70b4 |
tm.tm_sec=30;
|
|
Packit |
8f70b4 |
info.date_prec=30;
|
|
Packit |
8f70b4 |
if(info.second!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
tm.tm_sec=info.second;
|
|
Packit |
8f70b4 |
info.date_prec=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
info.date=mktime_from_utc(&tm;;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(info.size==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(strspn(info.size_str,"0123456789")==strlen(info.size_str))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
long long size_ll=0;
|
|
Packit |
8f70b4 |
if(sscanf(info.size_str,"%lld",&size_ll)!=1)
|
|
Packit |
8f70b4 |
size_ll=0;
|
|
Packit |
8f70b4 |
info.size=size_ll;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(info.perms[0]==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(info.is_directory)
|
|
Packit |
8f70b4 |
strcpy(info.perms,"drwxr-xr-x");
|
|
Packit |
8f70b4 |
else if(info.is_sym_link)
|
|
Packit |
8f70b4 |
strcpy(info.perms,"lrwxrwxrwx");
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
strcpy(info.perms,"-rw-r--r--");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!list || !show_in_list)
|
|
Packit |
8f70b4 |
goto info_done;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(info_string)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
line_add.vset(info_string.get()," ",link_target.get(),NULL);
|
|
Packit |
8f70b4 |
goto append_symlink_maybe;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
line_add.setf("%s %11s %04d-%s-%02d",
|
|
Packit |
8f70b4 |
info.perms,info.size_str,info.year,info.month_name,info.day);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if (info.hour >= 0 || info.minute >= 0) {
|
|
Packit |
8f70b4 |
if (info.hour >= 0) {
|
|
Packit |
8f70b4 |
line_add.appendf(" %02d:",info.hour);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
line_add.append(" --:");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if (info.minute >= 0) {
|
|
Packit |
8f70b4 |
line_add.appendf("%02d", info.minute);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
line_add.append("--");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
// neither hour nor minute are given
|
|
Packit |
8f70b4 |
line_add.append(" ");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
line_add.append(" ");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
type = FileInfo::NORMAL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(info.is_directory)
|
|
Packit |
8f70b4 |
type = FileInfo::DIRECTORY;
|
|
Packit |
8f70b4 |
else if(info.is_sym_link && !info.sym_link)
|
|
Packit |
8f70b4 |
type = FileInfo::SYMLINK;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if (color && FileInfo::NORMAL != type && all_links && !all_links->FindByName(link_target)) {
|
|
Packit |
8f70b4 |
list->Put(line_add);
|
|
Packit |
8f70b4 |
DirColors::GetInstance()->PutColored(list, link_target, type);
|
|
Packit |
8f70b4 |
line_add.truncate(0); // reset
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
line_add.append(link_target);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
append_symlink_maybe:
|
|
Packit |
8f70b4 |
if(info.sym_link)
|
|
Packit |
8f70b4 |
line_add.vappend(" -> ",info.sym_link.get(),NULL);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
append_type_maybe:
|
|
Packit |
8f70b4 |
if(lsopt && lsopt->append_type)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(info.is_directory)
|
|
Packit |
8f70b4 |
line_add.append('/');
|
|
Packit |
8f70b4 |
if(info.is_sym_link && !info.sym_link)
|
|
Packit |
8f70b4 |
line_add.append('@');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
line_add.append('\n');
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!all_links->FindByName(link_target))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
list->Put(line_add);
|
|
Packit |
8f70b4 |
FileInfo *fi=new FileInfo(link_target);
|
|
Packit |
8f70b4 |
all_links->Add(fi);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
info_done:
|
|
Packit |
8f70b4 |
if(set && link_target[0]!='/' && link_target[0]!='~')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *slash=strchr(link_target,'/');
|
|
Packit |
8f70b4 |
if(slash)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
link_target.truncate(slash-link_target);
|
|
Packit |
8f70b4 |
info.is_directory=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileInfo *fi=new FileInfo(link_target);
|
|
Packit |
8f70b4 |
if(info.sym_link)
|
|
Packit |
8f70b4 |
fi->SetSymlink(info.sym_link);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
fi->SetType(info.is_directory ? fi->DIRECTORY : fi->NORMAL);
|
|
Packit |
8f70b4 |
if(info.nlink>0)
|
|
Packit |
8f70b4 |
fi->SetNlink(info.nlink);
|
|
Packit |
8f70b4 |
if(info.user[0])
|
|
Packit |
8f70b4 |
fi->SetUser(info.user);
|
|
Packit |
8f70b4 |
if(info.group[0])
|
|
Packit |
8f70b4 |
fi->SetGroup(info.group);
|
|
Packit |
8f70b4 |
if(info.size!=-1)
|
|
Packit |
8f70b4 |
fi->SetSize(info.size);
|
|
Packit |
8f70b4 |
if(info.perms[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=parse_perms(info.perms+1);
|
|
Packit |
8f70b4 |
if(m>=0)
|
|
Packit |
8f70b4 |
fi->SetMode(m);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(info.date_prec!=-1 && info.date!=NO_DATE)
|
|
Packit |
8f70b4 |
fi->SetDate(info.date,info.date_prec);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
set->Add(fi);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return skip_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// HttpDirList implementation
|
|
Packit |
8f70b4 |
#define super DirList
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int HttpDirList::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(buf->Eof())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ubuf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
curr=args->getnext();
|
|
Packit |
8f70b4 |
if(!curr)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf->PutEOF();
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(args->count()>2)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(args->getindex()>1)
|
|
Packit |
8f70b4 |
buf->Put("\n");
|
|
Packit |
8f70b4 |
buf->Put(curr);
|
|
Packit |
8f70b4 |
buf->Put(":\n");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
curr_url=new ParsedURL(session->GetFileURL(curr));
|
|
Packit |
8f70b4 |
if(mode==FA::RETRIEVE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// strip file name, directory remains.
|
|
Packit |
8f70b4 |
const char *slash=strrchr(curr_url->path,'/');
|
|
Packit |
8f70b4 |
if(slash && slash>curr_url->path)
|
|
Packit |
8f70b4 |
curr_url->path.truncate(slash-curr_url->path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
retry:
|
|
Packit |
8f70b4 |
const char *cache_buffer=0;
|
|
Packit |
8f70b4 |
int cache_buffer_size=0;
|
|
Packit |
8f70b4 |
int err;
|
|
Packit |
8f70b4 |
if(use_cache && FileAccess::cache->Find(session,curr,mode,&err,
|
|
Packit |
8f70b4 |
&cache_buffer,&cache_buffer_size))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==FA::MP_LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode=FA::LONG_LIST;
|
|
Packit |
8f70b4 |
goto retry;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetErrorCached(cache_buffer);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ubuf=new IOBuffer(IOBuffer::GET);
|
|
Packit |
8f70b4 |
ubuf->Put(cache_buffer,cache_buffer_size);
|
|
Packit |
8f70b4 |
ubuf->PutEOF();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==FA::MP_LIST && !*curr && session->GetCwd().is_file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode=FA::LONG_LIST;
|
|
Packit |
8f70b4 |
goto retry;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
session->Open(curr,mode);
|
|
Packit |
8f70b4 |
session->UseCache(use_cache);
|
|
Packit |
8f70b4 |
ubuf=new IOBufferFileAccess(session);
|
|
Packit |
8f70b4 |
if(FileAccess::cache->IsEnabled(session->GetHostName()))
|
|
Packit |
8f70b4 |
ubuf->Save(FileAccess::cache->SizeLimit());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int len;
|
|
Packit |
8f70b4 |
ubuf->Get(&b,&len;;
|
|
Packit |
8f70b4 |
if(b==0) // eof
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileAccess::cache->Add(session,curr,mode,FA::OK,ubuf);
|
|
Packit |
8f70b4 |
ubuf=0;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
reparse:
|
|
Packit |
8f70b4 |
if(mode!=FA::MP_LIST || parse_as_html)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int n=parse_html(b,len,ubuf->Eof(),buf,0,&all_links,curr_url,&base_href,&ls_options, color);
|
|
Packit |
8f70b4 |
if(n>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ubuf->Skip(n);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ParsePropsFormat(b,len,ubuf->Eof());
|
|
Packit |
8f70b4 |
if(parse_as_html)
|
|
Packit |
8f70b4 |
goto reparse;
|
|
Packit |
8f70b4 |
ubuf->Skip(len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(ubuf->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileAccess::cache->Add(session,curr,mode,session->GetErrorCode(),ubuf);
|
|
Packit |
8f70b4 |
if(mode==FA::MP_LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode=FA::LONG_LIST;
|
|
Packit |
8f70b4 |
ubuf=0;
|
|
Packit |
8f70b4 |
goto retry;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetError(ubuf->ErrorText());
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
HttpDirList::HttpDirList(FileAccess *s,ArgV *a)
|
|
Packit |
8f70b4 |
: DirList(s,a)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode=FA::MP_LIST;
|
|
Packit |
8f70b4 |
parse_as_html=false;
|
|
Packit |
8f70b4 |
#if USE_EXPAT
|
|
Packit |
8f70b4 |
xml_p=0;
|
|
Packit |
8f70b4 |
xml_ctx=0;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
args->rewind();
|
|
Packit |
8f70b4 |
int opt;
|
|
Packit |
8f70b4 |
while((opt=args->getopt("faCFl"))!=EOF)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(opt)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('f'):
|
|
Packit |
8f70b4 |
mode=FA::RETRIEVE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('a'):
|
|
Packit |
8f70b4 |
ls_options.show_all=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('C'):
|
|
Packit |
8f70b4 |
ls_options.multi_column=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('F'):
|
|
Packit |
8f70b4 |
ls_options.append_type=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
while(args->getindex()>1)
|
|
Packit |
8f70b4 |
args->delarg(1); // remove options.
|
|
Packit |
8f70b4 |
if(args->count()<2)
|
|
Packit |
8f70b4 |
args->Append("");
|
|
Packit |
8f70b4 |
args->rewind();
|
|
Packit |
8f70b4 |
curr=0;
|
|
Packit |
8f70b4 |
curr_url=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
HttpDirList::~HttpDirList()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ParsePropsFormat(0,0,true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *HttpDirList::Status()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ubuf && !ubuf->Eof() && session->IsOpen())
|
|
Packit |
8f70b4 |
return xstring::format(_("Getting file list (%lld) [%s]"),
|
|
Packit |
8f70b4 |
(long long)session->GetPos(),session->CurrentStatus());
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void HttpDirList::SuspendInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::SuspendInternal();
|
|
Packit |
8f70b4 |
if(ubuf)
|
|
Packit |
8f70b4 |
ubuf->SuspendSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void HttpDirList::ResumeInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ubuf)
|
|
Packit |
8f70b4 |
ubuf->ResumeSlave();
|
|
Packit |
8f70b4 |
super::ResumeInternal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#undef super
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// HttpListInfo implementation
|
|
Packit |
8f70b4 |
FileSet *HttpListInfo::Parse(const char *b,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==FA::MP_LIST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileSet *fs=ParseProps(b,len,session->GetCwd());
|
|
Packit |
8f70b4 |
if(!fs)
|
|
Packit |
8f70b4 |
mode=FA::LONG_LIST;
|
|
Packit |
8f70b4 |
return fs;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return session->ParseLongList(b,len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileSet *Http::ParseLongList(const char *b,int len,int *err) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
*err=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileSet *set=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(len>5 && !strncmp(b,"
|
|
Packit |
8f70b4 |
set=HttpListInfo::ParseProps(b,len,GetCwd());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!set)
|
|
Packit |
8f70b4 |
set=new FileSet;
|
|
Packit |
8f70b4 |
if(set->count()>0)
|
|
Packit |
8f70b4 |
return set;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ParsedURL prefix(GetConnectURL());
|
|
Packit |
8f70b4 |
xstring_c base_href;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int n=parse_html(b,len,true,Ref<Buffer>::null,set,0,&prefix,&base_href);
|
|
Packit |
8f70b4 |
if(n==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
b+=n;
|
|
Packit |
8f70b4 |
len-=n;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return set;
|
|
Packit |
8f70b4 |
}
|