/*  This file is part of the KDE project
    Copyright (C) 2000,2001 Alexander Neundorf <neundorf@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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 GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <kdebug.h>
#include <tdelocale.h>
#include <tdeinstance.h>
#include <tdeconfig.h>
#include <tdeglobal.h>
#include <tdeprocess.h>

#include <tqfile.h>

#include <iostream>
#include <string.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <pwd.h>

#include "tdeio_lan.h"

#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#endif

#define PORTSETTINGS_CHECK 0
#define PORTSETTINGS_PROVIDE 1
#define PORTSETTINGS_DISABLE 2

using namespace TDEIO;

#ifndef SHUT_RDWR
#define SHUT_RDWR 2
#endif

extern "C" { TDE_EXPORT int kdemain(int argc, char **argv); }

int kdemain( int argc, char **argv )
{
  TDEInstance instance( "tdeio_lan" );

  if (argc != 4)
  {
     fprintf(stderr, "Usage: tdeio_lan protocol domain-socket1 domain-socket2\n");
     exit(-1);
  }
  int isLanIoslave=(strcmp("lan",argv[1])==0);

  // Trigger creation to make sure we pick up KIOSK settings correctly.
  (void)TDEGlobal::dirs();
  (void)TDEGlobal::locale();
  (void)TDEGlobal::config();

  kdDebug(7101) << "LAN: kdemain: starting" << endl;

  LANProtocol slave(isLanIoslave, argv[2], argv[3]);
  slave.dispatchLoop();
  return 0;
}

LANProtocol::LANProtocol(int isLanIoslave, const TQCString &pool, const TQCString &app )
:TCPSlaveBase(7741,isLanIoslave?"lan":"rlan", pool, app)
,m_currentHost("")
,m_port(7741)
,m_maxAge(15*60)
,m_isLanIoslave(isLanIoslave?true:false)
{
   TDEConfig *config=TDEGlobal::config();

   m_protocolInfo[KIOLAN_FTP].enabled=config->readNumEntry("Support_FTP",PORTSETTINGS_CHECK);
   m_protocolInfo[KIOLAN_HTTP].enabled=config->readNumEntry("Support_HTTP",PORTSETTINGS_CHECK);
   m_protocolInfo[KIOLAN_NFS].enabled=config->readNumEntry("Support_NFS",PORTSETTINGS_CHECK);
   m_protocolInfo[KIOLAN_SMB].enabled=config->readNumEntry("Support_SMB",PORTSETTINGS_CHECK);
   m_protocolInfo[KIOLAN_FISH].enabled=config->readNumEntry("Support_FISH",PORTSETTINGS_CHECK);

   m_defaultLisaHost=config->readEntry("DefaultLisaHost", "localhost");
   m_shortHostnames=config->readBoolEntry("ShowShortHostnames",false);
   m_maxAge=config->readNumEntry("MaxAge",15)*60;
   if (m_maxAge<0) m_maxAge=0;

   strcpy(m_protocolInfo[KIOLAN_NFS].name,"NFS");
   strcpy(m_protocolInfo[KIOLAN_FTP].name,"FTP");
   strcpy(m_protocolInfo[KIOLAN_SMB].name,"SMB");
   strcpy(m_protocolInfo[KIOLAN_HTTP].name,"HTTP");
   strcpy(m_protocolInfo[KIOLAN_FISH].name,"FISH");

   // Now we check for port 445 for SMB/CIFS also.  But we call both entries
   // SMB.  Clients will see only one SMB folder, though, whichever
   // port (or both) is detected.  The smb ioslave should be able
   // to figure out which port to actually use.

   m_protocolInfo[KIOLAN_NFS].ports.push_back(2049);
   m_protocolInfo[KIOLAN_FTP].ports.push_back(21);
   m_protocolInfo[KIOLAN_SMB].ports.push_back(445);
   m_protocolInfo[KIOLAN_SMB].ports.push_back(139);
   m_protocolInfo[KIOLAN_HTTP].ports.push_back(80);
   m_protocolInfo[KIOLAN_FISH].ports.push_back(22);

   m_hostInfoCache.setAutoDelete(true);
}

LANProtocol::~LANProtocol()
{
   m_hostInfoCache.clear();
}

int LANProtocol::readDataFromServer()
{
   if (m_isLanIoslave)
      return lanReadDataFromServer();
   else
      return rlanReadDataFromServer();
   return 0;
}

int LANProtocol::lanReadDataFromServer()
{
   kdDebug(7101)<<"LANProtocol::lanReadDataFromServer() host: "<<m_currentHost<<" port: "<<m_port<<endl;
   if (!connectToHost(m_currentHost.latin1(), m_port, false))
   {
      error(ERR_SLAVE_DEFINED, i18n("<qt>The Lisa daemon does not appear to be running.<p>"
                                    "In order to use the LAN Browser the Lisa daemon must be "
                                    "installed and activated by the system administrator."));
      return 0;
   }
   kdDebug(7101)<<"LANProtocol::lanReadDataFromServer() connected"<<endl;

   int receivedBytes(0);
   char* receiveBuffer(0);
   char tmpBuf[64*1024];
   int bytesRead(0);
   do
   {
      fd_set tmpFDs;
      FD_ZERO(&tmpFDs);
      FD_SET(m_iSock,&tmpFDs);
      timeval tv;
      tv.tv_sec = 1;
      tv.tv_usec = 0;
      select(m_iSock+1,&tmpFDs,0,0,&tv);
      if (FD_ISSET(m_iSock,&tmpFDs))
      {
         bytesRead=read(tmpBuf,64*1024);
         kdDebug(7101)<<"LANProtocol::lanReadDataFromServer: read "<<bytesRead<<" bytes"<<endl;

         if (bytesRead>0)
         {
            char *newBuf=new char[receivedBytes+bytesRead];
            if (receiveBuffer!=0) memcpy(newBuf,receiveBuffer,receivedBytes);
            memcpy(newBuf+receivedBytes,tmpBuf,bytesRead);
            receivedBytes+=bytesRead;
            if (receiveBuffer!=0) delete [] receiveBuffer;
            receiveBuffer=newBuf;
         }
      }
   } while (bytesRead>0);
   closeDescriptor();
   if ((bytesRead<0) || (receivedBytes<4))
   {
      delete [] receiveBuffer;
      error(ERR_INTERNAL_SERVER,i18n("Received unexpected data from %1").arg(m_currentHost));
      return 0;
   }

   UDSEntry entry;

   char *currentBuf=receiveBuffer;
   int bytesLeft=receivedBytes;
   //this should be large enough for a name
   char tmpName[4*1024];
   //this should be large enough for the hostname
   char tmpHostname[4*1024];
   while (bytesLeft>0)
   {
      int tmpIP=2;
      tmpName[0]='\0';
      if ((memchr(currentBuf,0,bytesLeft)==0) || (memchr(currentBuf,int('\n'),bytesLeft)==0))
      {
         delete [] receiveBuffer;
         error(ERR_INTERNAL_SERVER,i18n("Received unexpected data from %1").arg(m_currentHost));
         return 0;
      }
      kdDebug(7101)<<"LANProtocol::lanReadDataFromServer: processing "<<currentBuf;
      //since we check for 0 and \n with memchr() we can be sure
      //at this point that tmpBuf is correctly terminated
      int length=strlen(currentBuf)+1;
      if (length<(4*1024))
         sscanf(currentBuf,"%u %s\n",&tmpIP,tmpName);
      else
      {
        kdDebug(7101)<<"LANProtocol::lanReadDataFromServer:  buffer overflow attempt detected, aborting"<<endl;
        break;
      }

      bytesLeft-=length;
      currentBuf+=length;
      if ((bytesLeft==0) && ((tmpIP==0) ||(tmpIP==1)) && (strstr(tmpName,"succeeded")!=0))
      {
         kdDebug(7101)<<"LANProtocol::lanReadDataFromServer: succeeded"<<endl;
      }
      else if (tmpIP!=2)
      {
         kdDebug(7101)<<"LANProtocol::lanReadDataFromServer: listing host: "<<tmpName<<" with ip: "<<tmpIP<<endl;
         UDSAtom atom;

         atom.m_uds = TDEIO::UDS_NAME;
         if (m_shortHostnames)
         {
            if (inet_addr(tmpName)!=-1)
               atom.m_str=tmpName;
            else
            {
               sscanf(tmpName,"%[^.]",tmpHostname);
               kdDebug(7101)<<"LANProtocol::lanReadDataFromServer: Hostname of " << tmpName <<  " is " << tmpHostname << "\n";
               atom.m_str = tmpHostname;
            }
         }
         else
            atom.m_str = tmpName;

         entry.append( atom );
         atom.m_uds = TDEIO::UDS_SIZE;
         atom.m_long = 1024;
         entry.append(atom);
         atom.m_uds = TDEIO::UDS_ACCESS;
         atom.m_long = S_IRUSR | S_IRGRP | S_IROTH ;
         //atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
         entry.append(atom);
         atom.m_uds = TDEIO::UDS_FILE_TYPE;
         atom.m_long = S_IFDIR; // it is always a directory
         entry.append( atom );
         listEntry(entry,false);
      }
   }

   listEntry( entry, true ); // ready
   delete [] receiveBuffer;
   return 1;
}

int LANProtocol::rlanReadDataFromServer()
{
   kdDebug(7101)<<"RLANProtocol::readDataFromServer"<<endl;

   int sockFD=socket(AF_LOCAL, SOCK_STREAM, 0);
   sockaddr_un addr;
   memset((char*)&addr,0,sizeof(addr));
   addr.sun_family=AF_LOCAL;
   TQCString socketname="/tmp/resLisa-";

   struct passwd *user = getpwuid( getuid() );
   if ( user )
      socketname+=user->pw_name;
   else
      //should never happen
      socketname+="???";

   strlcpy(addr.sun_path,socketname,sizeof(addr.sun_path));
   int result=::connect(sockFD,(sockaddr*)&addr, sizeof(addr));

   kdDebug(7101)<<"readDataFromServer(): result: "<<result<<" name: "<<addr.sun_path<<" socket: "<<sockFD<<endl;

   if (result!=0)
   {
      ::close(sockFD);
      TDEProcess proc;
      proc<<"reslisa";

      bool ok=proc.start(TDEProcess::DontCare);
      if (!ok)
      {
         error( ERR_CANNOT_LAUNCH_PROCESS, "reslisa" );
         return 0;
      }
      //wait a moment
      //reslisa starts tde-config, then does up to 64
      //name lookups and then starts to ping
      //results won't be available before this is done
      kdDebug(7101)<<"sleeping..."<<endl;
      ::sleep(1);
      kdDebug(7101)<<"sleeping again..."<<endl;
      ::sleep(5);
      kdDebug(7101)<<"woke up "<<endl;
      sockFD=socket(AF_LOCAL, SOCK_STREAM, 0);

      memset((char*)&addr,0,sizeof(addr));
      addr.sun_family=AF_LOCAL;
      strlcpy(addr.sun_path,socketname,sizeof(addr.sun_path));

      kdDebug(7101)<<"connecting..."<<endl;
      result=::connect(sockFD,(sockaddr*)&addr, sizeof(addr));
      kdDebug(7101)<<"readDataFromServer() after starting reslisa: result: "<<result<<" name: "<<addr.sun_path<<" socket: "<<sockFD<<endl;
      if (result!=0)
      {
         error( ERR_CANNOT_OPEN_FOR_READING, socketname );
         return 0;
      }
      kdDebug(7101)<<"succeeded :-)"<<endl;
   }

   int receivedBytes(0);
   char* receiveBuffer(0);
   char tmpBuf[64*1024];
   int bytesRead(0);
   do
   {
      fd_set tmpFDs;
      FD_ZERO(&tmpFDs);
      FD_SET(sockFD,&tmpFDs);
      timeval tv;
      tv.tv_sec = 1;
      tv.tv_usec = 0;
      select(sockFD+1,&tmpFDs,0,0,&tv);
      if (FD_ISSET(sockFD,&tmpFDs))
      {
         bytesRead=::read(sockFD,tmpBuf,64*1024);
         kdDebug(7101)<<"RLANProtocol::readDataFromServer: read "<<bytesRead<<" bytes"<<endl;

         if (bytesRead>0)
         {
            char *newBuf=new char[receivedBytes+bytesRead];
            if (receiveBuffer!=0) memcpy(newBuf,receiveBuffer,receivedBytes);
            memcpy(newBuf+receivedBytes,tmpBuf,bytesRead);
            receivedBytes+=bytesRead;
            if (receiveBuffer!=0) delete [] receiveBuffer;
            receiveBuffer=newBuf;
         }
      }
   } while (bytesRead>0);
   ::close(sockFD);


   if ((bytesRead<0) || (receivedBytes<4))
   {
      delete [] receiveBuffer;
      error(ERR_CANNOT_OPEN_FOR_READING,socketname);
      return 0;
   }

   UDSEntry entry;

   char *currentBuf=receiveBuffer;
   int bytesLeft=receivedBytes;
   //this should be large enough for a name
   char tmpName[4*1024];
   //this should be large enough for the hostname
   char tmpHostname[4*1024];
   while (bytesLeft>0)
   {
      int tmpIP=2;
      tmpName[0]='\0';
      if ((memchr(currentBuf,0,bytesLeft)==0) || (memchr(currentBuf,int('\n'),bytesLeft)==0))
      {
         delete [] receiveBuffer;
         error(ERR_INTERNAL_SERVER,i18n("Received unexpected data from %1").arg(socketname.data()));
         return 0;
      }
      kdDebug(7101)<<"RLANProtocol::readDataFromServer: processing "<<currentBuf;
      //since we check for 0 and \n with memchr() we can be sure
      //at this point that tmpBuf is correctly terminated
      int length=strlen(currentBuf)+1;
      if (length<(4*1024))
         sscanf(currentBuf,"%u %s\n",&tmpIP,tmpName);
      else
      {
        kdDebug(7101)<<"RLANProtocol::readDataFromServer:  buffer overflow attempt detected, aborting"<<endl;
        break;
      }

      bytesLeft-=length;
      currentBuf+=length;
      if ((bytesLeft==0) && ((tmpIP==0) ||(tmpIP==1)) && (strstr(tmpName,"succeeded")!=0))
      {
         kdDebug(7101)<<"RLANProtocol::readDataFromServer: succeeded"<<endl;
      }
      else if (tmpIP!=2)
      {
         kdDebug(7101)<<"RLANProtocol::readDataFromServer: listing host: "<<tmpName<<" with ip: "<<tmpIP<<endl;
         UDSAtom atom;

         atom.m_uds = TDEIO::UDS_NAME;
         if (m_shortHostnames)
         {
            if (inet_addr(tmpName)!=-1)
               atom.m_str=tmpName;
            else
            {
               sscanf(tmpName,"%[^.]",tmpHostname);
               kdDebug(7101)<<"LANProtocol::lanReadDataFromServer: Hostname of " << tmpName <<  " is " << tmpHostname << "\n";
               atom.m_str = tmpHostname;
            }
         }
         else
            atom.m_str = tmpName;
         entry.append( atom );
         atom.m_uds = TDEIO::UDS_SIZE;
         atom.m_long = 1024;
         entry.append(atom);
         atom.m_uds = TDEIO::UDS_ACCESS;
         atom.m_long = S_IRUSR | S_IRGRP | S_IROTH ;
         //atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
         entry.append(atom);
         atom.m_uds = TDEIO::UDS_FILE_TYPE;
         atom.m_long = S_IFDIR; // it is always a directory
         entry.append( atom );
         listEntry(entry,false);
      }
   }

   listEntry( entry, true ); // ready
   delete [] receiveBuffer;
   return 1;
}

int LANProtocol::checkHost(const TQString& host)
{
   kdDebug(7101)<<"LAN::checkHost() "<<host<<endl;

   TQString hostUpper=host.upper();
   HostInfo* hostInfo=m_hostInfoCache[hostUpper];
   if (hostInfo!=0)
   {
      kdDebug(7101)<<"LAN::checkHost() getting from cache"<<endl;
      //this entry is too old, we delete it !
      if ((time(0)-hostInfo->created)>m_maxAge)
      {
         kdDebug(7101)<<"LAN::checkHost() cache content too old, deleting it"<<endl;
         m_hostInfoCache.remove(hostUpper);
         hostInfo=0;
      }
   }
   if (hostInfo==0)
   {
      hostInfo=new HostInfo;
      in_addr ip;

      struct hostent *hp=gethostbyname(host.latin1());
      if (hp==0)
      {
         error( ERR_UNKNOWN_HOST, host.latin1() );
         delete hostInfo;
         return 0;
      }
      memcpy(&ip, hp->h_addr, sizeof(ip));

      for (int i=0; i<KIOLAN_MAX; i++)
      {
         int result(0);
         if (m_protocolInfo[i].enabled==PORTSETTINGS_DISABLE)
            result=0;
         else if (m_protocolInfo[i].enabled==PORTSETTINGS_PROVIDE)
            result=1;
         else if (m_protocolInfo[i].enabled==PORTSETTINGS_CHECK)
            result=checkPort(m_protocolInfo[i].ports,ip);

         //host not reachable
         if (result==-1)
         {
            delete hostInfo;
            hostInfo=0;
            error( ERR_UNKNOWN_HOST, host.latin1() );
            return 0;
         }
         hostInfo->services[i]=result;
      }
      hostInfo->created=time(0);
      m_hostInfoCache.insert(hostUpper,hostInfo);
   }
   //here hostInfo is always != 0
   if (hostInfo==0)
   {
      error( ERR_INTERNAL, "hostInfo==0" );
      return 0;
   }

   UDSEntry entry;
   for (int i=0; i<KIOLAN_MAX; i++)
   {
      if (hostInfo->services[i]==1)
      {
         kdDebug(7101)<<"LAN::checkHost(): Host ["<<hostUpper<<"] Service ["<<m_protocolInfo[i].name<<"]"<<endl;
         UDSAtom atom;
         // name
         atom.m_uds = TDEIO::UDS_NAME;
         atom.m_str = m_protocolInfo[i].name;
         entry.append( atom );
         // size
         atom.m_uds = TDEIO::UDS_SIZE;
         atom.m_long = 1024;
         entry.append(atom);
         // access permissions
         atom.m_uds = TDEIO::UDS_ACCESS;
         atom.m_long = S_IRUSR | S_IRGRP | S_IROTH ;
         //atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
         entry.append(atom);
         // file type
         atom.m_uds = TDEIO::UDS_FILE_TYPE;
         if (strcmp(m_protocolInfo[i].name,"HTTP")==0)
         {
            // normal file -- if we called stat(2) on this,
            // this flag would be set in the st_mode field of struct stat
            atom.m_long=S_IFREG;
            entry.append(atom);

            // also define the mime-type for this file
            atom.m_uds = TDEIO::UDS_MIME_TYPE;
            atom.m_str="text/html";
            entry.append( atom );
         }
         else
         {
            // directory -- if we called stat(2) on this, then this
            // flag would be set in the st_mode field of the struct stat
            atom.m_long = S_IFDIR; // it is always a directory
            entry.append(atom);

            // also set the mime-type
            atom.m_uds = TDEIO::UDS_MIME_TYPE;
            atom.m_str="inode/directory";
            entry.append( atom );
         }
         listEntry(entry,false);
      }
   }
   listEntry( entry, true ); // ready
   return 1;
}

// Check if a service is running on a host with IP address 'ip'
// by checking all the ports in '_ports', using a non-blocking connect.
// Right now -- assume if *any* of these ports are active,
// the service is active.
int LANProtocol::checkPort( TQValueVector<int>& _ports, in_addr ip )
{
   int _port=0;
   struct sockaddr_in to_scan;

   to_scan.sin_family = AF_INET;
   to_scan.sin_addr = ip;

   for (TQValueVector<int>::iterator i= _ports.begin(); i != _ports.end(); i++)
   {
      _port=(*i);
      kdDebug(7101)<<"LANProtocol::checkPort: "<<_port<<endl;
      to_scan.sin_port = htons(_port);
      // open a TCP socket
      int mysocket = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (mysocket< 0 )
      {
         std::cerr << "LanProt::checkPort: Error while opening Socket" << std::endl;
         ::close( mysocket );
         return 0;
      }
      //make the socket non blocking
      long int options = O_NONBLOCK | ::fcntl(mysocket, F_GETFL);
      if (::fcntl( mysocket, F_SETFL, options )!=0)
      {
         std::cerr << "LanProt::checkPort: Error making it nonblocking"<< std::endl;
         ::close( mysocket );
         return 0;
      }
      int result=connect( mysocket, (struct sockaddr *) &to_scan, sizeof( to_scan ));
      //it succeeded immediately
      if (result==0)
      {
         std::cerr<<"LANProtocol::checkPort("<<_port<<") connect succeeded immediately"<<std::endl;
         ::shutdown( mysocket, SHUT_RDWR );
         return 1;
      }
      //it failed
      if ((result<0) && (errno!=EINPROGRESS))
      {
         // errno was not EINPROGRESS, so there is some serious problem
         ::shutdown( mysocket, SHUT_RDWR );
         // maybe some other port will work
         continue;
      }
      // last errno was EINPROGRESS, so we should select() on socket
      // and wait for the final verdict
      timeval tv;
      tv.tv_sec=5;
      tv.tv_usec=0;
      fd_set rSet, wSet;
      FD_ZERO(&rSet);
      FD_SET(mysocket,&rSet);
      wSet=rSet;
      //timeout or error
      result=select(mysocket+1,&rSet,&wSet,0,&tv);
      ::shutdown( mysocket, SHUT_RDWR );
      if (result==1)
         return 1;
   }
   // gosh, no port worked
   return 0;

}

void LANProtocol::setHost( const TQString& host, int port, const TQString& , const TQString& )
{
   if (m_isLanIoslave)
   {
      m_currentHost=host;
      if (port==0)
         m_port=7741;
      else
         m_port=port;
      kdDebug(7101)<<"LANProtocol::setHost: "<<m_currentHost<<endl;
   }
   else
   {
      if (!host.isEmpty())
         error(ERR_MALFORMED_URL,i18n("No hosts allowed in rlan:/ URL"));
   }
}

void LANProtocol::mimetype( const KURL& url)
{
   kdDebug(7101)<<"LANProtocol::mimetype -"<<url.prettyURL()<<"-"<<endl;
   TQString path( TQFile::encodeName(url.path()));
   TQStringList pathList=TQStringList::split( "/",path);
   if ((pathList.count()==2) && (pathList[1].upper()=="HTTP"))
   {
      //kdDebug(7101)<<"LANProtocol::mimeType text/html"<<endl;
      mimeType("text/html");
   }
   else
   {
      mimeType("inode/directory");
      //kdDebug(7101)<<"LANProtocol::mimeType inode/directory"<<endl;
   }
   finished();
}

void LANProtocol::listDir( const KURL& _url)
{
   KURL url(_url);
   TQString path( TQFile::encodeName(url.path()));
   if (path.isEmpty())
   {
      url.setPath("/");
      redirection(url);
      finished();
      return;
   }
   if ((m_currentHost.isEmpty()) && (m_isLanIoslave))
   {
      url.setHost(m_defaultLisaHost);
      redirection(url);
      finished();
      return;
   }
   kdDebug(7101)<<"LANProtocol::listDir: host: "<<m_currentHost<<" port: "<<m_port<<" path: "<<path<<endl;
   TQStringList pathList=TQStringList::split("/", path);
   kdDebug(7101)<<"parts are: "<<endl;
   for (TQStringList::Iterator it=pathList.begin(); it !=pathList.end(); it++)
      kdDebug(7101)<<"-"<<(*it)<<"-"<<endl;
   if (pathList.count()>2)
   {
      kdDebug(7101)<<"LANProtocol::listDir: too deep path: "<<pathList.count()<<endl;
      error(ERR_DOES_NOT_EXIST,_url.prettyURL());
      return;
   }
   int succeeded(0);
   if (path=="/")
   {
      //get the stuff from the netland server
      succeeded=readDataFromServer();
   }
   else if (pathList.count()==1)
   {
      //check the ports and stuff
      succeeded=checkHost(pathList[0]);
   }
   else
   {
      kdDebug(7101)<<"LANProtocol::listDir: trying to redirect"<<endl;
      int isSupportedProtocol(0);
      for (int i=0; i<KIOLAN_MAX; i++)
      {
         if (pathList[1].upper()==m_protocolInfo[i].name)
         {
            isSupportedProtocol=m_protocolInfo[i].enabled;
            break;
         }
      }
      if (isSupportedProtocol==PORTSETTINGS_DISABLE)
      {
         kdDebug(7101)<<"LANProtocol::listDir: protocol not enabled "<<endl;
         error(ERR_DOES_NOT_EXIST,_url.prettyURL());
         return;
      }
      //redirect it
      KURL newUrl(pathList[1]+"://"+pathList[0]);
      redirection(newUrl);
      succeeded=1;
   }
   if (succeeded) finished();
}

void LANProtocol::stat( const KURL & url)
{
   kdDebug(7101)<<"LANProtocol::stat: "<<endl;
   UDSEntry entry;
   UDSAtom atom;

   atom.m_uds = TDEIO::UDS_NAME;
   atom.m_str = url.path();
   entry.append( atom );
   atom.m_uds = TDEIO::UDS_SIZE;
   atom.m_long = 1024;
   entry.append(atom);

   atom.m_uds = TDEIO::UDS_ACCESS;
   atom.m_long = S_IRUSR | S_IRGRP | S_IROTH ;
   //atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
   entry.append(atom);


   TQString path( TQFile::encodeName(url.path()));
   TQStringList pathList=TQStringList::split( "/",path);
   if ((pathList.count()==2) && (pathList[1].upper()=="HTTP"))
   {
      atom.m_uds = TDEIO::UDS_FILE_TYPE;
      atom.m_long=S_IFREG;
      entry.append(atom);
      atom.m_uds = TDEIO::UDS_MIME_TYPE;
      atom.m_str="text/html";
      //kdDebug(7101)<<"LANProtocol::stat: http is reg file"<<endl;
      entry.append( atom );
   }
   else
   {
      atom.m_uds = TDEIO::UDS_FILE_TYPE;
      atom.m_long = S_IFDIR; // it is always a directory
      entry.append(atom);
      atom.m_uds = TDEIO::UDS_MIME_TYPE;
      atom.m_str="inode/directory";
      //kdDebug(7101)<<"LANProtocol::stat: is dir"<<endl;
      entry.append( atom );
   }

   statEntry( entry );
   finished();
}

void LANProtocol::get(const KURL& url )
{
   TQString path(TQFile::encodeName(url.path()));

   kdDebug(7101)<<"LANProtocol::get: "<<path<<endl;
   TQStringList pathList=TQStringList::split("/", path);
   kdDebug(7101)<<"parts are: "<<endl;
   for (TQStringList::Iterator it=pathList.begin(); it !=pathList.end(); it++)
      kdDebug(7101)<<"-"<<(*it)<<"-"<<endl;
   if ((pathList.count()!=2) || (pathList[1].upper()!="HTTP"))
   {
      kdDebug(7101)<<"LANProtocol::get: invalid url: "<<pathList.count()<<endl;
      error(ERR_DOES_NOT_EXIST,url.prettyURL());
      return;
   }
   KURL newUrl("http://"+pathList[0]);
   redirection(newUrl);
   finished();
   return;
}
