Logo Search packages:      
Sourcecode: kdebluetooth version File versions  Download package

qobexfbsserverops.cpp

/*
    This file is part of libqobex.

    Copyright (c) 2003-2004 Mathias Froehlich <Mathias.Froehlich@web.de>

    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., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qstring.h>
#include <qstringlist.h>
#include <qfile.h>
#include <qdir.h>
#include <qdom.h>
#include <qcstring.h>
#include <qbuffer.h>
#include <qdatetime.h>

#include <qobex/qobexuuid.h>
#include <qobex/qobexobject.h>

#include <qobex/qobexserverops.h>
#include "qobexfbsserverops.h"

#undef DEBUG
#define DEBUG
#ifdef DEBUG
#define myDebug(a) qDebug a
#else
#define myDebug(a) (void)0
#endif

QObexFBSServerOps::QObexFBSServerOps() {
  mFolderListingMode = false;
}

QObexFBSServerOps::~QObexFBSServerOps() {
}

void QObexFBSServerOps::connect( const QObexObject&, QObexObject& resp ) {
  myDebug(( "QObexFBSServerOps::connect()" ));
  if ( !isAuthenticated() )
    resp.setCode( QObexObject::Unauthorized );
}

void QObexFBSServerOps::disconnect( const QObexObject& ) {
  myDebug(( "QObexFBSServerOps::disconnect()" ));
}

void QObexFBSServerOps::get( const QObexObject& req, QObexObject& resp ) {
  myDebug(( "QObexFBSServerOps::get(): cwd = %s", getCwd().ascii() ));
 
  QString name = req.getHeader( QObexHeader::Name ).stringData();
  if ( checkForDotDot( name, resp ) )
    return;
  QString fullname = composePath( name );
  QString type = req.getHeader( QObexHeader::Type ).stringData();

  if ( !name.isEmpty() || !type.isEmpty() ) {
    if ( type == "x-obex/folder-listing" ) {
      mFolderListingMode = true;

      if ( fullname.isEmpty() )
      fullname = QString( "." );

      bool ok;
      mXmlBuf.setBuffer( getObexFolderListing( fullname, &ok ) );
      if ( ok )
      enterDirectory( name );

      mXmlBuf.open( IO_ReadOnly );
      resp.addHeader( QObexHeader( QObexHeader::Length, Q_UINT32( mXmlBuf.size() ) ) );
    } else {
      mFolderListingMode = false;
      if ( !f.isOpen() ) {
      f.setName( fullname );
      f.open( IO_ReadOnly );
      resp.addHeader( QObexHeader( QObexHeader::Length, Q_UINT32( f.size() ) ) );
      }
    }
  }
}

bool QObexFBSServerOps::dataReq( QByteArray& data, Q_LONG sz ) {
  myDebug(( "QObexFBSServerOps::dataReq( ... )" ));
  if ( 0 < sz ) {
    if ( mFolderListingMode ) {
      if ( mXmlBuf.isOpen() ) {
      data.resize( sz );
      sz = mXmlBuf.readBlock( data.data(), sz );
      data.resize( sz );
      if ( mXmlBuf.atEnd() ) {
        mXmlBuf.close();
        mXmlBuf.setBuffer( QByteArray() );
      }
      }
    } else {
      if ( f.isOpen() ) {
      data.resize( sz );
      sz = f.readBlock( data.data(), sz );
      if ( f.atEnd() )
        f.close();
      if ( sz < 0 ) {
        data.resize( 0 );
        return false;
      }
      data.resize( sz );
      }
    }
  }
  return true;
}

void QObexFBSServerOps::del( const QObexObject& req, QObexObject& resp ) {
  myDebug(( "QObexFBSServerOps::del( ... ): cwd = %s", getCwd().ascii() ));

  QString name = req.getHeader( QObexHeader::Name ).stringData();
  if ( checkForDotDot( name, resp ) )
    return;
  if ( !name.isEmpty() ) {
    // Use locale for name ...
    QString fullname = composePath( name );

    QFileInfo fi( fullname );
    if ( fi.isDir() ) {
      QDir dir( fullname );
      QString dn = dir.dirName();
      if ( dn.isEmpty() ) {
      resp.setCode( QObexObject::Forbidden );
      resp.addHeader( QObexHeader( QObexHeader::Description, "Can not remove root directory" ) );
      } else {
      dir.setFilter( QDir::All | QDir::Hidden | QDir::System );
      dir.setSorting( QDir::Unsorted );
      if ( 2 < dir.count() ) {
        resp.setCode( QObexObject::PreconditionFailed );
        resp.addHeader( QObexHeader( QObexHeader::Description, "Directory not empty" ) );
        return;
      }
      dir.cdUp();
      if ( !dir.rmdir( dn ) ) {
        resp.setCode( QObexObject::Forbidden );
        resp.addHeader( QObexHeader( QObexHeader::Description, "Can not remove directory" ) );
      }
      }
    } else {
      if ( !QFile::remove( fullname ) ) {
      resp.setCode( QObexObject::Forbidden );
      resp.addHeader( QObexHeader( QObexHeader::Description, "Can not remove file" ) );
      }
    }
  }
}

void QObexFBSServerOps::put( const QObexObject& req, QObexObject& resp ) {
  myDebug(( "QObexFBSServerOps::put(): cwd = %s", getCwd().ascii() ));
  if ( !f.isOpen() ) {
    QString name = req.getHeader( QObexHeader::Name ).stringData();
    if ( checkForDotDot( name, resp ) )
      return;
    QString fullname = composePath( name );
    f.setName( fullname );
    f.open( IO_WriteOnly );
  }
}

bool QObexFBSServerOps::data( const QValueList<QByteArray>& bodies ) {
  myDebug(( "QObexFBSServerOps::data( ... )" ));
  if ( f.isOpen() ) {
    QValueList<QByteArray>::ConstIterator it;
    for ( it = bodies.begin(); it != bodies.end(); ++it )
      f.writeBlock( (*it) );
  }
  // Empty bodies signal end of operation.
  if ( bodies.isEmpty() )
    f.close();
  return true;
}

void QObexFBSServerOps::setPath( const QObexObject& req, QObexObject& resp ) {
  myDebug(( "QObexFBSServerOps::setPath( ... ): cwd = %s", getCwd().ascii() ));

  bool backup = req.getFlags() & QObexObject::Backup;
  if ( backup && isRootDir() ) {
    resp.setCode( QObexObject::NotAcceptable );
    resp.addHeader( QObexHeader( QObexHeader::Description, "Can not backup from root directory" ) );
    return;
  }

  if ( !req.hasHeader( QObexHeader::Name ) ) {
    // accept silently the noop: no name header and no backup flag
    if ( backup )
      oneDirectoryUp();
  } else {
    QObexHeader hdr = req.getHeader( QObexHeader::Name );

    if ( hdr.isEmpty() )
      enterRootDirectory();
    else {
      QString name = hdr.stringData();
      if ( checkForDotDot( name, resp ) )
      return;

      QString fullname = composePath( name, backup );
      QDir dir( fullname );
      if ( dir.exists() )
      enterDirectory( hdr.stringData() );
      else {
      // hmm, directory does not exist. Check if we should create it
      if ( req.getFlags() & QObexObject::NoCreate ) {
        resp.setCode( QObexObject::NotFound );
        resp.addHeader( QObexHeader( QObexHeader::Description, "Directory does not exist" ) );
      } else {
        dir.setPath( getCwd() );
        if ( dir.mkdir( name ) ) {
          enterDirectory( name );
        } else {
          resp.setCode( QObexObject::Forbidden );
          resp.addHeader( QObexHeader( QObexHeader::Description, "Can not create directory" ) );
        }
      }
      }
    }
  }
}

void QObexFBSServerOps::abort( const QObexObject& ) {
  myDebug(( "QObexFBSServerOps::abort( ... )" ));
  streamingError();
}

void QObexFBSServerOps::streamingError() {
  myDebug(( "QObexFBSServerOps::streamingError()" ));

  if ( mXmlBuf.isOpen() )
    mXmlBuf.close();
  mXmlBuf.setBuffer( QByteArray() );
  mFolderListingMode = false;

  if ( f.isOpen() )
    f.close();
}

bool QObexFBSServerOps::canHandle( const QByteArray& uuid ) {
  myDebug(( "QObexFBSServerOps::canHandle( ... )" ));
  return uuid == QObexUuidFBS;
}

QObexServerOps* QObexFBSServerOps::clone() {
  myDebug(( "QObexFBSServerOps::clone()" ));
  return new QObexFBSServerOps;
}

QObexAuthDigestChallenge::AuthInfo QObexFBSServerOps::serverAuthInfo() {
  myDebug(( "QObexFBSServerOps::serverAuthInfo( ... )" ));
  return QObexAuthDigestChallenge::AuthInfo( "serverRealm" );
}

QByteArray QObexFBSServerOps::serverSecret( const QString& ) {
  myDebug(( "QObexFBSServerOps::serverSecret( ... )" ));
  QByteArray secret;
  secret.duplicate( "fbsserver", 9 );
  return secret;
}

QObexAuthDigestResponse::AuthInfo QObexFBSServerOps::clientAuthInfo( const QString&, bool ) {
  myDebug(( "QObexFBSServerOps::authenticationRequired( ... )" ));
  QByteArray secret;
  secret.duplicate( "fbsserver", 9 );
  return QObexAuthDigestResponse::AuthInfo( secret, "clientUserid" );
}

bool QObexFBSServerOps::checkForDotDot( const QString& name, QObexObject& resp ) {
  myDebug(( "QObexFBSServerOps::checkForDotDot( %s, ... )", name.ascii() ));

  if ( name == ".." ||
       name.startsWith( "../" ) ||
       name.endsWith( "/.." ) ||
       name.contains( "/../" ) ) {
    resp.setCode( QObexObject::NotAcceptable );
    resp.addHeader( QObexHeader( QObexHeader::Description, "The path component .. is not allowed" ) );
    return true;
  }
  return false;
}

QByteArray QObexFBSServerOps::getObexFolderListing( const QString& name, bool*ok ) {
  QDomImplementation di;
  QDomDocument xmlDoc( di.createDocumentType( "folder-listing",
      QString::null, "obex-folder-listing.dtd" ) );
  QDomElement folderListingElement = xmlDoc.createElement( "folder-listing" );
  folderListingElement.setAttribute( "version", "1.0" );

  QDir dir( name );
  if ( dir.exists() ) {
    *ok = true;

    // stat the directory which is requested.
    // Writing to that will be the key to file deletion.
    QFileInfo dInfo( name );
    bool uDel = dInfo.permission( QFileInfo::WriteUser );
    bool gDel = dInfo.permission( QFileInfo::WriteGroup );
    bool oDel = dInfo.permission( QFileInfo::WriteOther );

    dir.setFilter( QDir::All | QDir::Hidden | QDir::System );
    dir.setSorting( QDir::Unsorted );
    QStringList entries = dir.entryList();
    QStringList::Iterator it = entries.begin();

    for ( it = entries.begin(); it != entries.end(); ++it ) {
      QString entName = *it;
      
      if ( (*it) == ".." ) {
      QDomElement element = xmlDoc.createElement( "parent-folder" );
      folderListingElement.appendChild( element );
      } else if ( (*it) != "." ) {
      QFileInfo fInfo( dir, *it );

      if ( fInfo.isDir() || fInfo.isFile() || fInfo.isSymLink() ) {
        QDomElement element
          = xmlDoc.createElement( fInfo.isDir() ? "folder" : "file" );
        element.setAttribute( "name", *it );
        element.setAttribute( "size", QString::number( fInfo.size() ) );
//          element.setAttribute( "type", "mimetype ... ???" );
        element.setAttribute( "modified", fInfo.lastModified().toString("yyyyMMddThhmmssZ") );
        element.setAttribute( "created", fInfo.created().toString("yyyyMMddThhmmssZ") );
        element.setAttribute( "accessed", fInfo.lastRead().toString("yyyyMMddThhmmssZ") );
        
        QString perm;
        if ( fInfo.permission( QFileInfo::ReadUser ) )
          perm += "R";
        if ( fInfo.permission( QFileInfo::WriteUser ) )
          perm += "W";
        if ( uDel )
          perm += "D";
        element.setAttribute( "user-perm", perm );
        perm.truncate( 0 );
        if ( fInfo.permission( QFileInfo::ReadGroup ) )
          perm += "R";
        if ( fInfo.permission( QFileInfo::WriteGroup ) )
          perm += "W";
        if ( gDel )
          perm += "D";
        element.setAttribute( "group-perm", perm );
        perm.truncate( 0 );
        if ( fInfo.permission( QFileInfo::ReadOther ) )
          perm += "R";
        if ( fInfo.permission( QFileInfo::WriteOther ) )
          perm += "W";
        if ( oDel )
          perm += "D";
        element.setAttribute( "other-perm", perm );
        element.setAttribute( "owner", fInfo.owner() );
        element.setAttribute( "group", fInfo.group() );
        // FIXME ????
//        element.setAttribute( "xml:lang", QString( QTextCodec::locale() ) );
        folderListingElement.appendChild( element );
      }
      }
    }
  }

  xmlDoc.appendChild( folderListingElement );
  
  QBuffer tmp;
  tmp.open( IO_WriteOnly );
  QTextStream stream( &tmp );
  stream.setEncoding( QTextStream::UnicodeUTF8 );
  stream << xmlDoc;
  tmp.close();
  
  return tmp.buffer();
}

Generated by  Doxygen 1.6.0   Back to index