www.pudn.com > PocketOBEX_demo.rar > ObexFTP.cpp


#include "stdafx.h" 
#include "obexFTP.h" 
#include  
#include  
 
#pragma comment(lib,"comsupp.lib") 
#pragma comment(lib,"ccrtrtti.lib") 
 
//----------------------------------------------------------------- 
// CObexDeviceProperties: ctor(1) with an IPropertyBag * 
// useful for OnDeviceXXX functions 
//----------------------------------------------------------------- 
CObexDeviceProperties::CObexDeviceProperties(IPropertyBag *Prop) : m_Bag(Prop) 
{ 
} 
//----------------------------------------------------------------- 
// CObexDeviceProperties: ctor(2) with an IObexDevice * 
// first query the device for the Properties 
//----------------------------------------------------------------- 
CObexDeviceProperties::CObexDeviceProperties(IObexDevice *Dev) 
{ 
  IPropertyBag *Bag=NULL; 
  if (Dev && SUCCEEDED(Dev->EnumProperties(__uuidof(IPropertyBag),(void **)&Bag))) 
  { 
    m_Bag=Bag; 
  } 
} 
//----------------------------------------------------------------- 
// CObexDeviceProperties: ctor(3) with an IUnknown * 
// used internally in IObexSink::Notify 
//----------------------------------------------------------------- 
CObexDeviceProperties::CObexDeviceProperties(IUnknown *Unk) 
{ 
  CComQIPtr Bag(Unk); 
  if (Bag) 
  { 
    m_Bag=Bag.Detach(); 
  } 
} 
 
//----------------------------------------------------------------- 
// CObexDeviceProperties: dtor - noop 
//----------------------------------------------------------------- 
CObexDeviceProperties::~CObexDeviceProperties() 
{ 
} 
 
//----------------------------------------------------------------- 
// CObexDeviceProperties: GetProperty 
// Basic call to read any property 
//----------------------------------------------------------------- 
HRESULT CObexDeviceProperties::GetProperty(LPCOLESTR PropName,VARIANT &Value) 
{ 
  if (m_Bag) 
  { 
    return m_Bag->Read(PropName,&Value,NULL); 
  } 
  else 
  { 
    return E_FAIL; 
  } 
} 
//----------------------------------------------------------------- 
// CObexDeviceProperties: GetProperty 
// return the string value of a  property 
//----------------------------------------------------------------- 
CString CObexDeviceProperties::GetProperty(LPCOLESTR PropName) 
{ 
  CComVariant varValue;; 
  CString strValue; 
  if (SUCCEEDED(GetProperty(PropName,varValue))) 
  { 
    if (SUCCEEDED(varValue.ChangeType(VT_BSTR))) 
    { 
      strValue=varValue.bstrVal; 
    } 
  } 
  return strValue; 
} 
 
CString CObexDeviceProperties::GetName()     // NAME of the Device 
{ 
  return GetProperty(c_szDevicePropName); 
} 
CString CObexDeviceProperties::GetAddress() // ADDRESS of the device 
{ 
  return GetProperty(c_szDevicePropAddress); 
} 
CString CObexDeviceProperties::GetTransport() // TRANSPORT of the device 
{ 
  return GetProperty(c_szDevicePropTransport); 
} 
CString CObexDeviceProperties::GetServices()  // SERVICEs of the device 
{ 
  return GetProperty(c_szDeviceServiceUUID); 
} 
bool CObexDeviceProperties::CanFTP()          // OBEX-FTP supported? 
{ 
  CString strServ=GetServices(); 
  if (!strServ.IsEmpty()) 
  { 
    LPCWSTR pszServ=strServ; 
    for ( ; (pszServ=wcschr(pszServ,L'{'))!=NULL; ++pszServ) 
    { 
      UINT uuid16=wcstoul(pszServ+1,NULL,16); 
      if (uuid16==OBEXFileTransferServiceClassID_UUID16)  
        return true; 
    } 
  } 
  return false; 
} 
 
 
CStreamToMemory::CStreamToMemory(UINT Initial/*=0*/,UINT Add/*=4096*/)  
  : m_Buffer(NULL),m_PageSize(Add),m_Allocated(0),m_Filled(0) 
{ 
  if (Initial) 
  { 
     m_Buffer=(BYTE *)malloc(Initial); 
     if (m_Buffer) m_Allocated=Initial; 
  } 
} 
CStreamToMemory::~CStreamToMemory() 
{ 
  Clear(); 
} 
BOOL CStreamToMemory::Read(IStream *pStream) 
{ 
  if (pStream==NULL) 
  { 
    return FALSE; 
  } 
  ULONG cbJustRead,cbSum=0; 
  BYTE aTempBuffer[1024]; 
  while (SUCCEEDED(pStream->Read(aTempBuffer,1024,&cbJustRead))) 
  { 
    if (m_Filled+cbJustRead>=m_Allocated) 
    { 
      UINT newAlloc=m_Allocated; 
      while (m_Filled+cbJustRead>newAlloc) 
        newAlloc+=m_PageSize; 
      if (m_Allocated==0) m_Buffer=(BYTE *)malloc(m_Allocated=newAlloc); 
      else                m_Buffer=(BYTE *)realloc(m_Buffer,newAlloc); 
      if (m_Buffer==NULL) return FALSE; 
    } 
    memcpy(m_Buffer+m_Filled,aTempBuffer,cbJustRead); 
    // Make sure there is a additional zero byte for ascii files 
    m_Buffer[m_Filled+=cbJustRead]=0; 
    cbSum+=cbJustRead; 
  } 
  return cbSum!=0; 
} 
 
UINT CStreamToMemory::Size() 
{ 
  return m_Filled; 
} 
BYTE *CStreamToMemory::GetData() 
{ 
  return m_Buffer; 
} 
void CStreamToMemory::Clear() 
{ 
  free(m_Buffer); m_Buffer=NULL; 
  m_Filled=m_Allocated=0; 
} 
 
 
CObexListing::CObexListing(UINT Initial/*=0*/,UINT Add/*=4096*/)  
 : CStreamToMemory(Initial,Add),m_pCur(NULL) 
{ 
} 
CObexListing::~CObexListing() 
{ 
} 
// Format of the obex-filelist date properties 
// yyyymmddThhmmssZ 
void CObexListing::GetDateProp(const char *p,FILETIME &ft) 
{ 
  SYSTEMTIME st; 
	st.wYear = 1000 * (p[0] - '0') + 100 * (p[1] - '0') + 10 * (p[2] - '0') + (p[3] - '0'); 
	st.wMonth = 10 * (p[4] - '0') + (p[5] - '0'); 
	st.wDay = 10 * (p[6] - '0') + (p[7] - '0'); 
	st.wHour = 10 * (p[9] - '0') + (p[10] - '0'); 
	st.wMinute = 10 * (p[11] - '0') + (p[12] - '0'); 
	st.wSecond = 10 * (p[13] - '0') + (p[14] - '0'); 
	SystemTimeToFileTime(&st, &ft); 
} 
// if the text text at current pointer m_pCur matches , advance m_pCur and return true 
// otherwise do not touch m_pCur and return false 
bool CObexListing::AtText(const char *t) 
{ 
  int tl=strlen(t); 
  if (0==_strnicmp(m_pCur,t,tl)) 
  { 
    m_pCur+=tl; 
    return true; 
  } 
  return false; 
} 
// Skip white space 
char *CObexListing::Skip(const char *t) 
{ 
  while (isspace(*t)) ++t; 
  return (char *)t; 
} 
// if the text at the current pointer m_pCur matches , then analyse a 
// property as: name = "value" 
// if the string is properly formatted then 
// point  to the fisrst chat of value 
// replace the terminating " with NUL  
// return true 
// Caution: you have to call NextProp to revert the changes! 
bool CObexListing::IsProp(const char *t,char **pAt) 
{ 
  char *save=m_pCur; 
  if (AtText(t)) 
  { 
    char *p=m_pCur; m_pCur=save; 
    if (isspace(*p)) p=Skip(t); 
    if (*p++!='=') return false; 
    p=Skip(p); 
    if (*p++!='\"') return false; 
    *pAt=p; 
    while (*p && *p!='\"') ++p; 
    if (*p) 
    { 
      *(m_pCur=p)=0; 
      return true; 
    } 
  } 
  return false; 
} 
// revert the changes made by IsProp and advance 
// m_pCur to point to the next property 
void CObexListing::NextProp() 
{ 
  *m_pCur++='\"'; 
  m_pCur=Skip(m_pCur); 
} 
// Skip an unknown property 
void CObexListing::SkipProp() 
{ 
  char *p=strchr(m_pCur,'\"'); 
  if (p) 
    p=strchr(p+1,'\"'); 
  if (p) 
    m_pCur=Skip(p+1); 
  else 
    m_pCur+=strlen(m_pCur); 
} 
 
 
// assume a well formed obex folder-list 
BOOL CObexListing::FindFirstFile(WIN32_FIND_DATA *FindFileData,UINT Mask) 
{ 
  m_Mask=Mask&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL); 
  if (Size()==0 || (m_pCur=(char *)GetData())==NULL) 
    return FALSE; 
  m_pCur=strstr(m_pCur,"cFileName,L".."); 
        FindFileData->dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY; 
        return true; 
      } 
    } 
    return FindNextFile(FindFileData); 
  } 
} 
BOOL CObexListing::FindNextFile(WIN32_FIND_DATA *FindFileData) 
{ 
  while (1) 
  { 
    if (m_pCur==NULL || (m_pCur=strstr(m_pCur,"dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY; 
    else if (AtText("dwFileAttributes=FILE_ATTRIBUTE_NORMAL; 
    else 
    { 
      m_pCur=NULL; 
      return FALSE; 
    } 
    char *PropAt=strstr(m_pCur,"/>"); 
    if (PropAt==NULL) 
    { 
      m_pCur=NULL; 
      return FALSE; 
    } 
    if ((FindFileData->dwFileAttributes&m_Mask)==0) 
    { 
      // not interested in this kind of oject: file/folder 
      m_pCur=Skip(PropAt+2); 
    } 
    else 
    { 
       // interpret the properties 
      *PropAt=0; 
      UINT dateFlags=0; 
      while (*m_pCur) 
      { 
        if (IsProp("name",&PropAt)) 
        { 
    	    MultiByteToWideChar (CP_ACP, 0, PropAt, -1, FindFileData->cFileName, MAX_PATH); 
          NextProp(); 
        } 
        else if (IsProp("size",&PropAt)) 
        { 
          FindFileData->nFileSizeLow=atoi(PropAt); 
          NextProp(); 
        } 
        else if (IsProp("created",&PropAt)) 
        { 
          GetDateProp(PropAt,FindFileData->ftCreationTime); 
          dateFlags|=1; 
          NextProp(); 
        } 
        else if (IsProp("modified",&PropAt)) 
        { 
          GetDateProp(PropAt,FindFileData->ftLastWriteTime); 
          dateFlags|=2; 
          NextProp(); 
        } 
        else if (IsProp("accessed",&PropAt)) 
        { 
          GetDateProp(PropAt,FindFileData->ftLastAccessTime); 
          dateFlags|=4; 
          NextProp(); 
        } 
        else 
        { 
          SkipProp(); 
        } 
      } 
      *m_pCur++='/'; m_pCur++; 
      if (dateFlags && dateFlags!=7) 
      { 
        if ((dateFlags&1)==0) 
        { 
          if (dateFlags&2) FindFileData->ftCreationTime=FindFileData->ftLastWriteTime; 
          else             FindFileData->ftCreationTime=FindFileData->ftLastAccessTime;  
        } 
        if ((dateFlags&2)==0) 
        { 
          if (dateFlags&1) FindFileData->ftLastWriteTime=FindFileData->ftCreationTime; 
          else             FindFileData->ftLastWriteTime=FindFileData->ftLastAccessTime;  
        } 
        if ((dateFlags&4)==0) 
        { 
          if (dateFlags&2) FindFileData->ftLastAccessTime=FindFileData->ftLastWriteTime; 
          else             FindFileData->ftLastAccessTime=FindFileData->ftCreationTime;  
        } 
      } 
      return TRUE; 
    } 
  } 
} 
 
BOOL CObexListing::FindClose() 
{ 
  Clear(); 
  return TRUE; 
} 
 
//------------------------------------------------------------------- 
// CObexFTP ctor - call Initialize after construction ! 
//------------------------------------------------------------------- 
CObexFTP::CObexFTP() : m_cRef(1),m_bEnumerating(false) 
{ 
} 
//------------------------------------------------------------------- 
// CObexFTP dtor - stop enumeration, relaese connection point, and 
//                 shutdown IObex 
//------------------------------------------------------------------- 
CObexFTP::~CObexFTP() 
{ 
  // close all active connections 
  CObexFTPConnection *c; 
  while ((c=m_Connections.m_pHead)!=NULL) 
  { 
    c->Disconnect(); 
  } 
  if (m_obex) 
  { 
    StopDeviceEnumeration(); 
    m_obex->Shutdown(); 
    m_obex=NULL; 
  } 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::Initialize  - call after ctor to init the obex system 
//------------------------------------------------------------------- 
BOOL CObexFTP::Initialize() 
{ 
  // already initialzed ? 
  if (m_obex) 
  { 
    return TRUE; 
  } 
  else 
  { 
    // CoCreate an instance of IObex 
    m_obex.CoCreateInstance(__uuidof(Obex)); 
    if (m_obex) 
    { 
      // Call IObex::Initialize 
      if (SUCCEEDED(m_obex->Initialize())) 
      { 
        // Advise the IObexSink connection point 
        LPUNKNOWN pUnkThis; 
        QueryInterface(IID_IUnknown,(void **)&pUnkThis); 
        m_dwAdvise=0; 
        if (SUCCEEDED(AtlAdvise(m_obex,pUnkThis,IID_IObexSink,&m_dwAdvise))) 
        { 
          return TRUE; 
        } 
        else 
        { 
          m_obex=NULL; 
          ATLTRACE(_T("Cannot Advise!\n")); 
        } 
      } 
      else 
      { 
        m_obex=NULL; 
        ATLTRACE(_T("Cannot IObex::Initialize!\n")); 
      } 
    } 
#ifdef _DEBUG 
    else 
    { 
      ATLTRACE(_T("Cannot CoCreate IObex!\n")); 
    } 
#endif 
  } 
  return FALSE; 
} 
  
//------------------------------------------------------------------- 
// CObexFTP::StartDeviceEnum - start asynchronous events via IObexSink 
//------------------------------------------------------------------- 
BOOL CObexFTP::StartDeviceEnumeration() 
{ 
  if (!m_bEnumerating) 
  { 
    if (m_obex) 
    { 
      if (SUCCEEDED(m_obex->StartDeviceEnum())) 
        m_bEnumerating=true; 
    } 
  } 
  return m_bEnumerating; 
} 
//------------------------------------------------------------------- 
// CObexFTP::StopDeviceEnum - stop asynchronous events via IObexSink 
//------------------------------------------------------------------- 
void CObexFTP::StopDeviceEnumeration() 
{ 
  if (m_bEnumerating) 
  { 
    ATLASSERT((IObex *)m_obex); 
    m_obex->StopDeviceEnum(); 
    m_bEnumerating=false; 
  } 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::IObexSink::IUnknown::Addref - std implementation 
//------------------------------------------------------------------- 
ULONG CObexFTP::AddRef() 
{ 
  ULONG cr=InterlockedIncrement(&m_cRef); 
  return cr; 
} 
//------------------------------------------------------------------- 
// CObexFTP::IObexSink::IUnknown::Release - std implementation 
//------------------------------------------------------------------- 
ULONG CObexFTP::Release() 
{ 
  ULONG cr=InterlockedDecrement(&m_cRef); 
  ATLASSERT(m_cRef); 
  return cr; 
} 
//------------------------------------------------------------------- 
// CObexFTP::IObexSink::IUnknown::QueryInterface - std implementation 
//------------------------------------------------------------------- 
HRESULT CObexFTP::QueryInterface(REFIID iid,void ** ppvObject) 
{ 
	if (InlineIsEqualGUID(iid, IID_IObexSink) ||  
			InlineIsEqualUnknown(iid)) 
	{ 
		if (ppvObject == NULL) 
				return E_POINTER; 
		*ppvObject = (void*)(IUnknown*)this; 
		AddRef(); 
    return S_OK; 
  } 
  *ppvObject=NULL; 
  return E_NOINTERFACE; 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::IObexSink::IUnknown::QueryInterface - std implementation 
//------------------------------------------------------------------- 
HRESULT CObexFTP::Notify(OBEX_EVENT Event,IUnknown* pUnk1,IUnknown* /*pUnk2*/) 
{ 
  // Create a helper object for property access 
  CObexDeviceProperties dev(pUnk1); 
  ATLASSERT((IPropertyBag *)dev); 
  if (dev) 
  { 
    // build a unique key from Address+ServiceUUID 
    CString Key=dev.GetAddress(); 
    Key+=dev.GetServices(); 
    // and determine if this device supports OBEX-FTP 
    bool IsFTP=dev.CanFTP(); 
    // if it does - see if its already connected 
    if (IsFTP) 
    { 
      CObexFTPConnection *pConn; 
      pConn=FindConnection(Key); 
      if (pConn) 
      { 
        // if yes - call the appropriate handler 
        ATLASSERT(Event!=OE_DEVICE_ARRIVAL); 
        if (Event==OE_DEVICE_UPDATE) 
          OnDeviceChange(pConn,dev); 
        else 
          OnDeviceRemoval(pConn); 
      } 
      else if (Event!=OE_DEVICE_DEPARTURE) 
      { 
        // no this a new one 
        OnDeviceArrived(dev); 
      } 
    } 
  } 
  return S_OK; 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::OnDeviceArrived - should be overridden ! 
//------------------------------------------------------------------- 
void CObexFTP::OnDeviceArrived(IPropertyBag *Bag) 
{ 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::OnDeviceRemoval - call pConn->OnDeviceRemoval 
//------------------------------------------------------------------- 
void CObexFTP::OnDeviceRemoval(CObexFTPConnection *pConn) 
{ 
  ATLASSERT(pConn); 
  if (pConn) 
    pConn->OnDeviceRemoval(); 
} 
//------------------------------------------------------------------- 
// CObexFTP::OnDeviceChange - call pConn->OnDeviceChange 
//------------------------------------------------------------------- 
void CObexFTP::OnDeviceChange(CObexFTPConnection *pConn,IPropertyBag *Prop) 
{ 
  ATLASSERT(pConn); 
  if (pConn) 
    pConn->OnDeviceChange(Prop); 
} 
 
// This is the ServiceUUID of the Obex-FTP in network order 
GUID CLSID_FileExchange_NetOrder =	// {F9ec7bc4-953c-11d2-984e-525400dc9e09} 
{ 0xc47becf9, 0x3c95, 0xd211, {0x98, 0x4e, 0x52, 0x54, 0x00, 0xdc, 0x9e, 0x09}}; 
 
//------------------------------------------------------------------- 
// CObexFTP::Connect() - called only from friend CObexFTPConnection 
//------------------------------------------------------------------- 
BOOL CObexFTP::Connect(CObexFTPConnection *pConn,IPropertyBag *Prop,IObexDevice **ppOut) 
{ 
  // first we must bind the properties to a device 
  if (m_obex) 
  { 
    CComPtr Dev; 
    if (SUCCEEDED(m_obex->BindToDevice(Prop,&Dev))) 
    { 
      // Set the password if required 
      const CString &Password=pConn->GetPassword(); 
      if (!Password.IsEmpty()) 
        Dev->SetPassword(Password); 
      // then connect to proper Service 
      CComPtr Coll; 
      if (SUCCEEDED(Coll.CoCreateInstance(__uuidof(HeaderCollection)))) 
      { 
         if (SUCCEEDED(Coll->AddTarget(sizeof(CLSID_FileExchange_NetOrder),(BYTE *)&CLSID_FileExchange_NetOrder))) 
         { 
           // Question: do we need the password here, if it's already set in SetPassword ? 
           //           is the dwCap parameter of any interest for any server ? 
           if (SUCCEEDED(Dev->Connect(Password,OBEX_DEVICE_CAP_FILE_BROWSE,Coll))) 
           { 
             // NOTE: may be SUCCEDED is not enough; WINCE samples re-enumerate the HeaderCollection, 
             // try to find a CONNECTION_ID-Header and only report success if it is found ? 
             *ppOut=Dev.Detach(); 
             // build the unique key 
             CObexDeviceProperties odp(Prop); 
             CString Key=odp.GetAddress(); 
             Key+=odp.GetServices(); 
             pConn->SetKey(Key); 
             // and add to our active list 
             AddConnection(pConn); 
             return TRUE; 
           } 
         } 
      } 
    } 
  } 
  return FALSE; 
} 
 
BOOL CObexFTP::Disconnect(CObexFTPConnection *pConn) 
{ 
  // simply unlink from our list of connections 
  return m_Connections.Unlink(pConn)!=NULL; 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::ConnectTo  
//  use this function if you do not want to use derived classes 
//  for CObexFTPConnection 
//------------------------------------------------------------------- 
CObexFTPConnection *CObexFTP::ConnectTo(IPropertyBag *Prop,LPCWSTR pszPassw/*=NULL*/) 
{ 
  CObexFTPConnection *pConn=new CObexFTPConnection(pszPassw); 
  if (!pConn->Connect(this,Prop)) 
  { 
    delete pConn; 
    pConn=NULL; 
  } 
  return pConn; 
} 
 
//------------------------------------------------------------------- 
// CObexFTP::Connect management: find a connection with unique id 
//------------------------------------------------------------------- 
CObexFTPConnection *CObexFTP::FindConnection(const CString &Key) 
{ 
  return m_Connections.Find(Key); 
} 
//------------------------------------------------------------------- 
// CObexFTP::Connect management: add a connection to the list 
//------------------------------------------------------------------- 
void CObexFTP::AddConnection(CObexFTPConnection *pConn) 
{ 
  m_Connections.Push(pConn); 
} 
 
 
//------------------------------------------------------------------- 
// CObexFTPConnection ctor 
// the optional password is used during connect if the server 
// requires this 
//------------------------------------------------------------------- 
CObexFTPConnection::CObexFTPConnection(LPCWSTR pszPassw/*=NULL*/) 
: m_strPassw(pszPassw),m_pNext(NULL),m_pObj(NULL) 
{ 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection dtor 
//------------------------------------------------------------------- 
CObexFTPConnection::~CObexFTPConnection() 
{ 
  // if still connected, disconnect 
  Disconnect(); 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::OnDeviceRemoval 
// should be overwritten to cancel operation an close 
//------------------------------------------------------------------- 
void CObexFTPConnection::OnDeviceRemoval() 
{ 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::OnDeviceChange 
// could be overwritten to reread saved properties etc. 
//------------------------------------------------------------------- 
void CObexFTPConnection::OnDeviceChange(IPropertyBag* /*Bag*/) 
{ 
} 
 
//------------------------------------------------------------------- 
// CObexFTPConnection::GetDeviceName 
// ask the device for its propertybag and the query the name 
//------------------------------------------------------------------- 
CString CObexFTPConnection::GetDeviceName() 
{ 
  CObexDeviceProperties Prop(m_device); 
  return Prop.GetName(); 
} 
 
//------------------------------------------------------------------- 
// CObexFTPConnection::Connect 
// typically called in CObexFTP::OnDeviceArrived 
// call CObexFTP::Connect to do the work 
//------------------------------------------------------------------- 
BOOL CObexFTPConnection::Connect(CObexFTP *pObj,IPropertyBag *Bag) 
{ 
  if (pObj->Connect(this,Bag,&m_device)) 
  { 
    m_pObj=pObj; 
    return TRUE; 
  } 
  return FALSE; 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::Disconnect 
// call this function if you are done with the connection 
// only delete a connection after Disconnect! 
//------------------------------------------------------------------- 
CObexFTPConnection *CObexFTPConnection::Disconnect(bool bAutoDel/*=false*/) 
{ 
  if (m_device) 
  { 
    CComPtr Coll; 
    Coll.CoCreateInstance(__uuidof(HeaderCollection)); 
    m_device->Disconnect(Coll); 
    m_device=NULL; 
  } 
  if (m_pObj) 
  { 
    CObexFTP *pParent=m_pObj; 
    m_pObj=NULL; 
    pParent->Disconnect(this); 
  } 
  if (bAutoDel) 
  { 
    delete this; 
    return NULL; 
  } 
  return this; 
} 
 
//------------------------------------------------------------------- 
// CObexFTPConnection::SetPath - set the Server-Path 
// NOTE: the server path is always relative so pszPath cannot contain 
//       \\ characters! you can use NULL to go back to the root or use 
//       dwFlags=SETPATH_FLAG_BACKUP to simulate a cd .. 
//       use dwFlags=SETPATH_FLAG_DONT_CREATE if you only want to read 
//------------------------------------------------------------------- 
BOOL CObexFTPConnection::SetPath(LPCWSTR pszPath,DWORD dwFlags/*=0*/) 
{ 
  if (m_device) 
    return SUCCEEDED(m_device->SetPath(pszPath,dwFlags,NULL)); 
  else 
    return FALSE; 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::GetFile - get a file from the current server 
//       path and store it in a Memory file 
//       use SetPath before for nested folders 
//------------------------------------------------------------------- 
BOOL CObexFTPConnection::GetFile(LPCWSTR pszName,CStreamToMemory &Mem) 
{ 
  if (m_device) 
  { 
    return GetFileOrDir(pszName,NULL,Mem); 
  } 
  else 
  { 
    return FALSE; 
  } 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::PutFile - send data as a file to the current  
//       server path  
//       use SetPath before for nested folders 
//------------------------------------------------------------------- 
BOOL CObexFTPConnection::PutFile(LPCWSTR pszName,void *Data,UINT Size) 
{ 
  if (m_device) 
  { 
    CComPtr Coll; 
    if (SUCCEEDED(Coll.CoCreateInstance(__uuidof(HeaderCollection)))) 
    { 
      if (SUCCEEDED(Coll->AddName(pszName)) && 
          SUCCEEDED(Coll->AddLength(Size))) 
      { 
        CComPtr Stream; 
        if (SUCCEEDED(m_device->Put(Coll,&Stream))) 
        { 
          DWORD Written=0; 
          if (SUCCEEDED(Stream->Write(Data,Size,&Written)) && 
              SUCCEEDED(Stream->Commit(0))) 
          { 
            return TRUE; 
          } 
        } 
      } 
    } 
  } 
  return FALSE; 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::GetDirectory - retrieve the content of the 
//       current server path  
//       use SetPath before for nested folders 
//       see member FindFirstFile, FindNextFile of CObexListing 
//------------------------------------------------------------------- 
BOOL CObexFTPConnection::GetDirectory(CObexListing &Dir) 
{ 
  if (m_device) 
  { 
    return GetFileOrDir(_T(""),"x-obex/folder-listing",Dir); 
  } 
  else 
  { 
    return FALSE; 
  } 
} 
//------------------------------------------------------------------- 
// CObexFTPConnection::GetFileOrDir  
//    helper function for GetFile and GetDirectory 
//------------------------------------------------------------------- 
BOOL CObexFTPConnection::GetFileOrDir(LPCWSTR pszName,const char *mime,CStreamToMemory &Mem) 
{ 
  ATLASSERT(m_device); 
  CComPtr Coll; 
  if (SUCCEEDED(Coll.CoCreateInstance(__uuidof(HeaderCollection)))) 
  { 
    if (SUCCEEDED(Coll->AddName(pszName))) 
    { 
      int mime_len=mime ? strlen(mime) : 0; 
      if (mime_len==0 || SUCCEEDED(Coll->AddType(mime_len+1,(BYTE *)mime))) 
      { 
        CComPtr Stream; 
        if (SUCCEEDED(m_device->Get(Coll,&Stream))) 
        { 
          return Mem.Read(Stream); 
        } 
      } 
    } 
  } 
  return FALSE; 
}