2005/5/9

     
 

FTPFileSystem.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_net/src/acdk/net/ftp/FTPFileSystem.cpp,v 1.7 2005/03/17 12:36:06 kommer Exp $

#include "FTPFileSystem.h"
#include "FTPFileImpl.h"


namespace acdk {
namespace net {
namespace ftp {

using namespace acdk::net;

FTPFileSystem::FTPFileSystem(IN(RString) url)
: _cache(new acdk::io::FileInfoArray(0))
{
  ACDK_SAFE_CONSTRUCTOR();
  _rootUrl = new URL(url);
  _rootUrl->setFile("");
  _connect();
  FileSystem::registerFileSystem(this);
}

FTPFileSystem::FTPFileSystem(IN(RURL) url)
: _cache(new acdk::io::FileInfoArray(0))
{
  ACDK_SAFE_CONSTRUCTOR();
  _rootUrl = url;
  _connect();
  FileSystem::registerFileSystem(this);
}

FTPFileSystem::~FTPFileSystem()
{
}

RFTPClient 
FTPFileSystem::getClient() 
{ 
  if (_client == Nil)
    _connect();
  return _client; 
}



bool 
FTPFileSystem::ownsFile(IN(RString) fname)
{
  if (fname->startsWith("ftp://") == false)
    return false;
  // convert to url to retrive the default port
  URL url(fname);
  RString ustr = url.toString();
  RString str = toString();
  
  if (ustr->startsWith(str) == true)
    return true;
  return false;
}

RString 
FTPFileSystem::getRootName()
{
  return _rootUrl->toExternalForm();
}

RFileArray 
FTPFileSystem::listFiles(IN(RString) directory, int listflags)
{
  RString ndir = directory;
  if (ndir->startsWith("/") == false)
    ndir = "/" + ndir;
  if (_client->setCwd(ndir) == false)
    return new FileArray(0);
  //### @todo support listflags
  RFileInfoArray arr = _client->listFileInfos();
  RFileArray fa = new FileArray(arr->length());
  for (int i = 0; i < arr->length(); ++i)
  {
    fa[i] = new File(new FTPFileImpl(this, arr[i]));
  }
  return fa;
}

RFile 
FTPFileSystem::file(IN(RString) path)
{
  return Nil;
}
  
RFileImpl 
FTPFileSystem::getFileImpl(IN(RString) fqpath)
{
  RString relname = fqpath;
  if (fqpath->startsWith("ftp://") == true)
    relname = fqpath->substr(6);
  int idx = relname->indexOf('/');
  if (idx == -1) // is root
  {
    return new FTPFileImpl(this, new FileInfo(FileInfoExists | FileInfoIsDir | FileInfoCanRead | FileInfoCanWrite, "", ""));
  }
  relname = relname->substr(idx + 1);
  return new FTPFileImpl(this, _getFileInfo(relname));
}

void
FTPFileSystem::_connect()
{
  _client = new FTPClient();
  int port = _rootUrl->getPort();
  if (port == -1)
    port = 21;
  _client->connect(_rootUrl->getHost(), port);
  RString user = _rootUrl->getUser();
  RString pass = _rootUrl->getPassword();
  if (user == Nil)
  {
    user = "ftp";
    pass = "anon@anon";
  }
  _client->login(user, pass);
  /*
  RString f = _rootUrl->getFile();
  if (f != Nil && f->length() > 0)
    _client->setCwd(f);
  */
}

acdk::io::RFileInfo 
FTPFileSystem::_findFileInfoFromCache(IN(RString) file)
{
  for (int i = 0; i < _cache->length(); ++i)
    if (_cache[i]->getPath()->equals(file) == true)
      return _cache[i];
  return Nil;
}

void 
FTPFileSystem::removeFromCache(IN(RFileInfo) fi)
{
  for (int i = 0; i < _cache->length(); ++i)
  {
    if (_cache[i]->equals(fi) == true)
    {
      _cache->remove(i);
      return;
    }
  }
}

acdk::io::RFileInfo 
FTPFileSystem::_getFileInfo(IN(RString) file)
{
  RFileInfo fi = _findFileInfoFromCache(file);
  if (fi != Nil)
    return fi;
  int idx = file->lastIndexOf('/');
  RString ncwd = "/";
  if (idx != -1)
    ncwd = file->substr(0, idx);
  if (_client->setCwd(ncwd) == false)
    return Nil;
  RFileInfoArray arr = _client->listFileInfos();
  RString nfile = file;
  if (file->startsWith("/") == false)
    nfile = "/" + file;
  // ### todo add to cache
  for (int i = 0; i < arr->length(); ++i)
  {
    RFileInfo fi = arr[i];
    RString fipath = fi->getPath();
    if (File::separatorChar() != '/') 
      fipath = fipath->replace(File::separatorChar(), '/');
    if (fipath->startsWith("/") == false)
      fipath = "/" + fipath;

    if (fipath->equals(nfile) == true)
      return arr[i];
  }
  fi = new FileInfo();
  if (idx != -1)
  {
    fi->name = file->substr(idx + 1);
    fi->dir = ncwd;
  }
  else
    fi->name = file;
  return fi;
}


RFileSystem 
FTPFileSystemFactory::create(IN(RString) file)
{
  return new FTPFileSystem(file);
}

ACDK_REGISTER_FILESYSTEM(FTPFileSystemFactory);


} // namespace ftp
} // namespace acdk
} // namespace net