void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist) { if (_word_count != 12 && _word_count != 18 && _word_count != 24) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (has to be 12, 18 or 24 bits)"); go_home(); return; } word_count = _word_count; enforce_wordlist = _enforce_wordlist; if (pin_protection && !change_pin()) { go_home(); return; } storage_set_passphrase_protected(passphrase_protection); storage_set_language(language); storage_set_label(label); uint32_t i; for (i = 0; i < word_count; i++) { word_order[i] = i + 1; } for (i = word_count; i < 24; i++) { word_order[i] = 0; } random_permute(word_order, 24); awaiting_word = true; word_index = 0; next_word(); }
void fsm_msgLoadDevice(LoadDevice *msg) { if(storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); return; } if(!confirm_load_device(msg->has_node)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled"); go_home(); return; } if(msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) { if(!mnemonic_check(msg->mnemonic)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Mnemonic with wrong checksum provided"); go_home(); return; } } storage_load_device(msg); storage_commit(); fsm_sendSuccess("Device loaded"); go_home(); }
/* ** subtest_dadb(test_list, status, ch) ** ** (da) (db) data above, (db) data below */ static void subtest_dadb( struct test_list *t, int *state, int *ch) { if (can_clear_screen && scroll_reverse && scroll_forward) { put_clear(); if (scroll_reverse) ptext("(da) Data-above should be set\r"); home_down(); if (scroll_forward) ptext("(db) Data-below should be set\r"); tc_putp(scroll_forward); go_home(); tc_putp(scroll_reverse); tc_putp(scroll_reverse); home_down(); tc_putp(scroll_forward); go_home(); ptextln("\n\n\n\n\nIf the top line is blank then (da) should be false."); ptextln("If the bottom line is blank then (db) should be false."); sprintf(temp, "\n(da) Data-above is %s, and (db) Data-below is %s, in the data base.", memory_above ? "true" : "false", memory_below ? "true" : "false"); ptextln(temp); line_count = lines; } else { ptextln("(da) Data-above, (db) Data-below not tested, scrolls or (clear) is missing."); } generic_done_message(t, state, ch); }
const HDNode *fsm_getDerivedNode(uint32_t *address_n, size_t address_n_count) { static HDNode node; if(!storage_get_root_node(&node)) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); go_home(); return 0; } if(!address_n || address_n_count == 0) { return &node; } if(hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); go_home(); return 0; } return &node; }
void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); if (!storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); return; } if(!pin_protect_cached()) { go_home(); return; } const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if(!node) { return; } uint8_t public_key[33]; // copy public key to temporary buffer memcpy(public_key, node->public_key, sizeof(public_key)); if(msg->has_ecdsa_curve_name) { const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); if(curve) { // correct public key (since fsm_getDerivedNode uses secp256k1 curve) ecdsa_get_public_key33(curve, node->private_key, public_key); } } resp->node.depth = node->depth; resp->node.fingerprint = node->fingerprint; resp->node.child_num = node->child_num; resp->node.chain_code.size = 32; memcpy(resp->node.chain_code.bytes, node->chain_code, 32); resp->node.has_private_key = false; resp->node.has_public_key = true; resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, public_key, 33); resp->has_xpub = true; hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); if(msg->has_show_display && msg->show_display) { if(!confirm_xpub(resp->xpub)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show extended public key cancelled"); go_home(); return; } } msg_write(MessageType_MessageType_PublicKey, resp); go_home(); }
void fsm_msgChangePin(ChangePin *msg) { bool removal = msg->has_remove && msg->remove; bool confirmed = false; if(removal) { if(storage_has_pin()) { confirmed = confirm(ButtonRequestType_ButtonRequest_RemovePin, "Remove PIN", "Do you want to remove PIN protection?"); } else { fsm_sendSuccess("PIN removed"); return; } } else { if(storage_has_pin()) confirmed = confirm(ButtonRequestType_ButtonRequest_ChangePin, "Change PIN", "Do you want to change your PIN?"); else confirmed = confirm(ButtonRequestType_ButtonRequest_CreatePin, "Create PIN", "Do you want to add PIN protection?"); } if(!confirmed) { fsm_sendFailure(FailureType_Failure_ActionCancelled, removal ? "PIN removal cancelled" : "PIN change cancelled"); go_home(); return; } if(!pin_protect("Enter Current PIN")) { go_home(); return; } if(removal) { storage_set_pin(0); storage_commit(); fsm_sendSuccess("PIN removed"); } else { if(change_pin()) { storage_commit(); fsm_sendSuccess("PIN changed"); } } go_home(); }
void fsm_msgSignMessage(SignMessage *msg) { RESP_INIT(MessageSignature); if (!storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); return; } if(!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message", (char *)msg->message.bytes)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); go_home(); return; } if(!pin_protect_cached()) { go_home(); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if(!coin) { return; } const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if(!node) { return; } if(cryptoMessageSign(coin, msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { fsm_sendFailure(FailureType_Failure_Other, "Error signing message"); } go_home(); }
void signing_abort(void) { if (signing) { go_home(); signing = false; } }
/* ** crum_os(test_list, status, ch) ** ** (cup) test Cursor position on overstrike terminals */ static void crum_os( struct test_list *t, int *state, int *ch) { int i; if (cursor_address && over_strike) { put_clear(); for (i = 0; i < columns - 2; i++) { tc_putch('|'); } for (i = 1; i < lines - 2; i++) { put_crlf(); tc_putch('_'); } for (i = 0; i < columns - 2; i++) { tputs(TPARM_2(cursor_address, 0, i), lines, tc_putch); tc_putch('+'); } for (i = 0; i < lines - 2; i++) { tputs(TPARM_2(cursor_address, i, 0), lines, tc_putch); tc_putch(']'); tc_putch('_'); } go_home(); put_newlines(3); ptext(" All the characters should look the same. "); generic_done_message(t, state, ch); put_clear(); } }
void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label) { if(_strength != 128 && _strength != 192 && _strength != 256) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid strength (has to be 128, 192 or 256 bits)"); go_home(); return; } strength = _strength; random_buffer(int_entropy, 32); char ent_str[4][17]; data2hex(int_entropy , 8, ent_str[0]); data2hex(int_entropy + 8, 8, ent_str[1]); data2hex(int_entropy + 16, 8, ent_str[2]); data2hex(int_entropy + 24, 8, ent_str[3]); if(display_random) { if(!confirm(ButtonRequestType_ButtonRequest_ResetDevice, "Internal Entropy", "%s %s %s %s", ent_str[0], ent_str[1], ent_str[2], ent_str[3])) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled"); go_home(); return; } } if(pin_protection && !change_pin()) { go_home(); return; } storage_set_passphrase_protected(passphrase_protection); storage_set_language(language); storage_set_label(label); EntropyRequest resp; memset(&resp, 0, sizeof(EntropyRequest)); msg_write(MessageType_MessageType_EntropyRequest, &resp); awaiting_entropy = true; }
void customer(void *unusedpointer, unsigned long customernum) { struct paintcan can; int i,j; (void) unusedpointer; /* avoid compiler warning */ i = 0; /* count number of interations */ do { #ifdef PRINT_ON kprintf("C %ld is ordering\n", customernum); #endif /* erase ingredients list on can and select a colour in terms of tints */ for (j = 0; j < PAINT_COMPLEXITY; j++) { can.requested_colours[j] = 0; } can.requested_colours[0] = RED; /* order the paint, this blocks until the order is forfilled */ order_paint(&can); #ifdef PRINT_ON kprintf("C %ld painting with the following %d, %d, %d\n", customernum, can.contents[0], can.contents[1], can.contents[2]); #endif /* empty the paint can */ for (j = 0; j < PAINT_COMPLEXITY; j++) { can.contents[j] = 0; } /* I needed that break.... */ thread_yield(); i++; } while (i < 10); /* keep going until .... */ #ifdef PRINT_ON kprintf("C %ld going home\n", customernum); #else (void)customernum; #endif /* * Now we go home. */ go_home(); V(alldone); }
void fsm_msgSignTx(SignTx *msg) { if (!storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); return; } if(msg->inputs_count < 1) { fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); go_home(); return; } if(msg->outputs_count < 1) { fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); go_home(); return; } if(!pin_protect("Enter Current PIN")) { go_home(); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if(!coin) { return; } /* master node */ const HDNode *node = fsm_getDerivedNode(0, 0); if(!node) { return; } layout_simple_message("Preparing Transaction..."); signing_init(msg->inputs_count, msg->outputs_count, coin, node); }
/* ** page_loop() ** ** send CR/LF or go home and bump letter */ void page_loop(void) { if (line_count + 2 >= lines) { NEXT_LETTER; go_home(); } else { put_crlf(); } }
/* ** subtest_smam(test_list, status, ch) ** ** test enter automatic margins mode (smam) */ static void subtest_smam( struct test_list *t, int *state, int *ch) { int i, j; if (!enter_am_mode) { ptext("(smam) not present. "); } else if (!can_go_home) { ptext("(smam) not tested, no way to home cursor. "); } else if (over_strike) { put_clear(); go_home(); tc_putp(enter_am_mode); ptext("\n(smam) will "); i = char_count; ptext("not set (am)"); go_home(); for (j = -i; j < columns; j++) put_this(' '); put_str("@@@"); put_newlines(2); } else { put_clear(); go_home(); tc_putp(enter_am_mode); ptext("\n(smam) will not set (am)"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(smam) will set (am) "); go_home(); put_str(" "); put_newlines(2); } ptext("Enter-automatic-margins "); generic_done_message(t, state, ch); }
void fsm_msgWipeDevice(WipeDevice *msg) { (void)msg; if(!confirm(ButtonRequestType_ButtonRequest_WipeDevice, "Wipe Device", "Do you want to erase your private keys and settings?")) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); go_home(); return; } /* Wipe device */ storage_reset(); storage_reset_uuid(); storage_commit(); fsm_sendSuccess("Device wiped"); go_home(); }
void recovery_abort(bool send_failure) { if(awaiting_word || recovery_cipher_abort()) { awaiting_word = false; if(send_failure) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Recovery cancelled"); } go_home(); } }
void fsm_msgPing(Ping *msg) { RESP_INIT(Success); if(msg->has_button_protection && msg->button_protection) if(!confirm(ButtonRequestType_ButtonRequest_Ping, "Ping", msg->message)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); go_home(); return; } if(msg->has_pin_protection && msg->pin_protection) { if(!pin_protect_cached()) { go_home(); return; } } if(msg->has_passphrase_protection && msg->passphrase_protection) { if(!passphrase_protect()) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); go_home(); return; } } if(msg->has_message) { resp->has_message = true; memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); } msg_write(MessageType_MessageType_Success, resp); go_home(); }
const CoinType *fsm_getCoin(const char *name) { const CoinType *coin = coinByName(name); if(!coin) { fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); go_home(); return 0; } return coin; }
/* ** subtest_cbt(test_list, status, ch) ** ** (cbt) back tab */ static void subtest_cbt( struct test_list *t, int *state, int *ch) { int i; if (back_tab) { put_clear(); ptext("Back-tab (cbt)"); go_home(); put_crlf(); for (i = 1; i < columns; i++) { putchp(' '); } for (i = 0; i < columns; i += 8) { tc_putp(back_tab); putchp('T'); tc_putp(back_tab); } go_home(); put_newlines(2); for (i = 1; i < columns; i++) { if (i % 8 == 1) { putchp('T'); } else { putchp(' '); } } go_home(); put_newlines(3); ptextln("The preceding two lines should be the same."); } else { ptextln("(cbt) Back-tab not present"); } generic_done_message(t, state, ch); }
/* ** crum_home(test_list, status, ch) ** ** (home) test Home cursor */ static void crum_home( struct test_list *t, int *state, int *ch) { if (cursor_home) { put_clear(); put_newlines(lines / 2); go_home(); put_crlf(); ptext("The bottom line should have text."); go_home(); put_newlines(lines - 1); ptext("This line is on the bottom."); go_home(); ptextln("This line starts in the home position."); put_crlf(); } else { ptextln("(home) Home cursor is not defined. "); } generic_done_message(t, state, ch); }
/* ** display_it(selection, text) ** ** print the display using sel */ static void display_it( int sel, char *txt) { int i, done_line; put_clear(); go_home(); put_newlines(2); ptextln(" The top line should be alternating <'s and >'s"); ptextln(" The left side should be alternating A's and V's"); ptext(" Testing "); ptext(txt); put_cr(); /* horizontal */ move_to(done_line = line_count, 0, 0, 2, sel); for (i = 4; i < columns - 2; i += 2) { putchp('>'); move_to(0, i - 1, 0, i, sel); } putchp('>'); i -= 2; move_to(0, i + 1, 0, i - 1, sel); for (; i > 2; i -= 2) { putchp('<'); move_to(0, i, 0, i - 3, sel); } putchp('<'); /* vertical */ move_to(0, 2, 0, 0, sel); for (i = 2; i < lines - 1; i += 2) { putchp('V'); move_to(i - 2, 1, i, 0, sel); } putchp('V'); i -= 2; move_to(i, 1, i + 1, 0, sel); for (; i > 0; i -= 2) { putchp('A'); move_to(i + 1, 1, i - 1, 0, sel); } putchp('A'); move_to(i + 1, 1, 0, 0, sel); /* go home first */ move_to(0, 0, done_line + 1, 3, sel); put_str(txt); put_str(" Done. "); }
/* ** subtest_tbc(test_list, status, ch) ** ** test clear tabs (tbc) */ static void subtest_tbc( struct test_list *t, int *state, int *ch) { int tabat; /* the tab spacing we end up with */ int i; if (clear_all_tabs && !set_tab) { ptext("(tbc) Clear-all-tabs is defined but (hts) set-tab is not. "); ptext("Once the tabs are cleared there is no way to set them. "); } else if (clear_all_tabs) { tabat = set_tab ? 8 : init_tabs; tc_putp(clear_all_tabs); ptext("Clear tabs (tbc)"); go_home(); put_crlf(); putchp('\t'); putchp('T'); go_home(); put_newlines(2); for (i = 0; i < columns; i++) { if (i == tabat) { putchp('T'); } else { putchp('.'); } } go_home(); ptext("\n\n\nIf the above two lines have T's in the same column then (tbc) has failed. "); } else { ptext("(tbc) Clear-all-tabs is not defined. "); } generic_done_message(t, state, ch); }
void fsm_msgGetEntropy(GetEntropy *msg) { if(!confirm(ButtonRequestType_ButtonRequest_GetEntropy, "Generate Entropy", "Do you want to generate and return entropy using the hardware RNG?")) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled"); go_home(); return; } RESP_INIT(Entropy); uint32_t len = msg->size; if(len > ENTROPY_BUF) { len = ENTROPY_BUF; } resp->entropy.size = len; random_buffer(resp->entropy.bytes, len); msg_write(MessageType_MessageType_Entropy, resp); go_home(); }
/* ** sync_home(test_list, status, ch) ** ** Baudrate test */ void sync_home( struct test_list *t, int *state, int *ch) { int j, k; unsigned long rate; if (!cursor_home && !cursor_address && !row_address) { ptext("Terminal can not home cursor. "); generic_done_message(t, state, ch); return; } if (skip_pad_test(t, state, ch, "(home) Start baudrate search")) { return; } pad_test_startup(1); do { go_home(); for (j = 1; j < lines; j++) { for (k = 0; k < columns; k++) { if (k & 0xF) { put_this(letter); } else { put_this('.'); } } SLOW_TERMINAL_EXIT; } NEXT_LETTER; } while(still_testing()); pad_test_shutdown(t, auto_right_margin == 0); /* note: tty_frame_size is the real framesize times two. This takes care of half bits. */ rate = (tx_cps * tty_frame_size) >> 1; if (rate > tty_baud_rate) { tty_baud_rate = rate; } if (tx_cps > tty_cps) { tty_cps = tx_cps; } sprintf(temp, "%d characters per second. Baudrate %d ", tx_cps, j); ptext(temp); generic_done_message(t, state, ch); }
void fsm_msgInitialize(Initialize *msg) { (void)msg; /* If device is in manufacture mode, turn if off and lock it */ if(is_mfg_mode()) { set_mfg_mode_off(); go_home_forced(); } recovery_abort(false); signing_abort(); session_clear(false); // do not clear PIN go_home(); fsm_msgGetFeatures(0); }
void fsm_msgVerifyMessage(VerifyMessage *msg) { if(!msg->has_address) { fsm_sendFailure(FailureType_Failure_Other, "No address provided"); return; } if(!msg->has_message) { fsm_sendFailure(FailureType_Failure_Other, "No message provided"); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; layout_simple_message("Verifying Message..."); uint8_t addr_raw[21]; if(!ecdsa_address_decode(msg->address, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); } if(msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { if(review(ButtonRequestType_ButtonRequest_Other, "Message Verified", (char *)msg->message.bytes)) { fsm_sendSuccess("Message verified"); } } else { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature"); } go_home(); }
/* ** subtest_rmam(test_list, status, ch) ** ** test exit automatic margins mode (rmam) */ static void subtest_rmam( struct test_list *t, int *state, int *ch) { int j; if (!exit_am_mode) { ptext("(rmam) not present. "); } else if (!can_go_home) { ptext("(rmam) not tested, no way to home cursor. "); } else if (over_strike) { put_clear(); go_home(); tc_putp(exit_am_mode); ptext("\n(rmam) will reset (am)"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(rmam) will not reset (am)"); go_home(); put_newlines(2); } else { put_clear(); go_home(); tc_putp(exit_am_mode); ptext("\n(rmam) will reset (am)"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(rmam) will not reset (am) "); go_home(); put_str(" "); go_home(); put_newlines(2); } ptext("Exit-automatic-margins "); generic_done_message(t, state, ch); }
/* ** crum_ll(test_list, status, ch) ** ** (ll) test Last line */ static void crum_ll( struct test_list *t, int *state, int *ch) { /* (ll) may be simulated with (cup). Don't complain if (cup) is present. */ if (cursor_to_ll) { put_clear(); put_str("This line could be anywhere."); tc_putp(cursor_to_ll); ptext("This line should be on the bottom"); go_home(); put_crlf(); } else if (cursor_address) { return; } else { ptextln("(ll) Move to last line is not defined. "); } generic_done_message(t, state, ch); }
/* ** subtest_am(test_list, status, ch) ** ** test automatic margins (am) */ static void subtest_am( struct test_list *t, int *state, int *ch) { int i, j; if (!can_go_home) { ptextln("(am) not tested, no way to home cursor. "); } else if (over_strike) { put_clear(); go_home(); ptext("\n(am) should "); i = char_count; ptext("not be set"); go_home(); for (j = -i; j < columns; j++) put_this(' '); put_str("@@@"); go_home(); put_newlines(2); sprintf(temp, "(am) is %s in the data base", auto_right_margin ? "true" : "false"); ptextln(temp); } else { put_clear(); go_home(); ptext("\n(am) should not be set"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(am) should be set "); go_home(); put_str(" \n\n"); sprintf(temp, "(am) is %s in the data base", auto_right_margin ? "true" : "false"); ptextln(temp); } ptext("Automatic-right-margin "); generic_done_message(t, state, ch); }
/* ** subtest_xenl(test_list, status, ch) ** ** (xenl) eat newline glitch */ static void subtest_xenl( struct test_list *t, int *state, int *ch) { int i, j, k; if (over_strike) { /* test (xenl) on overstrike terminals */ if (!can_go_home || !can_clear_screen) { ptextln("(xenl) Newline-glitch not tested, can't home cursor and clear."); generic_done_message(t, state, ch); return; } put_clear(); /* this test must be done in raw mode. Otherwise UNIX will translate CR to CRLF. */ if (stty_query(TTY_OUT_TRANS)) tty_raw(1, char_mask); ptext("\nreset (xenl). Does "); i = char_count; put_str("not ignore CR, does "); k = char_count; put_str("not ignore LF"); go_home(); for (j = 0; j < columns; j++) put_this(' '); put_cr(); for (j = 0; j < i; j++) putchp(' '); put_str("@@@\n@@"); go_home(); for (j = 0; j < columns; j++) put_this(' '); put_lf(); for (j = 0; j < k; j++) putchp(' '); put_str("@@@\r@@"); tty_set(); go_home(); put_newlines(4); sprintf(temp, "(xenl) Newline-glitch is %s in the data base", eat_newline_glitch ? "true" : "false"); ptextln(temp); } else { /* test (xenl) when (os) is reset */ if (!can_go_home) { ptextln("(xenl) Newline-glitch not tested, can't home cursor"); generic_done_message(t, state, ch); return; } /* (xenl) test */ put_clear(); /* this test must be done in raw mode. Otherwise UNIX will translate CR to CRLF. */ if (stty_query(TTY_OUT_TRANS)) tty_raw(1, char_mask); for (j = 0; j < columns; j++) put_this(' '); put_cr(); ptext("(xenl) should be set. Does not ignore CR"); go_home(); put_crlf(); for (j = 0; j < columns; j++) put_this(' '); put_lf(); /* test (cud1) */ ptext("(xenl) should be set. Ignores (cud1)"); go_home(); put_newlines(3); if (scroll_forward && cursor_down && strcmp(scroll_forward, cursor_down)) { for (j = 0; j < columns; j++) put_this(' '); put_ind(); /* test (ind) */ ptext("(xenl) should be set. Ignores (ind)"); go_home(); put_newlines(5); } tty_set(); ptextln("If you don't see text above telling you to set it, (xenl) should be false"); sprintf(temp, "(xenl) Newline-glitch is %s in the data base", eat_newline_glitch ? "true" : "false"); ptextln(temp); } generic_done_message(t, state, ch); }