Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp	(revision 43377)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp	(revision 43378)
@@ -99,4 +99,197 @@
 };
 
+/** Set by the signal handler. */
+static volatile bool    g_fCanceled = false;
+
+
+/**
+ * Signal handler that sets g_fCanceled.
+ *
+ * This can be executed on any thread in the process, on Windows it may even be
+ * a thread dedicated to delivering this signal.  Do not doing anything
+ * unnecessary here.
+ */
+static void showProgressSignalHandler(int iSignal)
+{
+    NOREF(iSignal);
+    ASMAtomicWriteBool(&g_fCanceled, true);
+}
+
+/**
+ * Print out progress on the console.
+ *
+ * This runs the main event queue every now and then to prevent piling up
+ * unhandled things (which doesn't cause real problems, just makes things
+ * react a little slower than in the ideal case).
+ */
+DECLHIDDEN(HRESULT) showProgress(ComPtr<IProgress> progress)
+{
+    using namespace com;
+
+    BOOL fCompleted = FALSE;
+    ULONG ulCurrentPercent = 0;
+    ULONG ulLastPercent = 0;
+
+    ULONG ulLastOperationPercent = (ULONG)-1;
+
+    ULONG ulLastOperation = (ULONG)-1;
+    Bstr bstrOperationDescription;
+
+    EventQueue::getMainEventQueue()->processEventQueue(0);
+
+    ULONG cOperations = 1;
+    HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
+    if (FAILED(hrc))
+    {
+        RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
+        RTStrmFlush(g_pStdErr);
+        return hrc;
+    }
+
+    /*
+     * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
+     *       to not get intermixed with other (raw) stdout data which might get
+     *       written in the meanwhile.
+     */
+    RTStrmPrintf(g_pStdErr, "0%%...");
+    RTStrmFlush(g_pStdErr);
+
+    /* setup signal handling if cancelable */
+    bool fCanceledAlready = false;
+    BOOL fCancelable;
+    hrc = progress->COMGETTER(Cancelable)(&fCancelable);
+    if (FAILED(hrc))
+        fCancelable = FALSE;
+    if (fCancelable)
+    {
+        signal(SIGINT,   showProgressSignalHandler);
+#ifdef SIGBREAK
+        signal(SIGBREAK, showProgressSignalHandler);
+#endif
+    }
+
+    hrc = progress->COMGETTER(Completed(&fCompleted));
+    while (SUCCEEDED(hrc))
+    {
+        progress->COMGETTER(Percent(&ulCurrentPercent));
+
+        /* did we cross a 10% mark? */
+        if (ulCurrentPercent / 10  >  ulLastPercent / 10)
+        {
+            /* make sure to also print out missed steps */
+            for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
+            {
+                if (curVal < 100)
+                {
+                    RTStrmPrintf(g_pStdErr, "%u%%...", curVal);
+                    RTStrmFlush(g_pStdErr);
+                }
+            }
+            ulLastPercent = (ulCurrentPercent / 10) * 10;
+        }
+
+        if (fCompleted)
+            break;
+
+        /* process async cancelation */
+        if (g_fCanceled && !fCanceledAlready)
+        {
+            hrc = progress->Cancel();
+            if (SUCCEEDED(hrc))
+                fCanceledAlready = true;
+            else
+                g_fCanceled = false;
+        }
+
+        /* make sure the loop is not too tight */
+        progress->WaitForCompletion(100);
+
+        EventQueue::getMainEventQueue()->processEventQueue(0);
+        hrc = progress->COMGETTER(Completed(&fCompleted));
+    }
+
+    /* undo signal handling */
+    if (fCancelable)
+    {
+        signal(SIGINT,   SIG_DFL);
+#ifdef SIGBREAK
+        signal(SIGBREAK, SIG_DFL);
+#endif
+    }
+
+    /* complete the line. */
+    LONG iRc = E_FAIL;
+    hrc = progress->COMGETTER(ResultCode)(&iRc);
+    if (SUCCEEDED(hrc))
+    {
+        if (SUCCEEDED(iRc))
+            RTStrmPrintf(g_pStdErr, "100%%\n");
+        else if (g_fCanceled)
+            RTStrmPrintf(g_pStdErr, "CANCELED\n");
+        else
+        {
+            RTStrmPrintf(g_pStdErr, "\n");
+            RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
+        }
+        hrc = iRc;
+    }
+    else
+    {
+        RTStrmPrintf(g_pStdErr, "\n");
+        RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
+    }
+    RTStrmFlush(g_pStdErr);
+    return hrc;
+}
+
+DECLHIDDEN(const char *) machineStateToName(MachineState_T machineState, bool fShort)
+{
+    switch (machineState)
+    {
+        case MachineState_PoweredOff:
+            return fShort ? "poweroff"             : "powered off";
+        case MachineState_Saved:
+            return "saved";
+        case MachineState_Aborted:
+            return "aborted";
+        case MachineState_Teleported:
+            return "teleported";
+        case MachineState_Running:
+            return "running";
+        case MachineState_Paused:
+            return "paused";
+        case MachineState_Stuck:
+            return fShort ? "gurumeditation"       : "guru meditation";
+        case MachineState_LiveSnapshotting:
+            return fShort ? "livesnapshotting"     : "live snapshotting";
+        case MachineState_Teleporting:
+            return "teleporting";
+        case MachineState_Starting:
+            return "starting";
+        case MachineState_Stopping:
+            return "stopping";
+        case MachineState_Saving:
+            return "saving";
+        case MachineState_Restoring:
+            return "restoring";
+        case MachineState_TeleportingPausedVM:
+            return fShort ? "teleportingpausedvm"  : "teleporting paused vm";
+        case MachineState_TeleportingIn:
+            return fShort ? "teleportingin"        : "teleporting (incoming)";
+        case MachineState_RestoringSnapshot:
+            return fShort ? "restoringsnapshot"    : "restoring snapshot";
+        case MachineState_DeletingSnapshot:
+            return fShort ? "deletingsnapshot"     : "deleting snapshot";
+        case MachineState_DeletingSnapshotOnline:
+            return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
+        case MachineState_DeletingSnapshotPaused:
+            return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
+        case MachineState_SettingUp:
+            return fShort ? "settingup"           : "setting up";
+        default:
+            break;
+    }
+    return "unknown";
+}
 
 DECLHIDDEN(void) serviceLog(const char *pszFormat, ...)
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h	(revision 43377)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h	(revision 43378)
@@ -113,4 +113,22 @@
 
 /**
+ * Print out progress on the console.
+ *
+ * This runs the main event queue every now and then to prevent piling up
+ * unhandled things (which doesn't cause real problems, just makes things
+ * react a little slower than in the ideal case).
+ */
+DECLHIDDEN(HRESULT) showProgress(ComPtr<IProgress> progress);
+
+/**
+ * Converts the machine state to a human readable string.
+ *
+ * @returns Pointer to the human readable state.
+ * @param   enmMachineState    Machine state to convert.
+ * @param   fShort             Flag whether to return a short form.
+ */
+DECLHIDDEN(const char *) machineStateToName(MachineState_T enmMachineState, bool fShort);
+
+/**
  * Parse the given configuration file and return the interesting config parameters.
  *
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp	(revision 43377)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp	(revision 43378)
@@ -27,4 +27,5 @@
 #include <iprt/log.h>
 #include <iprt/assert.h>
+#include <iprt/message.h>
 
 #include <algorithm>
@@ -36,9 +37,180 @@
 using namespace com;
 
+/**
+ * VM list entry.
+ */
+typedef struct AUTOSTOPVM
+{
+    /** ID of the VM to start. */
+    Bstr           strId;
+    /** Action to do with the VM. */
+    AutostopType_T enmAutostopType;
+} AUTOSTOPVM;
+
+static HRESULT autostartSaveVMState(ComPtr<IConsole> &console)
+{
+    HRESULT rc = S_OK;
+    ComPtr<IProgress> progress;
+
+    do
+    {
+        /* first pause so we don't trigger a live save which needs more time/resources */
+        bool fPaused = false;
+        rc = console->Pause();
+        if (FAILED(rc))
+        {
+            bool fError = true;
+            if (rc == VBOX_E_INVALID_VM_STATE)
+            {
+                /* check if we are already paused */
+                MachineState_T machineState;
+                CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
+                /* the error code was lost by the previous instruction */
+                rc = VBOX_E_INVALID_VM_STATE;
+                if (machineState != MachineState_Paused)
+                {
+                    RTMsgError("Machine in invalid state %d -- %s\n",
+                               machineState, machineStateToName(machineState, false));
+                }
+                else
+                {
+                    fError = false;
+                    fPaused = true;
+                }
+            }
+            if (fError)
+                break;
+        }
+
+        CHECK_ERROR(console, SaveState(progress.asOutParam()));
+        if (FAILED(rc))
+        {
+            if (!fPaused)
+                console->Resume();
+            break;
+        }
+
+        rc = showProgress(progress);
+        CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
+        if (FAILED(rc))
+        {
+            if (!fPaused)
+                console->Resume();
+        }
+    } while (0);
+
+    return rc;
+}
+
 DECLHIDDEN(RTEXITCODE) autostartStopMain(PCFGAST pCfgAst)
 {
     RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-
-    AssertMsgFailed(("Not implemented yet!\n"));
+    int vrc = VINF_SUCCESS;
+    std::list<AUTOSTOPVM> listVM;
+
+    /*
+     * Build a list of all VMs we need to autostop first, apply the overrides
+     * from the configuration and start the VMs afterwards.
+     */
+    com::SafeIfaceArray<IMachine> machines;
+    HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
+    if (SUCCEEDED(rc))
+    {
+        /*
+         * Iterate through the collection and construct a list of machines
+         * we have to check.
+         */
+        for (size_t i = 0; i < machines.size(); ++i)
+        {
+            if (machines[i])
+            {
+                BOOL fAccessible;
+                CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
+                if (!fAccessible)
+                    continue;
+
+                AutostopType_T enmAutostopType;
+                CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostopType)(&enmAutostopType));
+                if (enmAutostopType != AutostopType_Disabled)
+                {
+                    AUTOSTOPVM autostopVM;
+
+                    CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostopVM.strId.asOutParam()));
+                    autostopVM.enmAutostopType = enmAutostopType;
+
+                    listVM.push_back(autostopVM);
+                }
+            }
+        }
+
+        if (   SUCCEEDED(rc)
+            && listVM.size())
+        {
+            std::list<AUTOSTOPVM>::iterator it;
+            for (it = listVM.begin(); it != listVM.end(); it++)
+            {
+                MachineState_T enmMachineState;
+                ComPtr<IMachine> machine;
+
+                CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
+                                                             machine.asOutParam()));
+
+                CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
+
+                /* Only power off running machines. */
+                /** @todo: What about transient VM states? */
+                if (   enmMachineState == MachineState_Running
+                    || enmMachineState == MachineState_Paused)
+                {
+                    ComPtr<IMachine> sessionMachine;
+                    ComPtr<IConsole> console;
+                    ComPtr<IProgress> progress;
+
+                    /* open a session for the VM */
+                    CHECK_ERROR_BREAK(machine, LockMachine(g_pSession, LockType_Shared));
+
+                    /* get the associated console */
+                    CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
+                    CHECK_ERROR_BREAK(g_pSession, COMGETTER(Machine)(sessionMachine.asOutParam()));
+
+                    switch ((*it).enmAutostopType)
+                    {
+                        case AutostopType_SaveState:
+                        {
+                            rc = autostartSaveVMState(console);
+                            break;
+                        }
+                        case AutostopType_PowerOff:
+                        {
+                            CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
+
+                            rc = showProgress(progress);
+                            CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
+                            break;
+                        }
+                        case AutostopType_AcpiShutdown:
+                        {
+                            /** @todo: Wait for VM to change to powered off state. */
+                            BOOL fGuestEnteredACPI = false;
+                            CHECK_ERROR_BREAK(console, GetGuestEnteredACPIMode(&fGuestEnteredACPI));
+                            if (fGuestEnteredACPI)
+                                CHECK_ERROR_BREAK(console, PowerButton());
+                            else
+                            {
+                                /* Use save state instead and log this to the console. */
+                                serviceLog("The guest of VM \"%ls\" does not support ACPI shutdown, saving state...\n",
+                                           (*it).strId.raw());
+                                rc = autostartSaveVMState(console);
+                            }
+                            break;
+                        }
+                        default:
+                            serviceLog("Unknown autostop type for VM \"%ls\"\n", (*it).strId.raw());
+                    }
+                }
+                g_pSession->UnlockMachine();
+            }
+        }
+    }
 
     return rcExit;
