/* (C) 2003-2007 Willem Jan Hengeveld <itsme@xs4all.nl>
 * Web: http://www.xs4all.nl/~itsme/
 *      http://wiki.xda-developers.com/
 *
 * $Id$
 */
#include <util/wintypes.h>
#include <stdio.h>
#include "debug.h"
#include <util/rapitypes.h>
#include "stringutils.h"
#include "args.h"
#include "FileFunctions.h"

#include "ConfigApi.h"

void usage()
{
    printf("(C) 2003-2008 Willem jan Hengeveld  itsme@xs4all.nl\n");
    debug("Usage: prapi [-q|-d] [-p | -s | -c | -m] <params>\n");
    debug("   -v                              : verbose: always print repsonse\n");
    debug("   -q -p <policyid>                : query policy setting\n");
    debug("   -p <policyid> <policyvalue>     : set policy\n");
    debug("   -d -p <policyid>                : delete policy setting\n");

    debug("   -q -m <key>                     : query metabase key\n");
    debug("   -m <key> [-r role] [-a access]  : set metabase key\n");
    debug("   -d -m <key>                     : delete metabase key\n");

    debug("   -q <key> [<name>]               : query registry key or value\n");
    debug("   -s <key> <name> <type> <value>  : set registry key\n");
    debug("   -d <key> [<name>]               : delete registry key or value\n");

    debug("   -q -c[STORE] [file.cer]         : query certificate, whole store, or one cert\n");
    debug("   -c[STORE] [-r role] <file.cer>  : add certificate to store\n");
    debug("   -d -c[STORE] <file.cer>         : delete certificate from store\n");

    debug("Stores: codesigning: p=privileged, u=unprivileged, c=SPC/cabsigning\n");
    debug("      ssl/webserver: a=Certificate Authorities, r=root, m=my\n");
}
int main(int argc, char **argv)
{
    DebugStdOut();

    bool bPrintAnswer= false;

    bool doSetSecurityPolicy= false;
    bool doSetRegistryValue= false;
    bool doSetMetabase= false;
    bool doDelete= false;
    bool doQuery= false;
    bool doLoadCertificate= false;
    DWORD dwCertStore= 0;
    DWORD role=0;
    DWORD rwaccess=3;
    StringList args;
    for (int i=1 ; i<argc ; i++)
    {
        if (argv[i][0]=='-') switch(argv[i][1])
        {
            case 'p': doSetSecurityPolicy=true; break;
            case 'm': doSetMetabase=true; break;
            case 's': doSetRegistryValue=true; break;
            case 'd': doDelete=true; break;
            case 'q': doQuery=true; break;
            case 'v': bPrintAnswer=true; break;
            case 'r': HANDLEULOPTION(role,DWORD); break;
            case 'a': HANDLEULOPTION(rwaccess,DWORD); break;
            case 'c': doLoadCertificate=true; 
                  switch(argv[i][2]) {
                      case 'p': dwCertStore=CERTSTORE_PRIVILEGED;   break;
                      case 'u': dwCertStore=CERTSTORE_UNPRIVILEGED; break;
                      case 'c': dwCertStore=CERTSTORE_SPC;          break;
                      case 'a': dwCertStore=CERTSTORE_CA;           break;
                      case 'r': dwCertStore=CERTSTORE_ROOT;         break;
                      case 'm': dwCertStore=CERTSTORE_MY;           break;
                      default:  dwCertStore=CERTSTORE_PRIVILEGED;
                  }
                  break;
            default:
                  usage();
                  return 1;
        }
        else {
            args.push_back(argv[i]);
        }
    }

    std::string xml;
    if (doSetSecurityPolicy) {
        if (doQuery) {
            if (args.size()!=1) { usage(); return 1; }
            xml= pd_GetSecurityPolicy(strtoul(args[0].c_str(), 0, 0));
            bPrintAnswer= true;
        }
        else if (doDelete) {
            if (args.size()!=1) { usage(); return 1; }
            xml= pd_DeleteSecurityPolicy(strtoul(args[0].c_str(), 0, 0));
        }
        else {
            if (args.size()!=2) { usage(); return 1; }
            xml= pd_SetSecurityPolicy(strtoul(args[0].c_str(), 0, 0), strtoul(args[1].c_str(), 0, 0));
        }
    }
    else if (doSetMetabase) {
        if (doQuery) {
            if (args.size()!=1) { usage(); return 1; }

            xml= pd_QueryMetabaseKey(args[0]);
            bPrintAnswer= true;
        }
        else if (doDelete) {
            if (args.size()!=1) { usage(); return 1; }

            xml= pd_DeleteMetabaseKey(args[0]);
        }
        else {
            if (args.size()!=1) { usage(); return 1; }

            xml= pd_SetMetabaseKey(args[0], rwaccess, role);
        }
    }
    else if (doLoadCertificate) {
        if (doQuery) {
            if (args.size()) {
                std::string sha1hex_str;
                if (!calc_cert_sha1(args[0], sha1hex_str))
                    return 1;
                xml= pd_QueryCertificateStore(storenames[dwCertStore], sha1hex_str);
            }
            else {
                xml= pd_QueryCertificateStore(storenames[dwCertStore]);
            }
            bPrintAnswer= true;
        }
        else if (doDelete) {
            if (args.size()!=1) { usage(); return 1; }
            std::string sha1hex_str;
            if (!calc_cert_sha1(args[0], sha1hex_str))
                return 1;
            xml= pd_DeleteCertificate(storenames[dwCertStore], sha1hex_str);
        }
        else {
            if (args.size()!=1) { usage(); return 1; }

            // todo: fix crash when files does not exist

            ByteVector cert;
            if (!get_cert_from_file(args[0], cert)) {
                return 1;
            }
            xml= pd_LoadCertificate(storenames[dwCertStore], role, cert);
        }
    }
    else if (doQuery) {
        if (args.size()==1)
            xml= pd_QueryRegistryKey(args[0]);
        else if (args.size()==2)
            xml= pd_QueryRegistryValue(args[0], args[1]);
        else {
            usage();
            return 1;
        }
        bPrintAnswer= true;
    }
    else if (doSetRegistryValue) {
        if (args.size()!=4) { usage(); return 1; }
        xml= pd_SetRegistryValue(args[0], args[1], args[2], args[3]);
    }
    else if (doDelete) {
        if (args.size()==1)
            xml= pd_DeleteRegistryKey(args[0]);
        else if (args.size()>=2)
            xml= pd_DeleteRegistryValues(args[0], args.begin()+1, args.end());
        else {
            usage();
            return 1;
        }
    }
    else {
        usage();
        return 1;
    }

    if (!LoadRapi())
        return 1;

    if (xml.empty()) {
        printf("error - no query selected\n");
        usage();
        return 1;
    }
    std::string answer;
    bool bRes= LoadProvisioningDoc(xml, answer);
    int nResult= bRes ? 0 : 1;

    UnloadRapi();
    if (bPrintAnswer) {
        for (size_t i=answer.find("><") ; i!=answer.npos ; i= answer.find("><", i+1))
            answer.replace(i, 2, ">\n<");

        // .. don't use debug here, it truncates at 16K
        fputs(answer.c_str(), stdout);
    }
    return nResult;
}

