/* ftpparse.c, ftpparse.h: library for parsing FTP LIST responses
*
* Written by Uwe Ohse, 2002-07-12.
* Strongly influences by Daniel J. Bernsteins ftpparse.c.
*
* placed in the public domain.
*/
/*
* Currently covered:
* EPLF.
* UNIX ls, with or without gid.
* different Windows and DOS FTP servers.
* VMS, but not CMS.
* NetPresenz (Mac).
* NetWare.
*/
#include <time.h> /* gmtime, time_t, time() */
#include "ftpparse.h"
#include "bailout.h"
#include "str.h"
#include "case.h"
#include "utcdate2tai.h"
static int my_byte_equal(const char *s, unsigned int n, const char *t)
{
unsigned int i;
for (i=0;i<n;i++)
if (s[i]!=t[i]) return 0;
return 1;
}
static int
fix_year(unsigned long *year)
{
if (*year<70) *year+=2000;
else if (*year<100) *year+=1900;
else if (*year<1970) return 0;
return 1;
}
/* scan_ulong with bound-check */
static unsigned int
get_ulong(const char *p, unsigned int len, unsigned long *ul)
{
unsigned long u=0;
unsigned int i;
for (i=0;i<len;i++) {
if (p[i]>'9' || p[i]<'0')
break;
u*=10;
u+=p[i]-'0';
}
*ul=u;
return i;
}
static unsigned int
get_uint64(const char *p, unsigned int len, uint64 *ul)
{
uint64 u=0;
unsigned int i;
for (i=0;i<len;i++) {
if (p[i]>'9' || p[i]<'0')
break;
u*=10;
u+=p[i]-'0';
}
*ul=u;
return i;
}
/* UNIX ls does not show the year for dates in the last six months. */
/* So we have to guess the year. */
/* Apparently NetWare uses ``twelve months'' instead of ``six months''; ugh. */
/* Some versions of ls also fail to show the year for future dates. */
static long
guess_year(unsigned long month,unsigned long day)
{
static long this_year;
static struct tai yearstart;
struct tai x;
struct tai now;
tai_now(&now);
if (!this_year) {
struct tai n;
tai_now(&n);
this_year=1970;
while (1) {
utcdate2tai(&yearstart,this_year+1,0,1,0,0,0);
if (tai_less(&n,&yearstart)) break;
this_year++;
}
}
utcdate2tai(&x,this_year,month,day,0,0,0);
if (tai_less(&now,&x))
return this_year-1;
return this_year;
}
static int
getmod (struct tai *t, const unsigned char *p, unsigned int l)
{
unsigned int i;
unsigned long year,mon,day,hour,min,sec;
year=mon=day=hour=min=sec=0;
if (l<14) return 0;
for (i = 0; i < l; i++) {
unsigned int u;
if (p[i]<'0' || p[i]>'9') return 0;
u = (p[i] - '0');
switch (i) {
case 0:
case 1:
case 2:
case 3:
year *= 10;
year += u;
break;
case 4:
case 5:
mon *= 10;
mon += u;
break;
case 6:
case 7:
day *= 10;
day += u;
break;
case 8:
case 9:
hour *= 10;
hour += u;
break;
case 10:
case 11:
min *= 10;
min += u;
break;
case 12:
case 13:
sec *= 10;
sec += u;
break;
}
}
utcdate2tai(t,year,mon-1,day,hour,min,sec);
return 1;
}
static const char *months[12] =
{
"jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"
} ;
static int get_month(char *buf, unsigned int len)
{
int i;
if (len < 3) return -1;
#define CMP(x) \
(months[i][x]==buf[x] || months[i][x]==buf[x]+32)
for (i = 0;i < 12;++i)
if (CMP(0) && CMP(1) && CMP(2))
return i;
return -1;
}
/* see http://cr.yp.to/ftp/list/eplf.html */
static int
parse_eplf(struct ftpparse *f, char *buf, unsigned int len)
{
unsigned int start,pos;
unsigned long ul;
if (buf[0]!='+') return 0;
start=1;
for (pos = 1;pos < len;pos++) {
if ('\t'==buf[pos]) {
f->name=buf+pos+1;
f->namelen=len-pos-1;
if (!f->namelen) return 0; /* huh? */
f->format=FTPPARSE_FORMAT_EPLF;
return 1;
}
if (',' != buf[pos])
continue;
switch(buf[start]) {
case '/': f->flagtrycwd=1; break;
case 'r': f->flagtryretr=1; break;
case 's':
if (pos-start-1==0) return 0;
if (get_uint64(buf+start+1,pos-start-1,&f->size)
!=pos-start-1) return 0;
f->sizetype=FTPPARSE_SIZE_BINARY;
break;
case 'm':
if (pos-start-1==0) return 0;
if (get_ulong(buf+start+1,pos-start-1,&ul)!=pos-start-1) return 0;
tai_unix(&f->mtime,ul);
f->mtimetype = FTPPARSE_MTIME_LOCAL;
break;
case 'i':
/* refuse zero bytes length ids */
if (pos-start-1==0) return 0;
f->idtype = FTPPARSE_ID_FULL;
f->id=buf+start+1;
f->idlen=pos-start-1;
break;
}
start=pos+1;
}
return 0;
}
static int scan_time(const char *buf, const unsigned int len,
unsigned long *h, unsigned long *m, unsigned long *s, int *type)
{
/* 11:48:54 */
/* 01:48:54 */
/* 1:48:54 */
/* 11:48 */
/* 11:48PM */
/* 11:48AM */
/* 11:48:54PM */
/* 11:48:54AM */
unsigned int x;
unsigned int y;
*h=*m=*s=0;
x=get_ulong(buf,len,h);
if (len==x) return 0;
if (!x || x>2) return 0;
if (':' != buf[x]) return 0;
if (len==++x) return 0;
y=get_ulong(buf+x,len-x,m);
if (y!=2) return 0;
x+=y;
if (x!=len && ':' == buf[x]) {
if (len==++x) return 0;
y=get_ulong(buf+x,len-x,s);
if (y!=2) return 0;
x+=y;
*type=FTPPARSE_MTIME_REMOTESECOND;
} else
*type=FTPPARSE_MTIME_REMOTEMINUTE;
if (x!=len && ('A' == buf[x] || 'P' == buf[x])) {
if ('P' == buf [x])
*h+=12;
x++;
if (len==x) return 0;
if ('M' != buf[x]) return 0;
x++;
if (len==x) return 0;
}
if (len==x || buf[x]==' ') return x;
return 0;
}
/* 04-27-00 09:09PM <DIR> licensed */
/* 07-18-00 10:16AM <DIR> pub */
/* 04-14-00 03:47PM 589 readme.htm */
/* note the mon-day-year! */
static int
parse_msdos(struct ftpparse *f, char *buf, unsigned int len)
{
unsigned int pos,start;
unsigned int state;
unsigned long mon;
unsigned long day;
unsigned long year;
unsigned long hour;
unsigned long min;
unsigned long sec;
int mtimetype;
unsigned int x;
uint64 size=0;
unsigned int flagtrycwd=0;
unsigned int flagtryretr=0;
int maxspaces=0; /* to keep leading spaces before dir/file name */
for (state=start=pos=0;pos<len;pos++) {
switch(state) {
case 0: /* month */
if ('-'==buf[pos]) {
state++;
if (pos==start) return 0;
if (get_ulong(buf+start,pos-start,&mon)!=pos-start) return 0;
start=pos+1;
}
break;
case 1: /* day */
if ('-'==buf[pos]) {
state++;
if (pos==start) return 0;
if (get_ulong(buf+start,pos-start,&day)!=pos-start) return 0;
start=pos+1;
}
break;
case 2: /* year */
if (' '==buf[pos]) {
state++;
if (pos-start!=2 && pos-start!=4) return 0;
if (get_ulong(buf+start,pos-start,&year)!=pos-start) return 0;
start=pos+1;
if (!fix_year(&year)) return 0;
}
break;
case 3: /* spaces */
if (' ' == buf[pos]) continue;
state++;
start=pos;
/* FALL THROUGH */
case 4: /* time */
x=scan_time(buf+start,len-pos,&hour,&min,&sec,&mtimetype);
if (!x) return 0;
pos+=x;
if (pos==len) return 0;
state++;
break;
case 5: /* spaces */
if (' ' == buf[pos]) continue;
state++;
start=pos;
/* FALL THROUGH */
case 6: /* <DIR> or length */
if (' ' == buf[pos]) {
if (get_uint64(buf+start,pos-start,&size)!=pos-start) {
if (pos-start < 5
|| !my_byte_equal(buf+start,5,"<DIR>"))
return 0;
flagtrycwd=1;
maxspaces=10;
} else {
flagtryretr=1;
maxspaces=1;
}
state++;
start=pos;
}
break;
case 7: /* spaces */
if (' ' == buf[pos])
if (--maxspaces)
continue;
state++;
start=pos;
/* FALL THROUGH */
case 8: /* file / dir name */
f->name=buf+start;
f->namelen=len-pos;
f->flagtrycwd=flagtrycwd;
f->flagtryretr=flagtryretr;
f->mtimetype=mtimetype;
if (flagtryretr) {
f->size=size;
f->sizetype=FTPPARSE_SIZE_BINARY;
}
if (!fix_year(&year)) return 0;
utcdate2tai(&f->mtime,year,mon-1,day,hour,min,sec);
return 1;
}
}
return 0;
}
#define MAXWORDS 10
static unsigned int
dosplit(char *buf, int len, char *p[], unsigned int l[])
{
unsigned int count=0;
int inword=0;
int pos;
int start;
for (pos=start=0;pos<len;pos++) {
if (inword) {
if (' ' == buf[pos]) {
inword=0;
l[count++]=pos-start;
if (count==MAXWORDS) {
l[count-1]=len-start;
break;
}
}
} else {
if (' ' != buf[pos]) {
inword=1;
start=pos;
p[count]=buf+pos;
}
}
}
if (inword) {
l[count]=buf+pos-p[count];
count++;
}
return count;
}
static int parse_multinet(struct ftpparse *f, char *p[], int l[],
unsigned int count)
{
/* "CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)" */
/* "[VMSSERV.FILES]ALARM.DIR;1 1/3 5-MAR-1993 18:09:" */
int mon;
unsigned long day;
unsigned long year;
unsigned long hour;
unsigned long min;
unsigned long sec;
int mtimetype;
int x;
char *q;
int m;
if (count<4) return 0;
q=p[2];
m=l[2];
x=get_ulong(q,m,&day);
if (!x || x>2 || day>31) return 0;
if (q[x] != '-') return 0;
q+=x+1;
m-=x+1;
mon=get_month(q,m);
if (-1==mon) return 0;
if (q[3]!='-') return 0;
q+=4;
if (m<5) return 0;
m-=4;
x=get_ulong(q,m,&year);
if (!x || q[x]!=' ') return 0;
if (!fix_year(&year)) return 0;
x=scan_time(p[3],l[3],&hour,&min,&sec,&mtimetype);
if (x!=l[3]) return 0;
f->mtimetype = mtimetype;;
utcdate2tai (&f->mtime,year,mon,day,hour,min,sec);
for (x=0;x<l[0];x++)
if (p[0][x]==';')
break;
if (x>4)
if (p[0][x-4]=='.'
&& p[0][x-3]=='D'
&& p[0][x-2]=='I'
&& p[0][x-1]=='R') {
x-=4;
f->flagtrycwd=1;
}
if (!f->flagtrycwd)
f->flagtryretr=1;
f->namelen=x;
f->name=p[0];
if (f->name[0]=='[') {
/* [dir]file.maybe */
unsigned int y;
for (y=1;y<f->namelen;y++)
if (f->name[y]==']')
break;
if (y!=f->namelen) y++; /* skip ] */
if (y!=f->namelen) {
f->name+=y;
f->namelen-=y;
}
}
return 1;
}
static int
parse_unix(struct ftpparse *f, char *buf, int len,
char *p[], int l[], unsigned int count)
{
/* the horror ... */
/* this list has been taken from Daniel Bernsteins ftpparse.c */
/* UNIX-style listing, without inum and without blocks */
/* "-rw-r--r-- 1 root other 531 Jan 29 03:26 README" */
/* "dr-xr-xr-x 2 root other 512 Apr 8 1994 etc" */
/* "dr-xr-xr-x 2 root 512 Apr 8 1994 etc" */
/* "lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin" */
/* Also produced by Microsoft's FTP servers for Windows: */
/* "---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z" */
/* "d--------- 1 owner group 0 May 9 19:45 Softlib" */
/* Also WFTPD for MSDOS: */
/* "-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp" */
/* Also NetWare: */
/* "d [R----F--] supervisor 512 Jan 16 18:53 login" */
/* "- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe" */
/* Also NetPresenz for the Mac: */
/* "-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit" */
/* "drwxrwxr-x folder 2 May 10 1996 network" */
/*restructured: */
/* -PERM 1 user group 531 Jan 29 03:26 README */
/* dPERM 2 user group 512 Apr 8 1994 etc */
/* dPERM 2 user 512 Apr 8 1994 etc */
/* lPERM 1 user group 7 Jan 25 00:17 bin -> usr/bin */
/* -PERM 1 user group 1803128 Jul 10 10:18 ls-lR.Z */
/* dPERM 1 user group 0 May 9 19:45 Softlib */
/* -PERM 1 user group 322 Aug 19 1996 message.ftp */
/* d [R----F--] user 512 Jan 16 18:53 login */
/* - [R----F--] user 214059 Oct 20 15:27 cx.exe */
/* -PERM 326 NUMB NUMBER Nov 22 1995 MegaPhone.sit */
/* dPERM folder 2 May 10 1996 network */
/* handled as: */
/* dPERM folder 2 May 10 1996 network */
/* 0 1 2 3 4 5 6 7 8 */
/* note the date system: MON DAY [YEAR|TIME] */
int mon=-1; /* keep gcc quiet */
unsigned long day;
unsigned long year;
unsigned long hour;
unsigned long min;
unsigned long sec;
uint64 size;
int flagtrycwd=0;
int flagtryretr=0;
unsigned int i;
int x;
int mtimetype;
int may_have_size=0;
switch(p[0][0]) {
case 'd': flagtrycwd=1; break;
case '-': flagtryretr=1; break;
case 'l': flagtryretr=flagtrycwd=1; break;
}
i=3;
if (l[1]==6 && my_byte_equal(p[1],l[1],"folder"))
i=2;
x=get_uint64(p[i],l[i],&size);
if (x==l[i]) may_have_size=1;
i++;
while (i<count) {
mon=get_month(p[i],l[i]);
if (-1==mon) {
/* may be size */
x=get_uint64(p[i],l[i],&size);
if (x==l[i]) may_have_size=1;
}
i++;
if (-1!=mon) break;
}
if (i==count) return 0;
x=get_ulong(p[i],l[i],&day);
if (!x) return 0;
if (p[i][x]!=' ') return 0;
if (++i==count) return 0;
x=get_ulong(p[i],l[i],&year);
if (!x) return 0;
if (p[i][x]==':') {
x=scan_time(p[i],l[i],&hour,&min,&sec,&mtimetype);
if (x!=l[i]) return 0;
year=guess_year(mon,day);
} else {
mtimetype=FTPPARSE_MTIME_REMOTEDAY;
hour=min=sec=0;
/* may be this case: */
/* - [-RWCE-F-] mlm 11820 Feb 3 93 12:00 drivers.doc */
if (i+2<count) {
x=scan_time(p[i+1],l[i+1],&hour,&min,&sec,&mtimetype);
if (x!=l[i+1]) {
hour=min=sec=0;
mtimetype=FTPPARSE_MTIME_REMOTEDAY;
} else
i++;
}
if (!fix_year(&year)) return 0;
}
if (++i==count) return 0;
/* note: dosplit eats spaces - but we need them here. So go back. */
f->name=p[i];
f->namelen=buf+len-p[i];
/* "-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp" */
/* "-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 spacy" */
/* but: */
/* "d [R----F--] supervisor 512 Jan 16 18:53 login" */
if (p[0][1]!=' ') {
while (f->name[-2]==' ') {
f->name--;
f->namelen++;
}
}
if (may_have_size) {
f->sizetype=FTPPARSE_SIZE_BINARY;
f->size=size;
}
f->flagtryretr=flagtryretr;
f->flagtrycwd=flagtrycwd;
utcdate2tai (&f->mtime,year,mon,day,hour,min,sec);
f->mtimetype=mtimetype;
f->format=FTPPARSE_FORMAT_LS; /* for programs dealing with symlinks */
if ('l'==*buf) {
unsigned int j;
for (j=1;j<f->namelen-4;j++) /* 1, -4: no empty names, please */
if (f->name[j]==' '
&& f->name[j+1]=='-'
&& f->name[j+2]=='>'
&& f->name[j+3]==' ') {
f->symlink=f->name+j+4;
f->symlinklen=f->namelen-j-4;
f->namelen=j;
break;
}
}
return 1;
}
static int parse_supertcp(struct ftpparse *f, char *p[], int l[],
unsigned int count)
{
unsigned long mon;
unsigned long day;
unsigned long year;
unsigned long hour;
unsigned long min;
unsigned long sec;
int mtimetype;
uint64 size=0; /* optional, dirs */
int x;
int dir=0;
/* CMT <DIR> 11-21-94 10:17 */
/* DESIGN1.DOC 11264 05-11-95 14:20 */
if (count<4) return 0;
x=scan_time(p[3],l[3],&hour,&min,&sec,&mtimetype);
if (x!=l[3]) return 0;
x=get_ulong(p[2],l[2],&mon);
if (x!=2 || p[2][x]!='-') return 0;
x++;
x+=get_ulong(p[2]+x,l[2]-x,&day);
if (x!=5 || p[2][x]!='-') return 0;
x++;
x+=get_ulong(p[2]+x,l[2]-x,&year);
if ((x!=8 && x!=10) || p[2][x]!=' ') return 0;
if (!fix_year(&year)) return 0;
if (my_byte_equal(p[1],5,"<DIR>"))
dir=1;
else {
x=get_uint64(p[1],l[1],&size);
if (!x || p[1][x]!=' ') return 0;
}
f->name=p[0];
f->namelen=l[0];
f->size=size;
if (!dir)
f->sizetype=FTPPARSE_SIZE_BINARY;
utcdate2tai (&f->mtime,year,mon,day,hour,min,sec);
f->mtimetype=mtimetype;
if (dir) f->flagtrycwd=1;
else f->flagtryretr=1;
return 1;
}
/* another bright re-invention of a broken wheel from the people, who
* made an art of it.
*/
static int
parse_os2(struct ftpparse *f, char *p[], int l[],
unsigned int count)
{
/* 0 DIR 04-11-95 16:26 ADDRESS
* 612 A 07-28-95 16:45 air_tra1.bag
* 310992 06-28-94 09:56 INSTALL.EXE
*/
unsigned long mon;
unsigned long day;
unsigned long year;
unsigned long hour;
unsigned long min;
unsigned long sec;
int mtimetype;
uint64 size;
int x;
unsigned int i;
int dir=0;
if (count<4) return 0;
x=get_uint64(p[0],l[0],&size);
if (!x || p[0][x]!=' ') return 0;
for (i=1; i<count-2; i++) {
x=get_ulong(p[i],l[i],&mon);
if (!x) continue;
if (x!=2 || p[i][x]!='-') return 0;
mon-=1;
x++;
x+=get_ulong(p[i]+x,l[i]-x,&day);
if (x!=5 || p[i][x]!='-') return 0;
x++;
x+=get_ulong(p[i]+x,l[i]-x,&year);
if (x!=8 || p[i][x]!=' ') return 0;
if (!fix_year(&year)) return 0;
break;
}
if (i>1)
if (my_byte_equal(p[i-1],3,"DIR"))
dir=1;
i++;
if (i==count) return 0;
x=scan_time(p[i],l[i],&hour,&min,&sec,&mtimetype);
if (x!=l[i]) return 0;
i++;
if (i==count) return 0;
f->name=p[i];
f->namelen=l[i];
if (dir) {
f->flagtrycwd=1;
} else {
f->flagtryretr=1;
f->sizetype=FTPPARSE_SIZE_BINARY;
f->size=size;
}
utcdate2tai (&f->mtime,year,mon,day,hour,min,sec);
f->mtimetype=mtimetype;
return 1;
}
#define SETUP() do {\
fp->name = 0; \
fp->namelen = 0; \
fp->flagtrycwd = 0; \
fp->flagtryretr = 0; \
fp->sizetype = FTPPARSE_SIZE_UNKNOWN; \
fp->size = 0; \
fp->mtimetype = FTPPARSE_MTIME_UNKNOWN; \
tai_uint(&fp->mtime,0); \
fp->idtype = FTPPARSE_ID_UNKNOWN; \
fp->id = 0; \
fp->idlen = 0; \
fp->format = FTPPARSE_FORMAT_UNKNOWN; \
fp->flagbrokenmlsx=0; \
fp->symlink=0; \
fp->symlinklen=0; \
} while(0)
int
ftpparse_mlsx (struct ftpparse *fp, char *x, int ll, int is_mlst)
{
int i;
uint64 size;
struct tai mtime;
int flagtryretr=0;
int flagtrycwd=0;
char *id=0;
int idlen=0;
int mtimetype=FTPPARSE_MTIME_UNKNOWN;
int sizetype=FTPPARSE_SIZE_UNKNOWN;
int flagbrokenmlsx=0;
SETUP();
if (is_mlst)
if (ll>1) {
ll--;
x++;
}
if (ll<2) /* empty facts, space, one-byte-filename */
return 0;
for (i=0; i<ll;i++) {
int j=0,k=0;
if (x[i]==' ')
break; /* end of facts */
while (i+j<ll && x[i+j]!=';' && x[i+j]!=' ' && x[i+j]!='=')
j++;
if (i+j==ll)
return 0;
if (x[i+j]==' ')
return 0;
if (x[i+j]==';')
return 0;
/* x[i+j] is now '=' */
while (i+j+k<ll && x[i+j+k]!=';' && x[i+j+k]!=' ')
k++;
if (i+j+k==ll)
return 0;
/* x[i+j+k] is space or semicolon, so use of getlong is safe */
#define ISFACT(name) (j==sizeof(name)-1 && case_startb(x+i,j,name))
if (ISFACT ("size")) {
get_uint64 (x + i + j + 1, k - 1,&size);
sizetype=FTPPARSE_SIZE_BINARY;
} else if (ISFACT ("modify")) {
getmod(&mtime,x + i + j + 1, k - 1);
mtimetype = FTPPARSE_MTIME_LOCAL;
} else if (ISFACT ("type")) {
if (k==5 && case_startb (x + i + j + 1, 4, "file"))
flagtryretr = 1;
else if (case_startb (x + i + j + 1, 3, "dir")) /* "current" */
flagtrycwd = 1;
else if (case_startb (x + i + j + 1, 4, "pdir")) /* "parent" */
flagtrycwd = 1;
else if (case_startb (x + i + j + 1, 4, "cdir"))
flagtrycwd = 1;
else {
flagtryretr = 1;
flagtrycwd = 1;
}
} else if (ISFACT ("unique")) {
id = x + i + j + 1;
idlen = k - 1;
}
i+=j+k;
if (x[i]==' ') {
flagbrokenmlsx=1;
break;
}
}
if (ll==i) return 0;
i++;
if (ll==i) return 0;
fp->name = x + i;
fp->namelen = ll - i;
fp->sizetype = sizetype;
fp->size=size;
fp->mtimetype = mtimetype;
fp->mtime=mtime;
fp->flagtrycwd=flagtrycwd;
fp->flagtryretr=flagtryretr;
if (id) {
fp->idtype = FTPPARSE_ID_FULL;
fp->id=id;
fp->idlen=idlen;
}
fp->flagbrokenmlsx=flagbrokenmlsx;
fp->format=FTPPARSE_FORMAT_MLSX;
return 1;
}
static int
ftpparse_int(struct ftpparse *fp,char *buf,int len)
{
unsigned int count;
char *p[MAXWORDS];
int l[MAXWORDS];
SETUP();
if (len < 2) /* an empty name in EPLF, with no info, could be 2 chars */
return 0;
/* cheap cases first */
switch (*buf) {
case '+':
if (parse_eplf(fp,buf,len))
return 1;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (parse_msdos(fp,buf,len)) return 1;
break;
}
count=dosplit(buf, len, p,l);
switch(*buf) {
case 'b': case 'c': case 'd': case 'l':
case 'p': case 's': case '-':
if (parse_unix(fp,buf,len,p,l,count)) return 1;
break;
}
if (*buf==' ') {
switch(p[0][0]) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (parse_os2(fp,p,l,count)) return 1;
break;
}
}
if (parse_multinet(fp,p,l,count)) return 1;
if (parse_supertcp(fp,p,l,count)) return 1;
return 0;
}
int
ftpparse(struct ftpparse *fp,char *buf,int len, int eat_leading_spaces)
{
int x=ftpparse_int(fp,buf,len);
if (!x) return x;
if (eat_leading_spaces && fp->format!=FTPPARSE_FORMAT_EPLF
&& fp->format!=FTPPARSE_FORMAT_MLSX)
while (fp->namelen > 1 && fp->name[0]==' ') {
/* leave at least a " " in the name */
fp->name++;
fp->namelen--;
}
return x;
}
syntax highlighted by Code2HTML, v. 0.9.1