Index: /trunk/src/VBox/Main/include/GuestSessionImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 42565)
+++ /trunk/src/VBox/Main/include/GuestSessionImpl.h	(revision 42566)
@@ -31,5 +31,83 @@
 
 /**
- * TODO
+ * Abstract base class for a lenghtly per-session operation which
+ * runs in a Main worker thread.
+ */
+class GuestSessionTask
+{
+public:
+
+    GuestSessionTask(GuestSession *pSession, Progress *pProgress);
+
+    virtual ~GuestSessionTask(void);
+
+public:
+
+    virtual int Run(void) = 0;
+    virtual int RunAsync(const Utf8Str &strDesc) = 0;
+
+    int setProgress(unsigned uPercent);
+    int setProgressSuccess(void);
+    int setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg);
+
+protected:
+
+    Utf8Str                 mDesc;
+    ComObjPtr<GuestSession> mSession;
+    ComObjPtr<Progress>     mProgress;
+};
+
+/**
+ * Task for copying files from host to the guest.
+ */
+class SessionTaskCopyTo : public GuestSessionTask
+{
+public:
+
+    SessionTaskCopyTo(GuestSession *pSession, Progress *pProgress,
+                      const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);
+
+    virtual ~SessionTaskCopyTo(void);
+
+public:
+
+    int Run(void);
+    int RunAsync(const Utf8Str &strDesc);
+    static int taskThread(RTTHREAD Thread, void *pvUser);
+
+protected:
+
+    Utf8Str  mSource;
+    Utf8Str  mDest;
+    uint32_t mFlags;
+};
+
+/**
+ * Task for copying files from guest to the host.
+ */
+class SessionTaskCopyFrom : public GuestSessionTask
+{
+public:
+
+    SessionTaskCopyFrom(GuestSession *pSession, Progress *pProgress,
+                        const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);
+
+    virtual ~SessionTaskCopyFrom(void);
+
+public:
+
+    int Run(void);
+    int RunAsync(const Utf8Str &strDesc);
+    static int taskThread(RTTHREAD Thread, void *pvUser);
+
+protected:
+
+    Utf8Str  mSource;
+    Utf8Str  mDest;
+    uint32_t mFlags;
+};
+
+/**
+ * Guest session implementation.
  */
 class ATL_NO_VTABLE GuestSession :
@@ -72,6 +150,6 @@
      * @{ */
     STDMETHOD(Close)(void);
-    STDMETHOD(CopyFrom)(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(ULONG, aFlags), IProgress **aProgress);
-    STDMETHOD(CopyTo)(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(ULONG, aFlags), IProgress **aProgress);
+    STDMETHOD(CopyFrom)(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress);
+    STDMETHOD(CopyTo)(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress);
     STDMETHOD(DirectoryCreate)(IN_BSTR aPath, ULONG aMode, ComSafeArrayIn(DirectoryCreateFlag_T, aFlags), IGuestDirectory **aDirectory);
     STDMETHOD(DirectoryCreateTemp)(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aName, IGuestDirectory **aDirectory);
@@ -137,4 +215,5 @@
     inline bool             processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess);
     inline int              processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess);
+    int                     startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress);
     int                     queryInfo(void);
     /** @}  */
Index: /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 42565)
+++ /trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp	(revision 42566)
@@ -2860,5 +2860,5 @@
     while (itSessions != mData.mGuestSessions.end())
     {
-        if (strName.equals(itSessions->second->getName()))
+        if (strName.contains(itSessions->second->getName())) /** @todo Use a (simple) pattern match (IPRT?). */
             listSessions.push_back(itSessions->second);
         itSessions++;
Index: /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 42565)
+++ /trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp	(revision 42566)
@@ -27,4 +27,5 @@
 #include "Global.h"
 #include "AutoCaller.h"
+#include "ProgressImpl.h"
 
 #include <iprt/env.h>
@@ -51,4 +52,149 @@
     BaseFinalRelease();
     LogFlowThisFuncLeave();
+}
+
+// session task classes
+/////////////////////////////////////////////////////////////////////////////
+
+GuestSessionTask::GuestSessionTask(GuestSession *pSession, Progress *pProgress)
+{
+    mSession = pSession;
+    mProgress = pProgress;
+}
+
+GuestSessionTask::~GuestSessionTask(void)
+{
+}
+
+int GuestSessionTask::setProgress(unsigned uPercent)
+{
+    BOOL fCanceled;
+    mProgress->COMGETTER(Canceled)(&fCanceled);
+    if (fCanceled)
+        return VERR_CANCELLED;
+    mProgress->SetCurrentOperationProgress(uPercent);
+
+    return VINF_SUCCESS;
+}
+
+int GuestSessionTask::setProgressSuccess(void)
+{
+    BOOL fCanceled;
+    BOOL fCompleted;
+    if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
+        && !fCanceled
+        && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
+        && !fCompleted)
+    {
+        HRESULT hr = mProgress->notifyComplete(S_OK);
+        ComAssertComRC(hr);
+    }
+
+    return VINF_SUCCESS;
+}
+
+int GuestSessionTask::setProgressErrorMsg(HRESULT hr, const Utf8Str &strMsg)
+{
+    BOOL fCanceled;
+    BOOL fCompleted;
+    if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
+        && !fCanceled
+        && SUCCEEDED(mProgress->COMGETTER(Completed(&fCompleted)))
+        && !fCompleted)
+    {
+        HRESULT hr = mProgress->notifyComplete(hr,
+                                               COM_IIDOF(IGuestSession),
+                                               GuestSession::getStaticComponentName(),
+                                               strMsg.c_str());
+        if (FAILED(hr))
+            return VERR_COM_UNEXPECTED;
+    }
+    return VINF_SUCCESS;
+}
+
+SessionTaskCopyTo::SessionTaskCopyTo(GuestSession *pSession, Progress *pProgress,
+                                     const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
+                                     : GuestSessionTask(pSession, pProgress)
+{
+    mSource = strSource;
+    mDest   = mDest;
+    mFlags  = uFlags;
+}
+
+SessionTaskCopyTo::~SessionTaskCopyTo(void)
+{
+
+}
+
+int SessionTaskCopyTo::Run(void)
+{
+    return 0;
+}
+
+int SessionTaskCopyTo::RunAsync(const Utf8Str &strDesc)
+{
+    LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, uFlags=%x\n",
+                     strDesc.c_str(), mSource.c_str(), mDest.c_str(), mFlags));
+
+    mDesc = strDesc;
+
+    int rc = RTThreadCreate(NULL, SessionTaskCopyTo::taskThread, this,
+                            0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
+                            "gctlCpyTo");
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/* static */
+int SessionTaskCopyTo::taskThread(RTTHREAD Thread, void *pvUser)
+{
+    std::auto_ptr<SessionTaskCopyTo> task(static_cast<SessionTaskCopyTo*>(pvUser));
+    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
+
+    LogFlowFunc(("pTask=%p\n", task.get()));
+    return task->Run();
+}
+
+SessionTaskCopyFrom::SessionTaskCopyFrom(GuestSession *pSession, Progress *pProgress,
+                                         const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
+                                         : GuestSessionTask(pSession, pProgress)
+{
+    mSource = strSource;
+    mDest   = mDest;
+    mFlags  = uFlags;
+}
+
+SessionTaskCopyFrom::~SessionTaskCopyFrom(void)
+{
+
+}
+
+int SessionTaskCopyFrom::Run(void)
+{
+    return 0;
+}
+
+int SessionTaskCopyFrom::RunAsync(const Utf8Str &strDesc)
+{
+    LogFlowThisFunc(("strDesc=%s, strSource=%s, strDest=%s, uFlags=%x\n",
+                     strDesc.c_str(), mSource.c_str(), mDest.c_str(), mFlags));
+
+    mDesc = strDesc;
+
+    int rc = RTThreadCreate(NULL, SessionTaskCopyFrom::taskThread, this,
+                            0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
+                            "gctlCpyFrom");
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/* static */
+int SessionTaskCopyFrom::taskThread(RTTHREAD Thread, void *pvUser)
+{
+    std::auto_ptr<SessionTaskCopyFrom> task(static_cast<SessionTaskCopyFrom*>(pvUser));
+    AssertReturn(task.get(), VERR_GENERAL_FAILURE);
+
+    LogFlowFunc(("pTask=%p\n", task.get()));
+    return task->Run();
 }
 
@@ -761,4 +907,42 @@
 }
 
+int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
+                                 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
+{
+    LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
+
+    AssertPtrReturn(pTask, VERR_INVALID_POINTER);
+
+    int rc;
+
+    try
+    {
+        /* Create the progress object. */
+        HRESULT hr = pProgress.createObject();
+        if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
+
+        hr = pProgress->init(static_cast<IGuestSession*>(this),
+                             Bstr(strTaskDesc).raw(),
+                             TRUE /* aCancelable */);
+        if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
+
+        /* Initialize our worker task. */
+        std::auto_ptr<GuestSessionTask> task(pTask);
+
+        rc = task->RunAsync(strTaskDesc);
+        if (FAILED(rc)) throw rc;
+
+        /* Don't destruct on success. */
+        task.release();
+    }
+    catch (int rc2)
+    {
+        rc = rc2;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
 /**
  * Queries/collects information prior to establishing a guest session.
@@ -770,4 +954,8 @@
 int GuestSession::queryInfo(void)
 {
+#if 1
+    /* Since the new functions were not implemented yet, force Main to use protocol ver 1. */
+    mData.mProtocolVersion = 1;
+#else
     /*
      * Try querying the guest control protocol version running on the guest.
@@ -779,5 +967,5 @@
     uint32_t uVerAdditions = pGuest->getAdditionsVersion();
     mData.mProtocolVersion = (   VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions) >= 4
-                              && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2)
+                              && VBOX_FULL_VERSION_GET_MINOR(uVerAdditions) >= 2) /** @todo What's about v5.0 ? */
                            ? 2  /* Guest control 2.0. */
                            : 1; /* Legacy guest control (VBox < 4.2). */
@@ -789,5 +977,5 @@
         LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
                 VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions), mData.mProtocolVersion));
-
+#endif
     return VINF_SUCCESS;
 }
@@ -810,29 +998,97 @@
 }
 
-STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(ULONG, aFlags), IProgress **aProgress)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else
-    LogFlowThisFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    ReturnComNotImplemented();
-#endif /* VBOX_WITH_GUEST_CONTROL */
-}
-
-STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(ULONG, aFlags), IProgress **aProgress)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else
-    LogFlowThisFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    ReturnComNotImplemented();
+STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    CheckComArgStrNotEmptyOrNull(aSource);
+    CheckComArgStrNotEmptyOrNull(aDest);
+    CheckComArgOutPointerValid(aProgress);
+
+    LogFlowThisFuncEnter();
+
+    if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
+        return setError(E_INVALIDARG, tr("No source specified"));
+    if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
+        return setError(E_INVALIDARG, tr("No destination specified"));
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    uint32_t fFlags = CopyFileFlag_None;
+    if (aFlags)
+    {
+        com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
+        for (size_t i = 0; i < flags.size(); i++)
+            fFlags |= flags[i];
+    }
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT hr = S_OK;
+
+    ComObjPtr<Progress> pProgress;
+    SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this, pProgress,
+                                                         Utf8Str(aSource), Utf8Str(aDest), fFlags);
+    AssertPtrReturn(pTask, VERR_NO_MEMORY);
+    int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
+                            pTask, pProgress);
+    if (RT_SUCCESS(rc))
+    {
+        /* Return progress to the caller. */
+        hr = pProgress.queryInterfaceTo(aProgress);
+    }
+
+    /** @todo rc -> hr error lookup. */
+    return hr;
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
+STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else
+    CheckComArgStrNotEmptyOrNull(aSource);
+    CheckComArgStrNotEmptyOrNull(aDest);
+    CheckComArgOutPointerValid(aProgress);
+
+    LogFlowThisFuncEnter();
+
+    if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
+        return setError(E_INVALIDARG, tr("No source specified"));
+    if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
+        return setError(E_INVALIDARG, tr("No destination specified"));
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    uint32_t fFlags = CopyFileFlag_None;
+    if (aFlags)
+    {
+        com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
+        for (size_t i = 0; i < flags.size(); i++)
+            fFlags |= flags[i];
+    }
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    HRESULT hr = S_OK;
+
+    ComObjPtr<Progress> pProgress;
+    SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this, pProgress,
+                                                     Utf8Str(aSource), Utf8Str(aDest), fFlags);
+    AssertPtrReturn(pTask, VERR_NO_MEMORY);
+    int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
+                            pTask, pProgress);
+    if (RT_SUCCESS(rc))
+    {
+        /* Return progress to the caller. */
+        hr = pProgress.queryInterfaceTo(aProgress);
+    }
+
+    /** @todo rc -> hr error lookup. */
+    return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
 }
@@ -1302,5 +1558,4 @@
     HRESULT hr = ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
                                  ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinity), aProcess);
-    LogFlowFuncLeaveRC(hr);
     return hr;
 #endif /* VBOX_WITH_GUEST_CONTROL */
@@ -1444,26 +1699,4 @@
 }
 
-#if 0
-STDMETHODIMP GuestSession::SetTimeout(ULONG aTimeoutMS)
-{
-#ifndef VBOX_WITH_GUEST_CONTROL
-    ReturnComNotImplemented();
-#else
-    LogFlowThisFuncEnter();
-
-    AutoCaller autoCaller(this);
-    if (FAILED(autoCaller.rc())) return autoCaller.rc();
-
-    if (aTimeoutMS < 1000)
-        return setError(E_INVALIDARG, tr("Invalid timeout value specified"));
-
-    mData.mTimeout = aTimeoutMS;
-
-    LogFlowThisFunc(("aTimeoutMS=%RU32\n", mData.mTimeout));
-    return S_OK;
-#endif /* VBOX_WITH_GUEST_CONTROL */
-}
-#endif
-
 STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
 {
