//
// ui-dumb.c
//
//
//
//-UserX 2002/03/19
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "ui/ui-dumb.h"
#include "base/mem.h"
#include "base/str.h"
#include "base/strarray.h"
#include "base/strio.h"
#include "base/logger.h"
#include "base/getch.h"
#include "base/time.h"
#include "crypt/random.h"
#include "base/dblock.h"
#include "file/file.h"
/*
Provides a UI for dumb terminals.
@author userx
@name ui-dumb
*/
//#define BLANKUIDUMBWINDOW {NULL, NULL,
UIDumbWindow blankuidumbwindow = {
{
NULL,
NULL,
(UIFuncUIWindowInit)uidwInit,
(UIFuncUIWindowFree)uidwFree,
(UIFuncUIWindowRun)uidwRun,
(UIFuncUIControlSetState)uidcSetState,
(UIFuncUIControlSetValue)uidcSetValue,
(UIFuncUIEntryAdd)uidwAddControl
},
'a',
0
};
UIWindow *uidumbMake(void) {
UIDumbWindow *uidw;
uidw = memCopy(&blankuidumbwindow, sizeof(UIDumbWindow), "UIDumbWindow", NULL);
return (UIWindow *)uidw;
}
void uidwInit(UIDumbWindow *uidw) {
//nothing to do
}
void uidwFree(UIDumbWindow *uidw) {
//nothing to do
}
void uidwRun(UIDumbWindow *uidw) {
UIDumbControl *uidc;
int i;
if(uidw == NULL) {
return;
}
if(uidw->uiw.uica->size <= 0) {
return;
}
for(i = 0; i < uidw->uiw.uica->size; i++) {
uidc = (UIDumbControl *)(uidw->uiw.uica->data[i]);
if(uidc->uic.entry.notifyfunc != NULL) {
uidc->uic.entry.notifyfunc(uidw, uidc, UINOTIFY_INIT);
}
}
while(1) {
uidwDraw(uidw);
if(uidwDoInput(uidw) == 0) {
break;
}
}
}
void uidwAddControl(UIDumbWindow *uidw, UIEntry *uie) {
UIDumbControl *uidc;
uidc = memAlloc(sizeof(UIDumbControl), "UIDumbControl", NULL);
uieCopyAt(&uidc->uic.entry, uie);
switch(uie->type) {
case UITYPE_BUTTON:
case UITYPE_BUTTONOK:
case UITYPE_BUTTONCANCEL:
case UITYPE_EDIT:
case UITYPE_EDIT_LONG:
case UITYPE_CHECK:
case UITYPE_RADIO:
if(uidw->lastletter == 0) {
uidw->lastletter = uidw->firstletter;
} else {
uidw->lastletter++;
}
uidc->menuletter = uidw->lastletter;
break;
case UITYPE_COLUMN_START_2:
case UITYPE_COLUMN_STOP:
case UITYPE_RADIOSTART:
case UITYPE_RADIOSTOP:
case UITYPE_TEXT:
case UITYPE_BOXSTART:
case UITYPE_BOXSTOP:
case UITYPE_NONE:
uidc->menuletter = 0;
break;
default:
LOGERROR(stringJoinMany("uidwAddControl unhandle control type:", intToString(uidc->uic.entry.type), NULL));
}
uicaAdd(uidw->uiw.uica, (UIControl *) uidc);
}
void uidcSetState(UIDumbWindow *uidw, int index, int state) {
uidw->uiw.uica->data[index]->state = state;
}
void uidcSetValue(UIDumbWindow *uidw, int index) {
//nothing to do
}
void uidwDraw(UIDumbWindow *uidw) {
int i;
char *s1;
char *s2;
UIDumbControl *uidc;
for(i = 0; i < uidw->uiw.uica->size; i++) {
uidc = (UIDumbControl *) uidw->uiw.uica->data[i];
s1 = stringMake(3);
if((uidc->uic.state & UISTATE_DISABLED) == 0) {
//enabled
s1[0] = '<';
s1[1] = toupper(uidc->menuletter);
s1[2] = '>';
} else {
//disabled
s1[0] = ' ';
s1[1] = tolower(uidc->menuletter);
s1[2] = ' ';
}
s1[3] = 0;
switch(uidc->uic.entry.type) {
case UITYPE_BUTTON:
case UITYPE_BUTTONOK:
case UITYPE_BUTTONCANCEL:
s2 = stringAppend("...", uidc->uic.entry.caption);
break;
case UITYPE_EDIT:
case UITYPE_EDIT_LONG:
s2 = stringCopyMany(
"===",
uidc->uic.entry.caption,
":",
uidc->uic.stringvalue,
NULL);
break;
case UITYPE_CHECK:
s2 = stringAppend("[ ]", uidc->uic.entry.caption);
if(uidc->uic.value != 0) {
s2[1] = 'X';
}
break;
case UITYPE_RADIO:
s2 = stringAppend("( )", uidc->uic.entry.caption);
if(uidc->uic.value != 0) {
s2[1] = '*';
}
break;
case UITYPE_COLUMN_START_2:
case UITYPE_COLUMN_STOP:
case UITYPE_RADIOSTART:
case UITYPE_RADIOSTOP:
stringFree(s1);
continue;
case UITYPE_TEXT:
case UITYPE_BOXSTART:
stringFree(s1);
s1 = "--";
s2 = stringCopy(uidc->uic.entry.caption);
break;
case UITYPE_BOXSTOP:
stringFree(s1);
s1 = "--";
s2 = "----------------------------------------";
break;
//continue;
default:
LOGERROR(stringJoinMany("uidwDraw unhandle control type:", intToString(uidc->uic.entry.type), NULL));
stringFree(s1);
continue;
}
printf("%s%s\n", s1, s2);
stringFree(s1);
stringFree(s2);
}
}
int uidwDoInput(UIDumbWindow *uidw) {
UIDumbControl *uidc;
char c;
char *s;
int i;
int j;
printf("choose:>");
while(1) {
//c = tolower(getchar());
//c = scanf("%c\n", &c);
//c = tolower(c);
s = stringReadLine(fhstdin);
c = tolower(s[0]);
stringFree(s);
if(c < uidw->firstletter || c > uidw->lastletter) {
//continue;
return 1;
}
//printf("%c\n", c);
printf("\n");
for(i = 0; i < uidw->uiw.uica->size; i++) {
uidc = (UIDumbControl*)(uidw->uiw.uica->data[i]);
if(uidc->menuletter == c && (uidc->uic.state & UISTATE_DISABLED) == 0) {
switch(uidc->uic.entry.type) {
case UITYPE_BUTTON:
case UITYPE_BUTTONOK:
case UITYPE_BUTTONCANCEL:
if(uidc->uic.entry.notifyfunc != NULL) {
if(uidc->uic.entry.notifyfunc(uidw, uidc, UINOTIFY_ACTIVATED) == UINOTIFYRETURN_EXIT) {
return 0;
}
}
break;
case UITYPE_EDIT:
case UITYPE_EDIT_LONG:
printf("%s:", uidc->uic.entry.caption);
uidc->uic.oldstringvalue = uidc->uic.stringvalue;
s = stringMake(2048);
//j = scanf("%s", s); //todo: replace this with somthing that can't be overflowed.
s = stringReadLineOrEOF(fhstdin);
//if(j == 1) {
uidc->uic.stringvalue = stringTrim(s, "\r\n");
if(uidc->uic.entry.notifyfunc != NULL) {
if(uidc->uic.entry.notifyfunc(uidw, uidc, UINOTIFY_CHANGE) == UINOTIFYRETURN_OK) {
stringFree(uidc->uic.oldstringvalue);
} else {
stringFree(uidc->uic.stringvalue);
uidc->uic.stringvalue = uidc->uic.oldstringvalue;
}
}
//}
uidc->uic.oldstringvalue = NULL;
break;
case UITYPE_CHECK:
uidc->uic.oldvalue = uidc->uic.value;
uidc->uic.value = (uidc->uic.value != 0) ? 0 : 1;
if(uidc->uic.entry.notifyfunc != NULL) {
if(uidc->uic.entry.notifyfunc(uidw, uidc, UINOTIFY_CHANGE) == UINOTIFYRETURN_OK) {
//do nothing
} else {
uidc->uic.value = uidc->uic.oldvalue;
}
}
break;
case UITYPE_RADIO:
j = uicaClearRadioGroup(uidw->uiw.uica, i);
uidc->uic.value = 1;
if(uidc->uic.entry.notifyfunc != NULL) {
if(uidc->uic.entry.notifyfunc(uidw, uidc, UINOTIFY_CHANGE) == UINOTIFYRETURN_OK) {
//do nothing
} else {
uicaClearRadioGroup(uidw->uiw.uica, j);
uidw->uiw.uica->data[j]->value = 1;
uidc->uic.value = 0;
}
}
break;
default:
LOGERROR(stringJoinMany("uidwDoInput unhandle control type:", intToString(uidc->uic.entry.type), NULL));
}
return 1;
}
}
//continue;
return 1;
}
return 1;
}
int uidDialog(char *title, char *text, int type, int defaultchoice) {
StringArrayHandle *sa;
char *s;
int i;
//char c;
if(type && UIDIALOG_ALLTYPE == 0) {
return 0;
}
sa = saMake();
for(i = 1; i < UIDIALOG_ALLTYPE; i <<= 1) {
switch(i & type) {
case UIDIALOG_YES:
s = "Yes";
break;
case UIDIALOG_NO:
s = "No";
break;
case UIDIALOG_OK:
s = "Ok";
break;
case UIDIALOG_CANCEL:
s = "Cancel";
break;
default:
s = NULL;
}
if(s != NULL) {
if((i & type) == defaultchoice) {
s = stringToUpper(s);
}
saAppend(sa, s);
}
}
s = saImplode(sa, "/");
saFree(sa);
printf("%s (%s):", text, s);
stringFree(s);
while(1) {
//i = tolower(getchar());
//c = scanf("%c\n", &c);
//c = tolower(c);
s = stringReadLineOrEOF(fhstdin);
i = tolower(s[0]);
stringFree(s);
switch(i){
case 'y':
i = UIDIALOG_YES;
break;
case 'n':
i = UIDIALOG_NO;
break;
case 'o':
i = UIDIALOG_OK;
break;
case 'c':
i = UIDIALOG_CANCEL;
break;
case '\n':
case '\r':
case '\x1a':
i = defaultchoice;
break;
default:
i = 0;
}
i &= type;
if(i != 0) {
printf("\n");
return i;
}
}
}
int uidGetEntropy(char *title, char *text, int bits) {
#define MATCHLENGTH 8 /*probably excessive*/
DataBlock* db = dblockMake(MATCHLENGTH * 2, MATCHLENGTH * 2, "KeyEntropy buffer");
uint64 clocknow = 0, clockprev;
int discard;
int i;
int bitsgot = 0;
int escapecount = 0;
int c;
printf("\n%s\n", text);
printf(_("Press random keys...\n"));
while (bitsgot < bits) {
c = getch();
if(c == (EOF)) {
break;
}
discard = 0;
memmove(db->data, db->data + 1, db->size - 1);
db->data[db->size - 1] = c;
clockprev = clocknow;
clocknow = timeGetTicks();
if((clocknow - clockprev) <= 10000) {
/*probably part of a multi character key press*/
discard = 1;
}
for(i = 1; i <= MATCHLENGTH; i++) {
if(memcmp(db->data + db->size - i,
db->data + db->size - i - i, i) == 0) {
/*matched immediately preceding key sequences*/
discard = 1;
break;
}
}
printf("%c", discard ? '.' : '*');
randomAddEntropyClock(discard ? 0 : 1);
randomAddEntropy(c, discard ? 0 : 1);
if(!discard) bitsgot += 2;
}
printf("\a");
printf(_("\nEnough entropy gathered!\n"));
printf(_("Press enter twice to continue.\n"));
while(escapecount < 2) {
c = getch();
switch(c) {
case '\r':
case '\n':
escapecount++;
break;
case EOF:
return bitsgot;
break;
default:
escapecount = 0;
}
}
return bitsgot;
}
syntax highlighted by Code2HTML, v. 0.9.1