// // ui-dumb.c // // // //-UserX 2002/03/19 #include #include #include #include #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; }