root/src/apps/softwareupdater/SoftwareUpdaterApp.cpp
/*
 * Copyright 2016-2017 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT license
 *
 * Authors:
 *              Alexander von Gluck IV <kallisti5@unixzen.com>
 *              Brian Hill <supernova@tycho.email>
 */

#include "SoftwareUpdaterApp.h"

#include <getopt.h>
#include <stdlib.h>

#include <Catalog.h>

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SoftwareUpdaterApp"


static const char* const kUsage = B_TRANSLATE_COMMENT(
        "Usage:  SoftwareUpdater <command> [ <option> ]\n"
        "Updates installed packages.\n"
        "\n"
        "Commands:\n"
        "  update     - Search repositories for updates on all packages.\n"
        "  check      - Check for available updates but only display a "
                "notification with results.\n"
        "  full-sync  - Synchronize the installed packages with the "
                "repositories.\n"
        "\n"
        "Options:\n"
        "  -h or --help       Print this usage help\n"
        "  -v or --verbose    Output verbose information\n",
        "Command line usage help")
;

static struct option const kLongOptions[] = {
        {"verbose", no_argument, 0, 'v'},
        {"help", no_argument, 0, 'h'},
        {NULL}
};


SoftwareUpdaterApp::SoftwareUpdaterApp()
        :
        BApplication(kAppSignature),
        fWorker(NULL),
        fFinalQuitFlag(false),
        fActionRequested(FULLSYNC),
        fVerbose(false),
        fArgvsAccepted(true)
{
}


SoftwareUpdaterApp::~SoftwareUpdaterApp()
{
        if (fWorker) {
                fWorker->Lock();
                fWorker->Quit();
        }
}


bool
SoftwareUpdaterApp::QuitRequested()
{
        if (fFinalQuitFlag)
                return true;

        // Simulate a cancel request from window- this gives the updater a chance
        // to quit cleanly
        if (fWindowMessenger.IsValid())
                fWindowMessenger.SendMessage(kMsgCancel);
        return true;
}


void
SoftwareUpdaterApp::ReadyToRun()
{
        // Argvs no longer accepted once the process starts
        fArgvsAccepted = false;

        fWorker = new WorkingLooper(fActionRequested, fVerbose);
}


void
SoftwareUpdaterApp::ArgvReceived(int32 argc, char **argv)
{
        if (!fArgvsAccepted) {
                fputs(B_TRANSLATE("Argument variables are no longer accepted\n"),
                        stderr);
                return;
        }

        int c;
        while ((c = getopt_long(argc, argv, "hv", kLongOptions, NULL)) != -1) {
                switch (c) {
                        case 0:
                                break;
                        case 'h':
                                fputs(kUsage, stdout);
                                exit(0);
                                break;
                        case 'v':
                                fVerbose = true;
                                break;
                        default:
                                fputs(kUsage, stderr);
                                exit(1);
                                break;
                }
        }

        const char* command = "";
        int32 argCount = argc - optind;
        if (argCount == 0)
                return;
        else if (argCount > 1) {
                fputs(kUsage, stderr);
                exit(1);
        } else
                command = argv[optind];

        fActionRequested = USER_SELECTION_NEEDED;
        if (strcmp("update", command) == 0)
                fActionRequested = UPDATE;
        else if (strcmp("check", command) == 0)
                fActionRequested = UPDATE_CHECK_ONLY;
        else if (strcmp("full-sync", command) == 0)
                fActionRequested = FULLSYNC;
        else {
                fputs(B_TRANSLATE_COMMENT("Unrecognized argument", "Error message"),
                        stderr);
                fprintf(stderr, " \"%s\"\n", command);
                fputs(kUsage, stderr);
        }
}


void
SoftwareUpdaterApp::MessageReceived(BMessage* message)
{
        switch (message->what) {
                case kMsgRegister:
                        message->FindMessenger(kKeyMessenger, &fWindowMessenger);
                        break;

                case kMsgFinalQuit:
                        fFinalQuitFlag = true;
                        PostMessage(B_QUIT_REQUESTED);
                        break;

                default:
                        BApplication::MessageReceived(message);
        }
}


int
main(int argc, const char* const* argv)
{
        SoftwareUpdaterApp app;
        return app.Run();
}