/*
 * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 */

#include "rddnsclient.h"
#include "httpclient.h"
#include "crypt.h"
#include <stdio.h>
#include <string.h>

static int rddns_query(unsigned const char * path,
                       unsigned const char * querystring,
                       unsigned char * result_buffer, size_t result_buffer_len)
{
    unsigned char urlbuf[1024];
    unsigned char cyphertext[64];
    unsigned char * p;
    unsigned int i;
    struct hc * hc;
    u32 cyphertext_len;
    unsigned char * buf;
    size_t len;
    
    if (rtv_encrypt(querystring, strlen(querystring),
                    cyphertext, sizeof cyphertext, &cyphertext_len, 0) < 0) {
        fprintf(stderr, "ERROR: encrypt failure\n");
        return -1;
    }

    /* rddns-rns.replaytv.net */
    if (strlen("http://rddns-production.replaytv.net%s?q=") + 2*cyphertext_len + 1 > sizeof urlbuf) {
        fprintf(stderr, "ERROR rddns_lookup: urlbuf too small\n");
        return -1;
    }
    
    p = urlbuf + sprintf(urlbuf, "http://rddns-production.replaytv.net%s?q=", path);
    for (i = 0; i < cyphertext_len; i++) {
        p += sprintf(p, "%02x", cyphertext[i]);
    }
    hc = hc_start_request(urlbuf);
    if (!hc) {
        fprintf(stderr, "ERROR rddns_lookup: hc_start_request %s failed\n",
                urlbuf);
        hc_free(hc);
        return -1;
    }
    if (hc_send_request(hc) < 0) {
        fprintf(stderr, "ERROR rddns_lookup: hc_send_request failed\n");
        hc_free(hc);
        return -1;
    }
    if (hc_get_status(hc)/100 != 2) {
        fprintf(stderr, "ERROR rddns_lookup http status %d\n",
                hc_get_status(hc));
        hc_free(hc);
        return -1;
    }
    buf = hc_read_all_len(hc, &len);
    if (buf == NULL) {
        fprintf(stderr, "ERROR rddns_lookup read failed\n");
        hc_free(hc);
        return -1;
    }
    hc_free(hc);

    rtv_decrypt(buf, len,
                result_buffer, result_buffer_len,
                NULL, NULL, 0);
    free(buf);
    
    return 0;
}

int rddns_lookup(unsigned const char * ISN,
                 unsigned char * result_buffer, size_t result_buffer_len)
{
    unsigned char querystring[32];
    
    if (!ISN) {
        fprintf(stderr, "ERROR: rddns_lookup: null ISN\n");
        return -1;
    }
    if (strlen(ISN) != 17) {
        fprintf(stderr, "ERROR: rddns_lookup: invalid ISN\n");
        return -1;
    }
    sprintf(querystring, "isn=%s", ISN);

    if (rddns_query("/rd/servlet/gu", querystring,
                    result_buffer, result_buffer_len) < 0) {
        fprintf(stderr, "ERROR: rddns_lookup: rddns_query failed\n");
        return -1;
    }
    
    return 0;
}

int rddns_update(unsigned const char * ISN, unsigned short port,
                 unsigned char * result_buffer, size_t result_buffer_len)
{
    unsigned char querystring[64];
    
    if (!ISN) {
        fprintf(stderr, "ERROR: rddns_lookup: null ISN\n");
        return -1;
    }
    if (strlen(ISN) != 17) {
        fprintf(stderr, "ERROR: rddns_lookup: invalid ISN\n");
        return -1;
    }
    sprintf(querystring, "isn=%s&port=%d", ISN, port);

    if (rddns_query("/rd/servlet/ul", querystring,
                    result_buffer, result_buffer_len) < 0) {
        fprintf(stderr, "ERROR: rddns_lookup: rddns_query failed\n");
        return -1;
    }
    
    return 0;
}

