#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "osfile.h"
#include "osfscontrol.h"

#include "toolbox.h"
#include "window.h"
#include "radiobutton.h"
#include "writablefield.h"
#include "stringset.h"
#include "numberrange.h"
#include "button.h"
#include "optionbutton.h"
#include "draggable.h"
#include "actionbutton.h"

#include "rc5wimp.h"
#include "config.h"
#include "iniread.h"
#include "task.h"
#include "sound.h"

IniSection parameters;
bool have_params;
bool hidden;

toolbox_o choices_handle, choices_pane[7];

#define cmp_Set 0x2600
#define cmp_Tab0 0x2603
#define cmp_id 0x2650

#define cmp_Keyserver 0x4
#define cmp_KSPort 0x5
#define cmp_Proxy 0x8
#define cmp_ProxyLabel 0xA
#define cmp_PPort 0x9
#define cmp_Encoding 0xB
#define cmp_PassButton 0xD
#define cmp_NoFallback 0xE
#define cmp_NetTimeout 0xF
#define cmp_NoAutoKeyserver 0x12
#define cmp_NoAutoKSPort 0x13

#define cmp_RC5in 0x2
#define cmp_RC5out 0x4
#define cmp_DESin 0x6
#define cmp_DESout 0x8
#define cmp_DoDES 0x9
#define cmp_BlockSize 0xB
#define cmp_CkEnable 0x216
#define cmp_CkName 0x16
#define cmp_CkPopup 0x116

#define cmp_EmailEnable 0x14
#define cmp_EmailTarget 0x4
#define cmp_EmailSender 0x7
#define cmp_SMTPhost 0x9
#define cmp_SMTPport 0xF
#define cmp_EmailSize 0x10
#define cmp_MooType 0x12
#define cmp_MooEnable 0x13
#define cmp_MooTest 0x16
#define cmp_LogEnable 0x201
#define cmp_LogName 0x1
#define cmp_LogPopup 0x101

/*
    #define cmp_Timeslice 0x1
*/
#define cmp_CPU 0x3
#define cmp_NumCPU 0x8

#define cmp_ConnOnline 0x1
#define cmp_ConnOffline 0x2
#define cmp_ConnHelp 0x10

#define cmp_Autostart 0x0
#define cmp_Hide 0x1

#define cmp_UserID 0x2
#define cmp_Password 0x3

#define cmp_SaveAsDrag 0x82BC00
#define cmp_SaveAsName 0x82BC01

#define false 0
#define true 1

static bool CheckForcedKeyport(int *keyport)
{
  bool Forced = false;

  char keyproxy[64], *dot;

  stringsetgetselected_string(0, choices_pane[1], cmp_Keyserver, keyproxy, sizeof keyproxy);

  dot = strchr(keyproxy, '.');

  if (dot && (strcmpi(dot, ".v27.distributed.net") == 0 ||
      strcmpi(dot, ".distributed.net") == 0))
  {
    int foundport = 2064;
    char *p;

    for (p = keyproxy; p < dot; p++)
      if (isdigit(*p)) { foundport = atoi(p); break; }
    if (foundport == 2064 || foundport == 23 || foundport == 80)
    {
      if (*keyport != 3064)
        *keyport = foundport;
      Forced = true;
    }
  }

  return Forced;
}

#define B64_ENC(Ch) (char) (base64table[(char)(Ch) & 63])

void base64_encode(char *out, const char *username, const char *password)
{
  char in[160];
  static char base64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

  unsigned int length = strlen(username) + strlen(password) + 1;
  char *b = out, *data = in;

  sprintf(in, "%s:%s\n", username, password);

  for (; length > 2; length -= 3, data += 3)
  {
    *b++ = B64_ENC(data[0] >> 2);
    *b++ = B64_ENC(((data[0] << 4) & 060) | ((data[1] >> 4) & 017));
    *b++ = B64_ENC(((data[1] << 2) & 074) | ((data[2] >> 6) & 03));
    *b++ = B64_ENC(data[2] & 077);
  }

  if (length == 1)
  {
    *b++ = B64_ENC(data[0] >> 2);
    *b++ = B64_ENC((data[0] << 4) & 060);
    *b++ = '=';
    *b++ = '=';
  }
  else if (length == 2)
  {
    *b++ = B64_ENC(data[0] >> 2);
    *b++ = B64_ENC(((data[0] << 4) & 060) | ((data[1] >> 4) & 017));
    *b++ = B64_ENC((data[1] << 2) & 074);
    *b++ = '=';
  }
  *b = 0;
}

void canonicalise(const char *leaf, char *buffer, int bufsize)
{
    char our_path[1024];

    sprintf(our_path, "%s.", our_dir);

    osfscontrol_canonicalise_path(leaf, buffer, NULL, our_path, bufsize);
}

int ReadConfig()
{
    char filename[1024];

    if (have_params)
        IniSection_destroy(&parameters);

    IniSection_init(&parameters);

    sprintf(filename, "%s.rc5des/ini", our_dir);

    return IniSection_ReadIniFile(&parameters, filename, NULL, 0);
}

const char *user_id()
{
    IniStringList *sl;

    sl = IniSection_getkey(&parameters, NULL, "id", "", 0);

    return IniString_c_str(&sl->list[0]);
}

const char *logname()
{
    IniStringList *sl;

    sl = IniSection_getkey(&parameters, NULL, "logname", "none", 0);

    return IniString_c_str(&sl->list[0]);
}

bool hide()
{
    IniStringList *sl;

    sl = IniSection_getkey(&parameters, "guiriscos", "riscoshidden", "0", 1);

    return atoi(IniString_c_str(&sl->list[0])) ? TRUE : FALSE;
}

int playsound()
{
    IniStringList *sl;

    sl = IniSection_getkey(&parameters, "guiriscos", "playsound", "0", 1);

    return atoi(IniString_c_str(&sl->list[0]));
}

#define INIGETKEY(a, d) ( \
                        sl = IniSection_getkey(&parameters, "parameters", a, d, 1), \
                        IniString_c_str(&sl->list[0]) )

#define INIDEFAULTKEY(a, d) ( IniSection_getkey(&parameters, "parameters", a, d, 1) )

#define GUIGETKEY(a, d) ( \
                        sl = IniSection_getkey(&parameters, "guiriscos", a, d, 1), \
                        IniString_c_str(&sl->list[0]) )

static void fade_gadget(toolbox_o o, toolbox_c c, bool fade)
{
    gadget_flags f = gadget_get_flags(0, o, c);

    if ((fade & !(f & gadget_FADED)) || (!fade && (f & gadget_FADED)))
        gadget_set_flags(0, o, c, fade ? (f | gadget_FADED) : (f &~ gadget_FADED));
}

static void fade_network()
{
    toolbox_o o = choices_pane[1];
    int encoding, port, manual, manualport;

    port = numberrange_get_value(0, o, cmp_KSPort);

    encoding = stringsetgetselected_index(0, o, cmp_Encoding);

    manual = optionbutton_get_state(0, o, cmp_NoAutoKeyserver);

    manualport = optionbutton_get_state(0, o, cmp_NoAutoKSPort);

    fade_gadget(o, cmp_Keyserver, !manual);
    fade_gadget(o, cmp_KSPort, !manualport);
    fade_gadget(o, cmp_Proxy, encoding < 2);
    fade_gadget(o, cmp_PPort, encoding < 2);
    fade_gadget(o, cmp_PassButton, encoding < 2);
    button_set_value(0, o, cmp_ProxyLabel, encoding >= 4 ? "SOCKS proxy" : "HTTP proxy");

    if (CheckForcedKeyport(&port))
    {
        fade_gadget(o, cmp_KSPort, 1);
        numberrange_set_value(0, o, cmp_KSPort, port);
    }
}

static void fade_log()
{
    toolbox_o o = choices_pane[4];
    bool email = optionbutton_get_state(0, o, cmp_EmailEnable);
    bool moo = optionbutton_get_state(0, o, cmp_MooEnable);
    bool log = optionbutton_get_state(0, o, cmp_LogEnable);

    fade_gadget(o, cmp_EmailTarget, !email);
    fade_gadget(o, cmp_EmailSender, !email);
    fade_gadget(o, cmp_SMTPhost, !email);
    fade_gadget(o, cmp_SMTPport, !email);
    fade_gadget(o, cmp_EmailSize, !email);
    fade_gadget(o, cmp_MooType, !moo);
    fade_gadget(o, cmp_MooTest, !moo);
    fade_gadget(o, cmp_LogName, !log);
    fade_gadget(o, cmp_LogPopup, !log);
}

static void fade_buff()
{
    toolbox_o o = choices_pane[3];
    bool rc5ck = optionbutton_get_state(0, o, cmp_CkEnable);

    fade_gadget(o, cmp_CkName, !rc5ck);
    fade_gadget(o, cmp_CkPopup, !rc5ck);
}

int netset_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    if (id->this_cmp == cmp_Encoding)
    {
        int uuehttpmode = stringsetgetselected_index(0, id->this_obj, id->this_cmp);
        const char *keyproxy;

        switch (uuehttpmode)
        {
          default:
          case 0: /* normal */
          case 4: /* SOCKS4 */
          case 5: /* SOCKS5 */
            keyproxy = "us.v27.distributed.net";
            break;
          case 1: /* UUE */
            keyproxy = "us23.v27.distributed.net";
            break;
          case 2: /* HTTP */
          case 3: /* HTTP+UUE */
            keyproxy = "us80.v27.distributed.net";
            break;
        }

        stringsetsetselected_string(0, id->this_obj, cmp_Keyserver, keyproxy);

        fade_network();

        return 1;
    }

    return 0;
}

int netopt_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    fade_network();

    return 1;
}

int logset_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    fade_log();

    return 1;
}

int ckset_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    fade_buff();

    return 1;
}

static bool password_changed;
toolbox_o proxypasswordhandle;
static char userid[64], password[64];

int proxypass_show_handler(bits event_code, toolbox_action *event,
                         toolbox_block *id, void *handle)
{
    int uuehttpmode = stringsetgetselected_index(0, id->parent_obj, cmp_Encoding);

    writablefield_set_value(0, id->this_obj, cmp_UserID, "");
    writablefield_set_value(0, id->this_obj, cmp_Password, "");

    fade_gadget(id->this_obj, cmp_Password, uuehttpmode == 4);

    return 1;
}

int set_password_handler(bits event_code, toolbox_action *event,
                         toolbox_block *id, void *handle)
{
    password_changed = TRUE;

    writablefield_get_value(0, id->this_obj, cmp_UserID, userid, sizeof userid);
    writablefield_get_value(0, id->this_obj, cmp_Password, password, sizeof password);

    return 1;
}

int moo_test(bits event_code, toolbox_action *event,
             toolbox_block *id, void *handle)
{
    int type = stringsetgetselected_index(0, id->this_obj, cmp_MooType);
    if (type == 0) type = -1;

    report_error(moo(type));

    return 1;
}

int netkey_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    toolbox_o o = id->this_obj;
    int port, oldport;
    bool forced, oldforced;

    if (id->this_cmp != cmp_Keyserver)
    	return 0;

    oldport = numberrange_get_value(0, o, cmp_KSPort);
    oldforced = (gadget_get_flags(0, o, cmp_KSPort) & gadget_FADED) ? true : false;

    port = oldport;
    forced = CheckForcedKeyport(&port);

    if (forced != oldforced)
    	fade_gadget(o, cmp_KSPort, forced);

    if (forced && port != oldport)
    	numberrange_set_value(0, o, cmp_KSPort, port);

    return 1;
}

static void help_connection()
{
    bool online = radiobutton_get_state(0, choices_pane[2], cmp_ConnOnline);
    //bool online = radiobutton_get_state(0, choices_pane[2], cmp_ConnOnline, NULL);

    button_set_value(0, choices_pane[2], cmp_ConnHelp,
                     msgs_lookup(online ? "ConHelp1" : "ConHelp2"));
}

int connset_handler(bits event_code, toolbox_action *event,
                    toolbox_block *id, void *handle)
{
    help_connection();

    return 1;
}

static void fill_in_dbox()
{
    IniStringList *sl;
    int i;
    const char *s, *p;
    char buffer[1024];

    ReadConfig();

    password_changed = FALSE;

    writablefield_set_value(0, choices_pane[0], cmp_id,
                            INIGETKEY("id", "rc5@distributed.net"));

    s = INIGETKEY("threshold", "10:10");
    p = strchr(s, ':');
    numberrange_set_value(0, choices_pane[3], cmp_RC5in, atoi(s));
    numberrange_set_value(0, choices_pane[3], cmp_RC5out, p ? atoi(p+1) : atoi(s));

    p = INIGETKEY("threshold2", s);
    s = p;
    p = strchr(s, ':');
    numberrange_set_value(0, choices_pane[3], cmp_DESin, atoi(s));
    numberrange_set_value(0, choices_pane[3], cmp_DESout, p ? atoi(p+1) : atoi(s));

    INIDEFAULTKEY("count", "0");
    INIDEFAULTKEY("hours", "0.00");

/*
    numberrange_set_value(0, choices_pane[5], cmp_Timeslice,
                             atoi(INIGETKEY("timeslice", "2048")));
*/
    INIDEFAULTKEY("niceness", "0");

    s = INIGETKEY("logname", "none");
    if (s[0] && strcasecmp(s, "none") != 0)
    {
        canonicalise(s, buffer, sizeof buffer);
        optionbutton_set_state(0, choices_pane[4], cmp_LogEnable, TRUE);
    }
    else
    {
        canonicalise("rc5des/log", buffer, sizeof buffer);
        optionbutton_set_state(0, choices_pane[4], cmp_LogEnable, FALSE);
    }
    writablefield_set_value(0, choices_pane[4], cmp_LogName, buffer);

    s = INIGETKEY("keyproxy", "");
    stringsetsetselected_string(0, choices_pane[1], cmp_Keyserver, s);
    optionbutton_set_state(0, choices_pane[1], cmp_NoAutoKeyserver, s[0] != '\0');

    i = atoi(INIGETKEY("keyport", "0"));
    numberrange_set_value(0, choices_pane[1], cmp_KSPort, i);
    optionbutton_set_state(0, choices_pane[1], cmp_NoAutoKSPort, i != 0);

    i = atoi(INIGETKEY("uuehttpmode", "0"));
    stringsetsetselected_index(0, choices_pane[1], cmp_Encoding, i);

    writablefield_set_value(0, choices_pane[1], cmp_Proxy,
                             INIGETKEY("httpproxy", "wwwproxy.corporate.com"));

    numberrange_set_value(0, choices_pane[1], cmp_PPort,
                             atoi(INIGETKEY("httpport", "80")));

    fade_network();

    stringsetsetselected_index(0, choices_pane[5], cmp_CPU,
                             atoi(INIGETKEY("cputype", "-1"))+1);

    i = atoi(INIGETKEY("numcpu", "-1")) + 1;
    stringsetsetselected_index(0, choices_pane[5], cmp_NumCPU, i);

    /* Log stuff */
    i = atoi(INIGETKEY("messagelen", "0"));
    optionbutton_set_state(0, choices_pane[4], cmp_EmailEnable, i ? TRUE : FALSE);

    numberrange_set_value(0, choices_pane[4], cmp_EmailSize, i ? i : 10000);

    writablefield_set_value(0, choices_pane[4], cmp_SMTPhost,
                             INIGETKEY("smtpsrvr", "your.smtp.server"));

    numberrange_set_value(0, choices_pane[4], cmp_SMTPport,
                             atoi(INIGETKEY("smtpport", "25")));

    writablefield_set_value(0, choices_pane[4], cmp_EmailSender,
                             INIGETKEY("smtpfrom", "a.computer@your.site"));

    writablefield_set_value(0, choices_pane[4], cmp_EmailTarget,
                             INIGETKEY("smtpdest", "you@your.site"));

    help_connection();

    s = INIGETKEY("checkpointfile", "none");
    if (strcasecmp(s, "none") != 0)
    {
        canonicalise(s, buffer, sizeof buffer);
        optionbutton_set_state(0, choices_pane[3], cmp_CkEnable, TRUE);
    }
    else
    {
        canonicalise("ckpoint", buffer, sizeof buffer);
        optionbutton_set_state(0, choices_pane[3], cmp_CkEnable, FALSE);
    }
    writablefield_set_value(0, choices_pane[3], cmp_CkName, buffer);

    fade_buff();

    INIDEFAULTKEY("randomprefix", "100");

    numberrange_set_value(0, choices_pane[3], cmp_BlockSize,
                             atoi(INIGETKEY("preferredblocksize", "31")));
    optionbutton_set_state(0, choices_pane[3], cmp_DoDES,
                              atoi(INIGETKEY("processdes", "1")));

    INIDEFAULTKEY("quiet", "0");
    INIDEFAULTKEY("noexitfilecheck", "0");
    INIDEFAULTKEY("percentoff", "0");
    INIDEFAULTKEY("frequent", "0");
    INIDEFAULTKEY("nodisk", "0");

    i = atoi(INIGETKEY("nofallback", "0"));
    optionbutton_set_state(0, choices_pane[1], cmp_NoFallback, i ? TRUE : FALSE);

    INIDEFAULTKEY("cktime", "5");

    numberrange_set_value(0, choices_pane[1], cmp_NetTimeout,
                             atoi(INIGETKEY("nettimeout", "60")));

    INIDEFAULTKEY("exitfilechecktime", "30");
    INIDEFAULTKEY("in", "buff-in/rc5");
    INIDEFAULTKEY("out", "buff-out/rc5");
    INIDEFAULTKEY("in2", "buff-in/des");
    INIDEFAULTKEY("out2", "buff-out/des");
    INIDEFAULTKEY("pausefile", "none");

    s = INIGETKEY("runoffline", "0");
    if (s[0]=='0')
        radiobutton_set_state(0, choices_pane[2], cmp_ConnOnline, 1);
    else
        radiobutton_set_state(0, choices_pane[2], cmp_ConnOffline, 1);

    help_connection();

    INIDEFAULTKEY("contestdone", "0");
    INIDEFAULTKEY("contestdone2", "0");

    {
        fileswitch_object_type t = fileswitch_NOT_FOUND;
        xosfile_read_no_path("<Boot$ToBeTasks>.StartRC5", &t, NULL, NULL, NULL, NULL);
        optionbutton_set_state(0, choices_pane[6], cmp_Autostart, t & fileswitch_IS_FILE ? 1 : 0);
    }

    optionbutton_set_state(0, choices_pane[6], cmp_Hide, hide());

    i = playsound();
    optionbutton_set_state(0, choices_pane[4], cmp_MooEnable, i ? TRUE : FALSE);

    switch (i)
    {
      case -1: i = 0; break;
      case -2: i = 6; break;
      default: break;
    }

    stringsetsetselected_index(0, choices_pane[4], cmp_MooType, i);

    fade_log();
}

int saveas_show_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    if (id->parent_obj == choices_pane[4])
        draggable_set_sprite(0, id->this_obj, cmp_SaveAsDrag, "file_fff");
    else
        draggable_set_sprite(0, id->this_obj, cmp_SaveAsDrag, "file_ffd");

    switch (id->parent_cmp)
    {
      case cmp_LogPopup:
        writablefield_set_value(0, id->this_obj, cmp_SaveAsName, "rc5des/log");
        break;
      case cmp_CkPopup:
        writablefield_set_value(0, id->this_obj, cmp_SaveAsName, "ckpoint/rc5");
        break;
    }

    return 1;
}

static int saveas_myref;
static toolbox_o saveas_o;
static toolbox_c saveas_c;

int saveas_drag_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    draggable_action_drag_ended *drag = (draggable_action_drag_ended *) &event->data;
    wimp_message m;
    char buffer[1024];
    char *filename;

    writablefield_get_value(0, id->this_obj, cmp_SaveAsName, buffer, sizeof buffer);

    filename = strrchr(buffer, '.');
    if (!filename) filename = strrchr(buffer, ':');
    if (filename)
    	filename++;
    else
    	filename=buffer;

    m.size = (44 + strlen(filename) + 1 + 3) &~ 3;
    m.your_ref = 0;
    m.action = message_DATA_SAVE;
    m.data.data_xfer.w = drag->ids.wimp.w;
    m.data.data_xfer.i = drag->ids.wimp.i;
    m.data.data_xfer.pos = drag->pos;
    m.data.data_xfer.est_size = 0;
    m.data.data_xfer.file_type = osfile_TYPE_TEXT;
    strcpy(m.data.data_xfer.file_name, filename);

    wimp_send_message_to_window(wimp_USER_MESSAGE, &m,
                                m.data.data_xfer.w,
                                m.data.data_xfer.i);

    saveas_myref = m.my_ref;
    saveas_o = id->parent_obj;
    saveas_c = id->parent_cmp;

    return 1;
}

int saveas_ack_handler(wimp_message *message, void *handle)
{
    if (message->your_ref == saveas_myref)
    {
        if (message->data.data_xfer.est_size != -1 &&
            strcasecmp(message->data.data_xfer.file_name, "<Wimp$Scrap>") != 0)
        {
            writablefield_set_value(0, saveas_o, cmp_LogName, message->data.data_xfer.file_name);
            wimp_create_menu(wimp_CLOSE_MENU, 0, 0);
        }

        return 1;
    }

    return 0;
}

int saveas_save_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    char buffer[1024];
    char buffer2[1024];

    writablefield_get_value(0, id->this_obj, cmp_SaveAsName, buffer, sizeof buffer);

    canonicalise(buffer, buffer2, sizeof buffer2);

    writablefield_set_value(0, id->parent_obj, cmp_LogName, buffer2);

    return 1;
}

int choices_tab_handler(bits event_code, toolbox_action *event,
                            toolbox_block *id, void *handle)
{
    radiobutton_action_state_changed *e =
       (radiobutton_action_state_changed *) &event->data;

    if (!e->on)
        return 0;

    window_set_tool_bars(window_TOOL_BAR_ITL, choices_handle,
                         toolbox_NULL_OBJECT,
                         choices_pane[id->this_cmp - cmp_Tab0],
                         toolbox_NULL_OBJECT,
                         toolbox_NULL_OBJECT);

    return 1;
}

void configure()
{
    fill_in_dbox();

    window_set_tool_bars(window_TOOL_BAR_ITL, choices_handle,
                        toolbox_NULL_OBJECT, choices_pane[0],
                        toolbox_NULL_OBJECT, toolbox_NULL_OBJECT);


    radiobutton_set_state(0, choices_handle, cmp_Tab0, TRUE);

    toolbox_show_object(0, choices_handle, toolbox_POSITION_DEFAULT,
                        NULL, toolbox_NULL_OBJECT, toolbox_NULL_COMPONENT);
}

#define INISETKEY(s, k, v) IniSection_setrecord(&parameters, s, k, v)
#define INIFIND(k) IniSection_findfirst(&parameters, "parameters", k)

static void set_file_option(toolbox_o o, toolbox_c c, char *buffer, int bufsize, const char *opt, const char *none)
{
    const char *p;
    int a;

    a = optionbutton_get_state(0, o, c + 0x200);
    if (a)
    {
        char temp;
        int l = strlen(our_dir);
        writablefield_get_value(0, o, c, buffer, bufsize);
        p = buffer;
        temp = buffer[l];
        if (temp == '.')
        {
            buffer[l] = '\0';
            if (strcasecmp(buffer, our_dir) == 0)
            {
                p = buffer+l+1;
            }
            else
            {
                buffer[l] = '.';
            }
        }
    }
    else
        p=none;
    INISETKEY("parameters", opt, p);
}

int choices_button_handler(bits event_code, toolbox_action *event,
                        toolbox_block *id, void *handle)
{
    if ((event->flags & (actionbutton_SELECTED_CANCEL | actionbutton_SELECTED_ADJUST))
          == (actionbutton_SELECTED_CANCEL | actionbutton_SELECTED_ADJUST))
    {
        fill_in_dbox();
        return 1;
    }
    return 0;
}

static void killwhitespace(char *string)
// Removes all spaces from a string
{
  char *whitespaceptr;

  while ((whitespaceptr = strchr(string, ' ')) != NULL)
  {
    strcpy(whitespaceptr, whitespaceptr+1);
  }
}


int choices_set_handler(bits event_code, toolbox_action *event,
                        toolbox_block *id, void *handle)
{
    char buffer[1024];
    int uuehttpmode, a, b;
    IniRecord *ptr = NULL;

    writablefield_get_value(0, choices_pane[0], cmp_id, buffer, sizeof buffer);
    killwhitespace(buffer);
    INISETKEY("parameters", "id", buffer);

    uuehttpmode = stringsetgetselected_index(0, choices_pane[1], cmp_Encoding);
    sprintf(buffer, "%d", uuehttpmode);
    INISETKEY("parameters", "uuehttpmode", buffer);

    a = optionbutton_get_state(0, choices_pane[1], cmp_NoAutoKeyserver);
    stringsetgetselected_string(0, choices_pane[1], cmp_Keyserver, buffer, sizeof buffer);
    killwhitespace(buffer);
    INISETKEY("parameters", "keyproxy", a ? buffer : "");

    b = optionbutton_get_state(0, choices_pane[1], cmp_NoAutoKSPort);
    a = b ? numberrange_get_value(0, choices_pane[1], cmp_KSPort) : 0;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "keyport", buffer);

    writablefield_get_value(0, choices_pane[1], cmp_Proxy, buffer, sizeof buffer);
    killwhitespace(buffer);
    INISETKEY("parameters", "httpproxy", buffer);

    a = numberrange_get_value(0, choices_pane[1], cmp_PPort);
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "httpport", buffer);

    a = optionbutton_get_state(0, choices_pane[1], cmp_NoFallback);
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "nofallback", buffer);

    a = numberrange_get_value(0, choices_pane[1], cmp_NetTimeout);
    if (a < 30) a = 30; else if (a > 300) a = 300;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "nettimeout", buffer);

    if (password_changed && uuehttpmode >= 3)
    {
        writablefield_get_value(0, proxypasswordhandle, cmp_UserID, buffer+512, 128);
        writablefield_get_value(0, proxypasswordhandle, cmp_Password, buffer+768, 128);
        switch (uuehttpmode)
        {
          case 2:
          case 3: /* HTTP */
            base64_encode(buffer, buffer+512, buffer+768);
            INISETKEY("parameters", "httpid", buffer);
            break;

          case 4: /* SOCKS4 */
            INISETKEY("parameters", "httpid", buffer+512);
            break;

          case 5: /* SOCKS5 */
            sprintf(buffer, "%s:%s", buffer+512, buffer+768);
            INISETKEY("parameters", "httpid", buffer);
            break;
        }
    }

    if (uuehttpmode <= 1)
    {
        ptr = INIFIND("httpproxy");
        if (ptr) IniStringList_Erase(&ptr->values);
        ptr = INIFIND("httpport");
        if (ptr) IniStringList_Erase(&ptr->values);
        ptr = INIFIND("httpid");
        if (ptr) IniStringList_Erase(&ptr->values);
    }

    //a = radiobutton_get_state(0, choices_pane[2], cmp_ConnOffline, NULL);
    a = radiobutton_get_state(0, choices_pane[2], cmp_ConnOffline);
    INISETKEY("parameters", "runoffline", a ? "1" : "0");

    a = numberrange_get_value(0, choices_pane[3], cmp_RC5in);
    b = numberrange_get_value(0, choices_pane[3], cmp_RC5out);
    if (a<1) a=1; if (a>1000) a=1000;
    if (b<1) b=1; if (b>1000) b=1000;
    if (b>a) b=a;
    sprintf(buffer, "%d:%d", a, b);
    INISETKEY("parameters", "threshold", buffer);

    a = numberrange_get_value(0, choices_pane[3], cmp_DESin);
    b = numberrange_get_value(0, choices_pane[3], cmp_DESout);
    if (a<1) a=1; if (a>1000) a=1000;
    if (b<1) b=1; if (b>1000) b=1000;
    if (b>a) b=a;
    sprintf(buffer, "%d:%d", a, b);
    INISETKEY("parameters", "threshold2", buffer);

    a = optionbutton_get_state(0, choices_pane[3], cmp_DoDES);
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "processdes", buffer);

    a = numberrange_get_value(0, choices_pane[3], cmp_BlockSize);
    if (a<28) a=28; if (a>31) a=31;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "preferredblocksize", buffer);

    set_file_option(choices_pane[3], cmp_CkName, buffer, sizeof buffer, "checkpointfile", "none");

    a = optionbutton_get_state(0, choices_pane[4], cmp_EmailEnable);
    a = a ? numberrange_get_value(0, choices_pane[4], cmp_EmailSize) : 0;
    if (a <0) a=0; if (a>125000) a=125000;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "messagelen", buffer);

    writablefield_get_value(0, choices_pane[4], cmp_EmailTarget, buffer, sizeof buffer);
    killwhitespace(buffer);
    INISETKEY("parameters", "smtpdest", buffer);

    writablefield_get_value(0, choices_pane[4], cmp_EmailSender, buffer, sizeof buffer);
    INISETKEY("parameters", "smtpfrom", buffer);

    writablefield_get_value(0, choices_pane[4], cmp_SMTPhost, buffer, sizeof buffer);
    killwhitespace(buffer);
    INISETKEY("parameters", "smtpsrvr", buffer);

    a = numberrange_get_value(0, choices_pane[4], cmp_SMTPport);
    if (a < 0) a = 0;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "smtpport", buffer);

    set_file_option(choices_pane[4], cmp_LogName, buffer, sizeof buffer, "logname", "none");
/*
    a = numberrange_get_value(0, choices_pane[5], cmp_Timeslice);
    if (a < 1) a = 0x10000;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "timeslice", buffer);
*/
    a = stringsetgetselected_index(0, choices_pane[5], cmp_CPU) - 1;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "cputype", buffer);

    a = stringsetgetselected_index(0, choices_pane[5], cmp_NumCPU) - 1;
    sprintf(buffer, "%d", a);
    INISETKEY("parameters", "numcpu", buffer);

    a = optionbutton_get_state(0, choices_pane[6], cmp_Autostart);
    if (a)
    {
        os_error *e;

        sprintf(buffer,
                "|\n"
                "| Launch distributed.net client\n"
                "|\n"
                "/%s -run\n", our_dir);

        e = xosfile_save_stamped("<Boot$ToBeTasks>.StartRC5", osfile_TYPE_OBEY,
                                 (byte *)buffer, (byte *)buffer+strlen(buffer));
        if (e)
            report_error(e);
    }
    else
    	remove("<Boot$ToBeTasks>.StartRC5");

    a = optionbutton_get_state(0, choices_pane[6], cmp_Hide);
    sprintf(buffer, "%d", a);
    INISETKEY("guiriscos", "riscoshidden", buffer);

    a = optionbutton_get_state(0, choices_pane[4], cmp_MooEnable);
    if (a)
    {
        a = stringsetgetselected_index(0, choices_pane[4], cmp_MooType);
        if (a == 0) a = -1;
        if (a == 6) a = -2;
    }
    sprintf(buffer, "%d", a);
    INISETKEY("guiriscos", "playsound", buffer);

    sprintf(buffer, "%s.rc5des/ini", our_dir);
    IniSection_WriteIniFile(&parameters, buffer);

    fill_in_dbox();

    if (client_running())
    {
        stopping_for = Run;
        client_break(FALSE);
    }

    return 1;
}
