From e332a00cf9b6c2edbcd964cb0996f2db08a14c13 Mon Sep 17 00:00:00 2001 From: HAHALOSAH <67280050+HAHALOSAH@users.noreply.github.com> Date: Wed, 27 Mar 2024 22:50:45 -0700 Subject: [PATCH] merge tui! (#409) * Merge main into tui (#406) * plooshInit support * Add override libcheckra1nhelper option * update credits.c * Update build.yml --------- Co-authored-by: Nick Chan Co-authored-by: meow <69592455+kok3shidoll@users.noreply.github.com> * Add TUI * ISO C forbids an empty translation unit * Default to TUI * thanks iPadOS * I forgot * make random quotes more related (#408) Definitely a good concept of the TUI (and one that I am a fan of), but (as has been somewhat brought up by others) we should probably make them more related to checkm8, checkra1n, or palera1n (since those are the types of things that this tool is based off of) * "Connect your iPhone, iPad, iPod Touch, or Apple TV" * Add Linux TTY support * DIsable TUI for certain options * Fix boot-args overflow * auto reposition cursor * Moved droplet, no one could behave * Move the droplet back because it actually made it worse --------- Co-authored-by: Nick Chan Co-authored-by: meow <69592455+kok3shidoll@users.noreply.github.com> Co-authored-by: Michael <68412795+TheMasterOfMike@users.noreply.github.com> Co-authored-by: Samara <97859147+ssalggnikool@users.noreply.github.com> --- .github/workflows/build.yml | 4 +- include/paleinfo.h | 1 + include/palerain.h | 6 +- include/tui.h | 153 ++++++++++- src/credits.c | 6 +- src/exec_checkra1n.c | 17 +- src/lock_vars.c | 21 -- src/log.c | 19 +- src/main.c | 18 +- src/optparse.c | 42 ++- src/pongo_helper.c | 48 ++++ src/tui_devhelper.c | 220 ++++++++++++++++ src/tui_input.c | 166 ++++++++++++ src/tui_main.c | 235 ++++++++++++++--- src/tui_screen_enter_dfu.c | 454 +++++++++++++++++++++++++++++++- src/tui_screen_enter_recovery.c | 192 +++++++++++++- src/tui_screen_jailbreak.c | 156 ++++++++++- src/tui_screen_main.c | 379 +++++++++++++++++++++++--- src/tui_screen_options.c | 359 +++++++++++++++++++++---- 19 files changed, 2314 insertions(+), 182 deletions(-) create mode 100644 src/tui_devhelper.c create mode 100644 src/tui_input.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66ec646..714779f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -316,7 +316,7 @@ jobs: cp -a sysroot/${{ env.PREFIX }}/{include,lib} dep_root find dep_root -name '*.dylib' -delete find dep_root -name '*.la' -delete - gmake -j$(sysctl -n hw.ncpu) + gmake -j$(sysctl -n hw.ncpu) TUI=1 cp src/palera1n palera1n-${{ matrix.os }}-${{ matrix.arch }} dsymutil palera1n-${{ matrix.os }}-${{ matrix.arch }} strip palera1n-${{ matrix.os }}-${{ matrix.arch }} @@ -798,7 +798,7 @@ jobs: cp -a ${{ env.DESTDIR }}/${{ env.PREFIX }}/{include,lib} dep_root find dep_root -name '*.so' -delete find dep_root -name '*.la' -delete - CC="${{ matrix.triple }}-gcc" make -j$(nproc) + CC="${{ matrix.triple }}-gcc" make -j$(nproc) TUI=1 cp src/palera1n palera1n.release - name: Seperate debug symbols diff --git a/include/paleinfo.h b/include/paleinfo.h index d50a6ff..3a92124 100644 --- a/include/paleinfo.h +++ b/include/paleinfo.h @@ -46,6 +46,7 @@ typedef uint64_t palerain_option_t; // #define palerain_option_sf_launchdaemons (UINT64_C(1) << 28) /* safe mode with launchdaemons */ // #define palerain_option_emerg_mode (UINT64_C(1) << 29) /* emergency mode (early boot usb shell) */ #define palerain_option_jbinit_log_to_file (UINT64_C(1) << 30) /* deprecated (kept for compatibility) */ +#define palerain_option_cli (UINT64_C(1) << 31) /* CLI mode */ #define palerain_option_flower_chain (UINT64_C(1) << 61) /* Flower chain */ #define palerain_option_test1 (UINT64_C(1) << 62) /* Developer test option 1 */ diff --git a/include/palerain.h b/include/palerain.h index e64c613..085021a 100644 --- a/include/palerain.h +++ b/include/palerain.h @@ -25,6 +25,7 @@ #define palerain_option_case_version palerain_option_case(0) #define palerain_option_case_force_revert palerain_option_case(1) #define palerain_option_case_libcheckra1nhelper_path palerain_option_case(2) +#define palerain_option_case_cli palerain_option_case(3) #ifdef USE_LIBUSB @@ -226,9 +227,4 @@ void io_stop(stuff_t *stuff); void print_credits(void); -#ifdef TUI -#include -newtComponent get_tui_log(void); -newtComponent set_tui_log(newtComponent co); -#endif #endif diff --git a/include/tui.h b/include/tui.h index 9be0d36..98e6bf1 100644 --- a/include/tui.h +++ b/include/tui.h @@ -10,25 +10,69 @@ #include #include #include -#include #include +#include +#include #define WIDTH 76 #define HEIGHT 19 -#define PI_LOG_COLOR NEWT_COLORSET_CUSTOM(0) -#define PI_STEP_CURRENT NEWT_COLORSET_CUSTOM(1) -#define PI_STEP_OTHER NEWT_COLORSET_CUSTOM(2) - #define CHECKBOX_STATE(flags, opt) (flags & opt) != 0 ? '*' : ' ' +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +#define CLEAR_SCREEN printf("\033[2J") +#define RESETFONT printf("\x1b[0m") +#define PRINTAT(x, y, str) printf("\x1b[%d;%dH%s", y, x, str) +#define PRINTATT(x, y, str) PRINTAT(tui_x_offset + x, tui_y_offset + y, str) +#define PRINTATLEN(x, y, str, len) printf("\x1b[%d;%dH%." STR(len) "s", y, x, str) +#define PRINTATLENT(x, y, str, len) PRINTATLEN(tui_x_offset + x, tui_y_offset + y, str, len) +#define MOVETO(x, y) printf("\x1b[%d;%dH", y, x) +#define MOVETOT(x, y) MOVETO(tui_x_offset + x, tui_y_offset + y) +#define SETCOLOR(fg, bg) printf("\x1b[%d;%dm", fg, bg) +#define SETCOLORA(fg, bg, a) printf("\x1b[" STR(fg) ";" STR(bg) ";" STR(a) "m") +#define COLOR(fg, bg) "\x1b[" STR(fg) ";" STR(bg) "m" +#define FG_BLACK 30 +#define FG_YELLOW 33 +#define FG_BLUE 34 +#define FG_WHITE 37 +#define BG_BLACK 40 +#define BG_YELLOW 43 +#define BG_BLUE 44 +#define BG_WHITE 47 +#define NONE 0 +#define BOLD 1 +extern bool supports_bright_colors; +#define FG_BRIGHT_BLACK 90 +#define FG_BRIGHT_WHITE 97 +#define BG_BRIGHT_BLACK 100 +#define BG_BRIGHT_WHITE 107 +#define G1D4(set) printf("\x1b\x29%c", set) +#define DSGON putchar('\x0e'); G1D4('0') +#define DSGOFF putchar('\x0f'); G1D4('B') +#define MOUSEON printf("\x1b[?1003h") +#define MOUSEOFF printf("\x1b[?1003l") +#define CIVIS printf("\x1b[?25l") +#define CNORM printf("\x1b[?25h") +#define SMCUP printf("\x1b[?1049h") +#define RMCUP printf("\x1b[?1049l") +#define DRAWLINE(x, y, len) \ + MOVETO(x, y); \ + DSGON; \ + for (int i = 0; i < len; i++) { \ + putchar(0x71); \ + } \ + DSGOFF; +#define DRAWLINET(x, y, len) DRAWLINE(tui_x_offset + x, tui_y_offset + y, len) + typedef enum tui_screens { ERROR_SCREEN = -1, EXIT_SCREEN = 0, MAIN_SCREEN = 1, OPTIONS_SCREEN = 2, ENTER_DFU_SCREEN = 3, - JAILBREAKING_SCREEN = 4, + JAILBREAK_SCREEN = 4, ENTER_RECOVERY_SCREEN = 5 } tui_screen_t; @@ -38,12 +82,109 @@ typedef struct bitfield_checkbox_info { } tui_bit_info_t; tui_screen_t tui_screen_main(void); +void tui_screen_main_redraw(void); tui_screen_t tui_screen_options(void); +void tui_screen_options_redraw(void); tui_screen_t tui_screen_enter_recovery(void); +void tui_screen_enter_recovery_redraw(void); tui_screen_t tui_screen_enter_dfu(void); +void tui_screen_enter_dfu_redraw(void); tui_screen_t tui_screen_jailbreak(void); +void tui_screen_jailbreak_redraw(void); int redraw_screen(void); +void tui_draw_rectangle(int x1, int y1, int x2, int y2); + +#ifdef BUILD_TAG +#define TUI_VERSION BUILD_TAG +#else +#define TUI_VERSION "Unknown Version" +#endif + +extern int tui_state; +extern int tui_x_offset; +extern int tui_y_offset; + +extern bool tui_can_start; + +extern int tui_mouse_x; +extern int tui_mouse_y; + +enum { + TUI_INPUT_NONE, + TUI_INPUT_LEFT, + TUI_INPUT_RIGHT, + TUI_INPUT_UP, + TUI_INPUT_DOWN, + TUI_INPUT_MOUSE_MOVE, + TUI_INPUT_MOUSE_DOWN, + TUI_INPUT_MOUSE_UP, + TUI_INPUT_SELECT, + TUI_INPUT_TAB, + TUI_INPUT_TAB_BACK, + TUI_INPUT_BACKSPACE, + TUI_INPUT_ESCAPE, +}; + +enum { + TUI_EVENT_INPUT, + TUI_EVENT_CONNECTED_DEVICES_CHANGED, + TUI_EVENT_JAILBREAK_STATUS_CHANGED +}; + +int tui_get_input(void); +void *tui_input_thread(void *arg); +int tui_get_event(void); +int tui_try_get_event(void); + +extern int tui_last_event; +extern int tui_last_input; +extern sem_t *tui_event_semaphore; +extern char tui_last_key; + +void tui_devhelper(void); + +enum tui_device_mode { + TUI_DEVICE_MODE_NORMAL, + TUI_DEVICE_MODE_RECOVERY, + TUI_DEVICE_MODE_DFU +}; + +struct tui_connected_device { + uint64_t ecid; + char udid[44]; + char version[0x20]; + bool arm64; + enum tui_device_mode mode; + char product_type[0x20]; + char display_name[0x20]; + unsigned int cpid; + bool requires_passcode_disabled; + bool passcode_state; + struct tui_connected_device *next; +}; + +extern struct tui_connected_device *tui_connected_devices; + +int tui_compare_versions(const char *firstVersion, const char *secondVersion); + +void tui_jailbreak(void); +extern bool tui_is_jailbreaking; +extern int tui_jailbreak_stage; +extern char *tui_jailbreak_status; + +void tui_jailbreak_status_changed(void); + +extern bool tui_is_restarting; +void tui_terminate(int sig); + +extern bool tui_options_allow_untested; +extern bool tui_options_safe_mode; +extern bool tui_options_verbose_boot; +extern bool tui_options_force_revert; +extern bool tui_options_flower_chain; + +extern char tui_options_boot_args[0x1e0 + 1]; #endif diff --git a/src/credits.c b/src/credits.c index 0f5ad87..44f5904 100644 --- a/src/credits.c +++ b/src/credits.c @@ -5,15 +5,17 @@ #endif #define THE_PLUSH "Ploosh" +#define NEKO_DEVELOPE_R "HAHALOSAH" + #define T void #define R print_credits(void) { #define O fprintf( #define U stderr, #define B "#\n# palera1n: " BUILD_TAG " \n#\n" #define L "# ======== Made by =======\n" -#define E "# Made by: Nick Chan, " THE_PLUSH ", Samara, Mineek, staturnz, " BAKERAIN_DEVELOPE_R " \n" +#define E "# Made by: Nick Chan, " THE_PLUSH ", Samara, Mineek, staturnz, " BAKERAIN_DEVELOPE_R ", " NEKO_DEVELOPE_R " \n" #define M "# ======== Thanks to =======\n" -#define A "# Thanks to: pythonplayer123, llsc12, Nebula, tihmstar, nikias\n" +#define A "# Thanks to: llsc12, Nebula, tihmstar, nikias\n" #define K "# (libimobiledevice), checkra1n team (Siguza, axi0mx, littlelailo\n" #define I "# et al.), Procursus Team (Hayden Seay, Cameron Katri, Keto et.al)\n" #define N "# ==========================\n\n" diff --git a/src/exec_checkra1n.c b/src/exec_checkra1n.c index 7e51b3e..3f9362a 100644 --- a/src/exec_checkra1n.c +++ b/src/exec_checkra1n.c @@ -26,6 +26,9 @@ extern char **environ; extern char* gOverrideLibcheckra1nHelper; #include +#ifdef TUI +#include +#endif #include char* pongo_path = NULL; bool external_pongo = false; @@ -156,8 +159,17 @@ checkra1n_exec: {}; LOG(LOG_VERBOSE5, args); if (pongo_path != NULL) LOG(LOG_VERBOSE5, pongo_path); pid_t pid; + posix_spawn_file_actions_t action; + posix_spawn_file_actions_init(&action); +#ifdef TUI + if (tui_is_jailbreaking) { + // silence checkra1n + posix_spawn_file_actions_addopen(&action, 1, "/dev/null", O_WRONLY, 0); + posix_spawn_file_actions_addopen(&action, 2, "/dev/null", O_WRONLY, 0); + } +#endif if (pongo_path != NULL) { - ret = posix_spawn(&pid, checkra1n_path, NULL, NULL, (char* []){ + ret = posix_spawn(&pid, checkra1n_path, &action, NULL, (char* []){ checkra1n_path, args, "-k", @@ -165,12 +177,13 @@ checkra1n_exec: {}; NULL }, environ); } else { - ret = posix_spawn(&pid, checkra1n_path, NULL, NULL, (char* []){ + ret = posix_spawn(&pid, checkra1n_path, &action, NULL, (char* []){ checkra1n_path, args, NULL }, environ); } + posix_spawn_file_actions_destroy(&action); if (ret) { LOG(LOG_FATAL, "Cannot posix spawn %s: %d (%s)", checkra1n_path, errno, strerror(errno)); if (ext_checkra1n != NULL) unlink(checkra1n_path); diff --git a/src/lock_vars.c b/src/lock_vars.c index a5483b9..7da4219 100644 --- a/src/lock_vars.c +++ b/src/lock_vars.c @@ -30,11 +30,6 @@ #include pthread_mutex_t spin_mutex, found_pongo_mutex, ecid_dfu_wait_mutex; -#ifdef TUI -#include -pthread_mutex_t tui_log_mutex; -newtComponent tui_log_output = NULL; -#endif bool spin, found_pongo = 0; uint64_t ecid_wait_for_dfu = 0; @@ -88,19 +83,3 @@ uint64_t set_ecid_wait_for_dfu(uint64_t ecid) { pthread_mutex_unlock(&ecid_dfu_wait_mutex); return ecid; } - -#ifdef TUI -newtComponent get_tui_log(void) { - pthread_mutex_lock(&tui_log_mutex); - newtComponent ret = tui_log_output; - pthread_mutex_unlock(&tui_log_mutex); - return ret; -} - -newtComponent set_tui_log(newtComponent co) { - pthread_mutex_lock(&tui_log_mutex); - tui_log_output = co; - pthread_mutex_unlock(&tui_log_mutex); - return co; -} -#endif diff --git a/src/log.c b/src/log.c index 1441047..8afb5b7 100644 --- a/src/log.c +++ b/src/log.c @@ -8,8 +8,15 @@ #include #include +#ifdef TUI +#include +#endif + int p1_log(log_level_t loglevel, const char *fname, int lineno, const char *fxname, const char *__restrict format, ...) { +#ifdef TUI + if (tui_started) return 0; +#endif if (verbose >= 5 #ifdef TUI && !(palerain_flags & palerain_option_tui) @@ -61,18 +68,6 @@ int p1_log(log_level_t loglevel, const char *fname, int lineno, const char *fxna colour[0] = '\0'; colour_bold[0] = '\0'; } -#ifdef TUI - if ((palerain_flags & palerain_option_tui) && tui_started) { - newtComponent co = get_tui_log(); - if (co == NULL) { - return 0; /* 0 bytes printed */ - } - char printbuf[0x200]; - ret = vsnprintf(printbuf, 0x200, format, args); - pthread_mutex_lock(&log_mutex); - newtTextboxSetText(co, printbuf); - } else -#endif { pthread_mutex_lock(&log_mutex); char timestring[0x80]; diff --git a/src/main.c b/src/main.c index 13bc5ac..c959c68 100644 --- a/src/main.c +++ b/src/main.c @@ -90,7 +90,17 @@ void log_cb(libusb_context *ctx, enum libusb_log_level level, const char *str) { } #endif -int palera1n(int argc, char *argv[]) { +// save argc, argv, and envp for restarting + +int saved_argc; +char** saved_argv; +char** saved_envp; + +int palera1n(int argc, char *argv[], char *envp[]) { + saved_argc = argc; + saved_argv = argv; + saved_envp = envp; + print_credits(); int ret = 0; pthread_mutex_init(&log_mutex, NULL); @@ -101,7 +111,7 @@ int palera1n(int argc, char *argv[]) { if ((ret = optparse(argc, argv))) goto cleanup; if (!(palerain_flags & palerain_option_device_info) && (palerain_flags & palerain_option_palerain_version)) goto normal_exit; #ifdef TUI - if ((palerain_flags & palerain_option_tui)) { + if ((palerain_flags & palerain_option_tui) || (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && !(palerain_flags & palerain_option_cli))) { ret = tui(); if (ret) goto cleanup; else goto normal_exit; @@ -173,6 +183,6 @@ cleanup: } -int main (int argc, char* argv[]) { - return palera1n(argc, argv); +int main (int argc, char* argv[], char* envp[]) { + return palera1n(argc, argv, envp); } diff --git a/src/optparse.c b/src/optparse.c index 52d3eb0..8ad595b 100644 --- a/src/optparse.c +++ b/src/optparse.c @@ -14,6 +14,9 @@ #include #include #include +#ifdef TUI +#include +#endif uint64_t* palerain_flags_p = &palerain_flags; static bool force_use_verbose_boot = false; @@ -53,6 +56,7 @@ static struct option longopts[] = { #endif #ifdef TUI {"tui", no_argument, NULL, 't'}, + {"cli", no_argument, NULL, palerain_option_case_cli}, #endif {NULL, 0, NULL, 0} }; @@ -96,7 +100,9 @@ static int usage(int e, char* prog_name) "\t-i, --override-checkra1n \t\tOverride checkra1n\n" "\t-k, --override-pongo \t\tOverride Pongo image\n" "\t-K, --override-kpf \t\tOverride kernel patchfinder\n" +#ifdef ROOTFUL "\t-l, --rootless\t\t\t\tBoots rootless. This is the default\n" +#endif "\t-L, --jbinit-log-to-file\t\tMake jbinit log to /cores/jbinit.log (can be read from sandbox while jailbroken)\n" "\t-n, --exit-recovery\t\t\tExit recovery mode\n" "\t-I, --device-info\t\t\tPrint info about the connected device\n" @@ -112,7 +118,8 @@ static int usage(int e, char* prog_name) "\t-V, --verbose-boot\t\t\tVerbose boot\n" #ifdef TUI - "\t-t, --tui\t\t\t\tTerminal user interface\n" + "\t-t, --tui\t\t\t\tForce interactive TUI\n" + "\t--cli\t\t\t\tForce cli mode\n" #endif "\nEnvironmental variables:\n" "\tTMPDIR\t\ttemporary diretory (path the built-in checkra1n will be extracted to)\n" @@ -163,6 +170,9 @@ int optparse(int argc, char* argv[]) { case 'V': palerain_flags |= palerain_option_verbose_boot; force_use_verbose_boot = true; +#ifdef TUI + tui_options_verbose_boot = true; +#endif break; case 'e': if (strstr(optarg, "rootdev=") != NULL) { @@ -173,6 +183,9 @@ int optparse(int argc, char* argv[]) { return -1; } snprintf(xargs_cmd, sizeof(xargs_cmd), "xargs %s", optarg); +#ifdef TUI + snprintf(tui_options_boot_args, sizeof(tui_options_boot_args), "%s", optarg); +#endif break; case 'f': palerain_flags |= palerain_option_rootful; @@ -193,6 +206,9 @@ int optparse(int argc, char* argv[]) { break; case 's': palerain_flags |= palerain_option_safemode; +#ifdef TUI + tui_options_safe_mode = true; +#endif break; case 'k': if (access(optarg, F_OK) != 0) { @@ -286,6 +302,9 @@ int optparse(int argc, char* argv[]) { case 't': palerain_flags |= palerain_option_tui; break; + case palerain_option_case_cli: + palerain_flags |= palerain_option_cli; + break; #endif #ifdef DEV_BUILD case '1': @@ -297,6 +316,9 @@ int optparse(int argc, char* argv[]) { #endif case palerain_option_case_force_revert: palerain_flags |= palerain_option_force_revert; +#ifdef TUI + tui_options_force_revert = true; +#endif break; case palerain_option_case_version: palerain_flags |= palerain_option_palerain_version; @@ -336,10 +358,24 @@ int optparse(int argc, char* argv[]) { palerain_flags &= ~palerain_option_verbose_boot; } - if ((palerain_flags & (palerain_option_rootless | palerain_option_rootful)) == 0) { - LOG(LOG_FATAL, "must specify -l option"); + if ((palerain_flags & (palerain_option_tui)) && (palerain_flags & (palerain_option_cli))) { + LOG(LOG_FATAL, "cannot specify both --tui and --cli"); return -1; } + + if ((palerain_flags & (palerain_option_exit_recovery | palerain_option_enter_recovery | palerain_option_reboot_device | palerain_option_device_info | palerain_option_dfuhelper_only | palerain_option_pongo_exit | palerain_option_pongo_full)) > 0) { + palerain_flags &= ~palerain_option_tui; + palerain_flags |= palerain_option_cli; + } else { +#ifdef ROOTFUL + if ((palerain_flags & (palerain_option_rootless | palerain_option_rootful)) == 0) { + LOG(LOG_FATAL, "must specify -l option"); + return -1; + } +#else + palerain_flags |= palerain_option_rootless; +#endif + } snprintf(palerain_flags_cmd, 0x30, "palera1n_flags 0x%" PRIx64, palerain_flags); LOG(LOG_VERBOSE3, "palerain_flags: %s", palerain_flags_cmd); diff --git a/src/pongo_helper.c b/src/pongo_helper.c index f8bc44b..38ae61b 100644 --- a/src/pongo_helper.c +++ b/src/pongo_helper.c @@ -11,6 +11,9 @@ #include // fstst #include +#ifdef TUI +#include +#endif #include bool device_has_booted = 0; @@ -39,9 +42,23 @@ void *pongo_usb_callback(stuff_t *arg) { } LOG(LOG_INFO, "Found PongoOS USB Device"); usb_device_handle_t handle = arg->handle; +#ifdef TUI + if (tui_is_jailbreaking) { + tui_jailbreak_stage = 4; + tui_jailbreak_status = "Sending PongoOS commands"; + tui_jailbreak_status_changed(); + } +#endif issue_pongo_command(handle, NULL); issue_pongo_command(handle, "fuse lock"); issue_pongo_command(handle, "sep auto"); +#ifdef TUI + if (tui_is_jailbreaking) { + tui_jailbreak_stage = 5; + tui_jailbreak_status = "Sending KPF"; + tui_jailbreak_status_changed(); + } +#endif upload_pongo_file(handle, **kpf_to_upload, checkra1n_kpf_pongo_lzma_len); if (*kpf_to_upload == &checkra1n_kpf_pongo_lzma) { issue_pongo_command(handle, "modload " KPF_UNCOMPRESSED_SIZE); @@ -54,6 +71,13 @@ void *pongo_usb_callback(stuff_t *arg) { #endif { if (force_usbdevice) strncat(xargs_cmd, " AppleEmbeddedUSBArbitrator-force-usbdevice=1", 0x270 - strlen(xargs_cmd) - 1); +#ifdef TUI + if (tui_is_jailbreaking) { + tui_jailbreak_stage = 6; + tui_jailbreak_status = "Sending ramdisk"; + tui_jailbreak_status_changed(); + } +#endif upload_pongo_file(handle, **ramdisk_to_upload, ramdisk_dmg_lzma_len); if ((*ramdisk_to_upload) == &ramdisk_dmg_lzma) issue_pongo_command(handle, "ramdisk " RAMDISK_UNCOMPRESSED_SIZE); @@ -65,11 +89,26 @@ void *pongo_usb_callback(stuff_t *arg) { if (binpack_dmg_len != 0) #endif { +#ifdef TUI + if (tui_is_jailbreaking) { + tui_jailbreak_stage = 7; + tui_jailbreak_status = "Sending binpack"; + tui_jailbreak_status_changed(); + } +#endif upload_pongo_file(handle, **overlay_to_upload, binpack_dmg_len); issue_pongo_command(handle, "overlay"); } issue_pongo_command(handle, xargs_cmd); if ((palerain_flags & palerain_option_pongo_full)) goto done; + +#ifdef TUI + if (tui_is_jailbreaking) { + tui_jailbreak_stage = 8; + tui_jailbreak_status = "Booting"; + tui_jailbreak_status_changed(); + } +#endif issue_pongo_command(handle, "bootx"); LOG(LOG_INFO, "Booting Kernel..."); if ((palerain_flags & palerain_option_setup_partial_root)) { @@ -85,6 +124,15 @@ void *pongo_usb_callback(stuff_t *arg) { } done: device_has_booted = true; + +#ifdef TUI + if (tui_is_jailbreaking) { + tui_jailbreak_stage = 9; + tui_jailbreak_status = "All Done"; + tui_is_jailbreaking = false; + tui_jailbreak_status_changed(); + } +#endif #ifdef USE_LIBUSB libusb_unref_device(arg->dev); #endif diff --git a/src/tui_devhelper.c b/src/tui_devhelper.c new file mode 100644 index 0000000..fe99698 --- /dev/null +++ b/src/tui_devhelper.c @@ -0,0 +1,220 @@ +#ifdef TUI + +#include +#include + +irecv_device_t tui_get_recovery_device(uint64_t ecid) { + irecv_client_t client = NULL; + for (int i = 0; i <= 5; i++) { + irecv_error_t err = irecv_open_with_ecid(&client, ecid); + if (err == IRECV_E_UNSUPPORTED) { + return NULL; + } + else if (err != IRECV_E_SUCCESS) + sleep(1); + else + break; + + if (i == 5) { + return NULL; + } + } + + irecv_device_t device = NULL; + irecv_devices_get_device_by_client(client, &device); + irecv_close(client); + return device; +} + +struct tui_connected_device *tui_connected_devices = NULL; + +void* tui_connected_recovery_mode(struct irecv_device_info* info) { + //printf("Recovery mode device %" PRIu64 " connected\n", info->ecid); + tui_last_event = TUI_EVENT_CONNECTED_DEVICES_CHANGED; + sem_post(tui_event_semaphore); + pthread_exit(NULL); + return NULL; +} + +void* tui_disconnected_recovery_mode(struct irecv_device_info* info) { + //printf("Recovery mode device %" PRIu64 " disconnected\n", info->ecid); + tui_last_event = TUI_EVENT_CONNECTED_DEVICES_CHANGED; + sem_post(tui_event_semaphore); + pthread_exit(NULL); + return NULL; +} + +void* tui_connected_dfu_mode(struct irecv_device_info* info) { + //printf("DFU mode device %" PRIu64 " connected\n", info->ecid); + tui_last_event = TUI_EVENT_CONNECTED_DEVICES_CHANGED; + sem_post(tui_event_semaphore); + pthread_exit(NULL); + return NULL; +} + +void* tui_disconnected_dfu_mode(struct irecv_device_info* info) { + //printf("DFU mode device %" PRIu64 " disconnected\n", info->ecid); + tui_last_event = TUI_EVENT_CONNECTED_DEVICES_CHANGED; + sem_post(tui_event_semaphore); + pthread_exit(NULL); + return NULL; +} + +int tui_connected_normal_mode(const usbmuxd_device_info_t *usbmuxd_device) { + struct tui_connected_device *tui_dev = malloc(sizeof(struct tui_connected_device)); + strcpy(tui_dev->udid, usbmuxd_device->udid); + tui_dev->next = tui_connected_devices; + tui_dev->mode = TUI_DEVICE_MODE_NORMAL; + tui_connected_devices = tui_dev; + devinfo_t dev; + int ret; + ret = devinfo_cmd(&dev, usbmuxd_device->udid); + if (ret != 0) { + LOG(LOG_ERROR, "Unable to get device information"); + free(tui_dev); + return 0; + } + snprintf(tui_dev->product_type, sizeof(tui_dev->product_type), "%s", dev.productType); + snprintf(tui_dev->display_name, sizeof(tui_dev->display_name), "%s", dev.displayName); + tui_dev->ecid = dev.ecid; + if (strncmp(dev.CPUArchitecture, "arm64", strlen("arm64"))) { + tui_dev->arm64 = false; + } else { + tui_dev->arm64 = true; + } + sprintf(tui_dev->version, "%s", dev.productVersion); + if (!strncmp(dev.productType, "iPhone10,", strlen("iPhone10,"))) { + tui_dev->requires_passcode_disabled = true; + unsigned char passcode_state = 0; + ret = passstat_cmd(&passcode_state, usbmuxd_device->udid); + if (ret != 0) { + LOG(LOG_ERROR, "Failed to get passcode state"); + devinfo_free(&dev); + free(tui_dev); + return -1; + } + tui_dev->passcode_state = passcode_state; + } + + //enter_recovery_cmd(usbmuxd_device->udid); + devinfo_free(&dev); + + tui_last_event = TUI_EVENT_CONNECTED_DEVICES_CHANGED; + sem_post(tui_event_semaphore); + + return 0; +} + +void tui_disconnected_normal_mode(const usbmuxd_device_info_t *usbmuxd_device) { + struct tui_connected_device *cur = tui_connected_devices; + struct tui_connected_device *prev = NULL; + while (cur) { + if (!strcmp(cur->udid, usbmuxd_device->udid)) { + if (prev) { + prev->next = cur->next; + } else { + tui_connected_devices = cur->next; + } + free(cur); + break; + } + prev = cur; + cur = cur->next; + } + + tui_last_event = TUI_EVENT_CONNECTED_DEVICES_CHANGED; + sem_post(tui_event_semaphore); +} + +void tui_device_event_cb(const usbmuxd_event_t *event, void* userdata) { + if (event->device.conn_type != CONNECTION_TYPE_USB) return; + switch (event->event) { + case UE_DEVICE_ADD: + LOG(LOG_VERBOSE, "Normal mode device connected"); + tui_connected_normal_mode(&event->device); + break; + case UE_DEVICE_REMOVE: + LOG(LOG_VERBOSE, "Normal mode device disconnected"); + tui_disconnected_normal_mode(&event->device); + break; + } +} + +void tui_irecv_device_event_cb(const irecv_device_event_t *event, void* userdata) { + pthread_t recovery_thread, dfu_thread; + int ret; + + switch(event->type) { + case IRECV_DEVICE_ADD: { + struct tui_connected_device *dev = malloc(sizeof(struct tui_connected_device)); + dev->ecid = event->device_info->ecid; + dev->next = tui_connected_devices; + dev->arm64 = cpid_is_arm64(event->device_info->cpid); + /*recvinfo_t info; + ret = recvinfo_cmd(&info, event->device_info->ecid); + if (ret) { + LOG(LOG_WARNING, "Could not get info from device"); + } else { + snprintf(dev->product_type, sizeof(dev->product_type), "%s", info.product_type); + snprintf(dev->display_name, sizeof(dev->display_name), "%s", info.display_name); + }*/ + irecv_device_t device = tui_get_recovery_device(event->device_info->ecid); + if (!device) { + LOG(LOG_WARNING, "Could not get info from device"); + free(dev); + return; + } + snprintf(dev->product_type, sizeof(dev->product_type), "%s", device->product_type); + snprintf(dev->display_name, sizeof(dev->display_name), "%s", device->display_name); + dev->cpid = device->chip_id; + tui_connected_devices = dev; + + if (event->mode == IRECV_K_RECOVERY_MODE_1 || + event->mode == IRECV_K_RECOVERY_MODE_2 || + event->mode == IRECV_K_RECOVERY_MODE_3 || + event->mode == IRECV_K_RECOVERY_MODE_4) { + + dev->mode = TUI_DEVICE_MODE_RECOVERY; + pthread_create(&recovery_thread, NULL, (pthread_start_t)tui_connected_recovery_mode, event->device_info); + } else if (event->mode == IRECV_K_DFU_MODE) { + dev->mode = TUI_DEVICE_MODE_DFU; + pthread_create(&dfu_thread, NULL, (pthread_start_t)tui_connected_dfu_mode, event->device_info); + } + break; + } + case IRECV_DEVICE_REMOVE: { + struct tui_connected_device *cur = tui_connected_devices; + struct tui_connected_device *prev = NULL; + while (cur) { + if (cur->ecid == event->device_info->ecid) { + if (prev) { + prev->next = cur->next; + } else { + tui_connected_devices = cur->next; + } + if (cur->mode == TUI_DEVICE_MODE_RECOVERY) { + LOG(LOG_VERBOSE, "Recovery mode device %" PRIu64 " disconnected", event->device_info->ecid); + pthread_create(&recovery_thread, NULL, (pthread_start_t)tui_disconnected_recovery_mode, event->device_info); + } else if (cur->mode == TUI_DEVICE_MODE_DFU) { + LOG(LOG_VERBOSE, "DFU mode device %" PRIu64 " disconnected", event->device_info->ecid); + pthread_create(&dfu_thread, NULL, (pthread_start_t)tui_disconnected_dfu_mode, event->device_info); + } + free(cur); + break; + } + prev = cur; + cur = cur->next; + } + break; + } + } +} + +void tui_devhelper(void) { + subscribe_cmd(tui_device_event_cb, tui_irecv_device_event_cb); +} + +#else +/* ISO C forbids an empty translation unit */ +extern char** environ; +#endif diff --git a/src/tui_input.c b/src/tui_input.c new file mode 100644 index 0000000..cc6f6b4 --- /dev/null +++ b/src/tui_input.c @@ -0,0 +1,166 @@ +#ifdef TUI + +#include + +#ifdef __linux__ +#include +#endif + +int tui_mouse_x = 0; +int tui_mouse_y = 0; +int tui_mouse_button = -1; + +int tui_last_event = -1; +int tui_last_input = -1; +sem_t *tui_event_semaphore; +char tui_last_key = 0; + +#ifdef __linux__ +bool using_gpm = false; +#endif + +int tui_get_input(void) { + char c = getc(stdin); + if (c == '\x1b' && getc(stdin) == '[') { + char c3 = getc(stdin); + switch (c3) { + case 'D': + return TUI_INPUT_LEFT; + case 'C': + return TUI_INPUT_RIGHT; + case 'A': + return TUI_INPUT_UP; + case 'B': + return TUI_INPUT_DOWN; + case 'Z': + return TUI_INPUT_TAB_BACK; + case 'M': { + char c4 = getc(stdin); + char c5 = getc(stdin); + char c6 = getc(stdin); + + int new_mouse_x = c5 - 33; + if (new_mouse_x < 0) new_mouse_x += 256; + int new_mouse_y = c6 - 33; + if (new_mouse_y < 0) new_mouse_y += 256; + int mouse_button = c4 & 3; + + if (tui_mouse_x != new_mouse_x || tui_mouse_y != new_mouse_y) { + tui_mouse_x = new_mouse_x; + tui_mouse_y = new_mouse_y; + return TUI_INPUT_MOUSE_MOVE; + } + + if (tui_mouse_button != (c4 & 1)) { + tui_mouse_button = c4 & 1; + if (tui_mouse_button == 0) { + return TUI_INPUT_MOUSE_DOWN; + } else { + return TUI_INPUT_MOUSE_UP; + } + } + + break; + } + } + } + + tui_last_key = c; + + if (c == '\x0d' || c == ' ') { + return TUI_INPUT_SELECT; + } + + if (c == '\t') { + return TUI_INPUT_TAB; + } + + if (c == '\x7f') { + return TUI_INPUT_BACKSPACE; + } + + if (c == '\x1b') { + return TUI_INPUT_ESCAPE; + } + + return TUI_INPUT_NONE; +} + +#ifdef __linux__ +void *tui_gpm_thread(void *arg) { + Gpm_Event event; + while (1) { + if (Gpm_GetEvent(&event) == -1) { + exit(1); + } + tui_mouse_x = event.x - 1; + tui_mouse_y = event.y - 1; + if (event.type & GPM_MOVE) { + tui_last_event = TUI_EVENT_INPUT; + tui_last_input = TUI_INPUT_MOUSE_MOVE; + sem_post(tui_event_semaphore); + } + if (event.buttons & 4) { + if (event.type & GPM_DOWN) { + tui_mouse_button = 1; + tui_last_event = TUI_EVENT_INPUT; + tui_last_input = TUI_INPUT_MOUSE_DOWN; + sem_post(tui_event_semaphore); + } else if (event.type & GPM_UP) { + tui_mouse_button = 0; + tui_last_event = TUI_EVENT_INPUT; + tui_last_input = TUI_INPUT_MOUSE_UP; + sem_post(tui_event_semaphore); + } + continue; + } + } +} +#endif + +void *tui_input_thread(void *arg) { +#ifdef __linux__ + if (strncmp(getenv("TERM"), "linux", 5) == 0) { + Gpm_Connect conn; + Gpm_Event event; + conn.eventMask = GPM_UP | GPM_DOWN; + conn.defaultMask = ~0; + conn.minMod = 0; + conn.maxMod = 0xffff; + if (Gpm_Open(&conn, 0) != -1) { + using_gpm = true; + pthread_t gpm_thread; + pthread_create(&gpm_thread, NULL, tui_gpm_thread, NULL); + } + } +#endif + while (1) { + int input = tui_get_input(); + tui_last_event = TUI_EVENT_INPUT; + tui_last_input = input; + sem_post(tui_event_semaphore); + } + return 0; +} + +int tui_get_event(void) { + sem_wait(tui_event_semaphore); + int last_event = tui_last_event; + tui_last_event = -1; + return last_event; +} + +int tui_try_get_event(void) { + int ret = sem_trywait(tui_event_semaphore); + if (ret == 0) { + int last_event = tui_last_event; + tui_last_event = -1; + return last_event; + } + return -1; +} + +#else +/* ISO C forbids an empty translation unit */ +extern char** environ; +#endif diff --git a/src/tui_main.c b/src/tui_main.c index 64e49a0..d5d80d7 100644 --- a/src/tui_main.c +++ b/src/tui_main.c @@ -1,7 +1,13 @@ #ifdef TUI +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE +#else +#define _DEFAULT_SOURCE +#endif #include #include #include +#include #include #include #include @@ -9,97 +15,240 @@ #include #include #include +#include +#include +#include +#include #include #include +#ifdef __APPLE__ +int proc_pidpath(int pid, void * buffer, uint32_t buffersize); +char random_sem_name[sizeof("palera1n.tui_event_semaphore") + 16 + 1]; +#endif + +int tui_state = 0; +int tui_x_offset = 0; +int tui_y_offset = 0; + +bool supports_bright_colors = true; + +struct termios saved_termios; + int redraw_screen(void) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + CLEAR_SCREEN; + MOVETO(0, 0); + + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + if (w.ws_col < 80 || w.ws_row < 24) { + LOG(LOG_FATAL, "Terminal size must be at least 80x24"); + printf("\033[37;41mERROR: Terminal size must be at least 80x24!"); + fflush(stdout); + return -1; + } + tui_y_offset = (w.ws_row - 24) / 2; + for (int i = 0; i < tui_y_offset; i++) { + printf("\n"); + } + tui_x_offset = (w.ws_col - 80) / 2; + + const char* tui_version = TUI_VERSION; + if (tui_version[0] == 'v') tui_version++; + + tui_draw_rectangle(0, 0, 79, 23); + MOVETOT((int)(80 - (strlen("[palera1n - Version ]") + strlen(tui_version) ) - 1), 1); + printf("[palera1n - Version %s]", tui_version); + SETCOLOR(FG_WHITE, BG_BLACK); + switch(tui_state) { + case MAIN_SCREEN: + tui_screen_main_redraw(); + break; + case OPTIONS_SCREEN: + tui_screen_options_redraw(); + break; + case ENTER_RECOVERY_SCREEN: + tui_screen_enter_recovery_redraw(); + break; + case ENTER_DFU_SCREEN: + tui_screen_enter_dfu_redraw(); + break; + case JAILBREAK_SCREEN: + tui_screen_jailbreak_redraw(); + break; + } + fflush(stdout); return 0; } int destroy_window(void) { + if (!tui_started) return 0; + tui_started = false; + tcsetattr(STDIN_FILENO, 0, &saved_termios); + MOUSEOFF; + CLEAR_SCREEN; + + MOVETO(0, 0); + RMCUP; + CNORM; + return 0; } int init_window(void) { setlocale(LC_ALL, NULL); - setenv( - "NEWT_COLORS", - "root=,black\n" - "border=lightgray,black\n" - "title=lightgray,black\n" - "roottext=red,black\n" - "label=lightgray,black\n" - "entry=lightgray,black\n" - "window=red,black\n" - "textbox=lightgray,black\n" - "button=black,lightgray\n" - "compactbutton=lightgray,black\n" - "listbox=lightgray,black\n" - "actlistbox=black,lightgray\n" - "actsellistbox=black,lightgray\n" - "checkbox=lightgray,black\n" - "actcheckbox=black,lightgray\n", - 0); tui_started = true; - newtInit(); - int cols, rows; - newtGetScreenSize(&cols, &rows); - if (cols < 80 || rows < 24) { - newtFinished(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + if (w.ws_col < 80 || w.ws_row < 24) { tui_started = false; LOG(LOG_FATAL, "Terminal size must be at least 80x24"); return -1; } - LOG(LOG_VERBOSE3, "cols: %d, rows: %d\n", cols, rows); - newtCls(); - newtSetColor(PI_LOG_COLOR, "yellow", "black"); - newtSetColor(PI_STEP_CURRENT, "lightgray", "black"); - newtSetColor(PI_STEP_OTHER, "gray", "black"); - newtDrawRootText(0, 0, "palera1n version 2.0.0"); - newtPushHelpLine(NULL); + LOG(LOG_VERBOSE3, "cols: %d, rows: %d\n", w.ws_col, w.ws_row); + SMCUP; + CIVIS; + fflush(stdout); + struct termios term; + tcgetattr(STDIN_FILENO, &term); + tcgetattr(STDIN_FILENO, &saved_termios); + cfmakeraw(&term); + term.c_lflag |= ISIG; + tcsetattr(STDIN_FILENO, 0, &term); + + MOUSEON; + return 0; } +bool tui_is_restarting = false; + +extern int saved_argc; +extern char** saved_argv; +extern char** saved_envp; + +void tui_terminate(int sig) { + destroy_window(); + if (tui_is_restarting) { +#ifdef __APPLE__ + sem_close(tui_event_semaphore); + sem_unlink(random_sem_name); + char pathbuf[4096]; + if (proc_pidpath(getpid(), pathbuf, sizeof(pathbuf)) <= 0) { + LOG(LOG_FATAL, "Failed to get path of running executable"); + exit(1); + } + + execve(pathbuf, saved_argv, saved_envp); +#elif defined(__linux__) + execve("/proc/self/exe", saved_argv, saved_envp); +#endif + } else { + exit(0); + } +} + +void resize_handler(int sig) { + redraw_screen(); +} + int tui(void) { + if (strncmp(getenv("TERM"), "xterm", 5) != 0) { + supports_bright_colors = false; + } + srand(time(NULL)); int ret = 0; if ((ret = init_window())) return ret; - ret = MAIN_SCREEN; + signal(SIGINT, tui_terminate); + signal(SIGTERM, tui_terminate); + signal(SIGQUIT, tui_terminate); + signal(SIGWINCH, resize_handler); + +#ifdef __APPLE__ + // generate a 16 character random hex string from urandom + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + LOG(LOG_FATAL, "Failed to open /dev/urandom"); + return -1; + } + uint8_t random[8]; + if (read(fd, random, 8) != 8) { + LOG(LOG_FATAL, "Failed to read from /dev/urandom"); + return -1; + } + close(fd); + for (int i = 0; i < 8; i++) { + sprintf(&random_sem_name[i * 2], "%02x", random[i]); + } + sem_unlink(random_sem_name); + tui_event_semaphore = sem_open(random_sem_name, O_CREAT, 0644, 0); +#else + tui_event_semaphore = malloc(sizeof(sem_t)); + sem_init(tui_event_semaphore, 0, 0); +#endif + pthread_t input_thread; + pthread_create(&input_thread, NULL, tui_input_thread, NULL); + + tui_devhelper(); + + tui_state = MAIN_SCREEN; while (1) { - switch (ret) { + switch (tui_state) { case ERROR_SCREEN: - goto out; - break; case EXIT_SCREEN: goto out; break; case MAIN_SCREEN: - ret = tui_screen_main(); + tui_state = tui_screen_main(); break; case OPTIONS_SCREEN: - ret = tui_screen_options(); + tui_state = tui_screen_options(); break; case ENTER_RECOVERY_SCREEN: - ret = tui_screen_enter_recovery(); + tui_state = tui_screen_enter_recovery(); break; case ENTER_DFU_SCREEN: - ret = tui_screen_enter_dfu(); + tui_state = tui_screen_enter_dfu(); break; - case JAILBREAKING_SCREEN: - ret = tui_screen_jailbreak(); + case JAILBREAK_SCREEN: + tui_state = tui_screen_jailbreak(); break; default: assert(0); goto out; } - newtPopWindow(); } out: - newtFinished(); - tui_started = false; + destroy_window(); return 0; } + +void tui_draw_rectangle(int x1, int y1, int x2, int y2) { + if (x1 == x2 || y1 == y2) return; + DSGON; + MOVETOT(x1 + 1, y1 + 1); + printf("%c", 0x6C); + for (int x = x1 + 1; x < x2; x++) { + putchar(0x71); + } + putchar(0x6B); + MOVETOT(x1 + 1, y2 + 1); + putchar(0x6D); + for (int x = x1 + 1; x < x2; x++) { + putchar(0x71); + } + putchar(0x6A); + for (int y = y1 + 1; y < y2; y++) { + PRINTATT(x1 + 1, y + 1, "\x78"); + PRINTATT(x2 + 1, y + 1, "\x78"); + } + DSGOFF; + fflush(stdout); +} + #else /* ISO C forbids an empty translation unit */ extern char** environ; diff --git a/src/tui_screen_enter_dfu.c b/src/tui_screen_enter_dfu.c index f6ef518..afd1409 100644 --- a/src/tui_screen_enter_dfu.c +++ b/src/tui_screen_enter_dfu.c @@ -13,8 +13,460 @@ #include #include -tui_screen_t tui_screen_enter_dfu(void) { return JAILBREAKING_SCREEN; } +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int tui_enter_dfu_nav_selection = 1; +bool tui_device_is_entering_dfu = false; +int tui_enter_dfu_status = 0; + +enum { + DEVICE_TYPE_IPHONE_SE, + DEVICE_TYPE_IPHONE_6S, + DEVICE_TYPE_IPHONE_7_8, + DEVICE_TYPE_IPHONE_X, + DEVICE_TYPE_IPAD, + DEVICE_TYPE_IPOD_TOUCH +} device_type; + +int tui_product_type_to_device_type(char *product_type) { + if (strcmp(product_type, "iPhone8,1") == 0 || strcmp(product_type, "iPhone8,2") == 0) { + return DEVICE_TYPE_IPHONE_6S; + } + if (strcmp(product_type, "iPhone8,4") == 0) return DEVICE_TYPE_IPHONE_SE; + if (strcmp(product_type, "iPhone9,1") == 0 || strcmp(product_type, "iPhone9,2") == 0 + || strcmp(product_type, "iPhone9,3") == 0 || strcmp(product_type, "iPhone9,4") == 0) { + return DEVICE_TYPE_IPHONE_7_8; + } + if (strcmp(product_type, "iPhone10,1") == 0 || strcmp(product_type, "iPhone10,2") == 0 + || strcmp(product_type, "iPhone10,4") == 0 || strcmp(product_type, "iPhone10,5") == 0) { + return DEVICE_TYPE_IPHONE_7_8; + } + if (strcmp(product_type, "iPhone10,3") == 0 || strcmp(product_type, "iPhone10,6") == 0) { + return DEVICE_TYPE_IPHONE_X; + } + if (strncmp(product_type, "iPad", strlen("iPad")) == 0) { + return DEVICE_TYPE_IPAD; + } + if (strcmp(product_type, "iPod9,1") == 0) { + return DEVICE_TYPE_IPOD_TOUCH; + } + + // Not found + return DEVICE_TYPE_IPHONE_SE; +} + +int tui_enter_dfu_device_type = DEVICE_TYPE_IPHONE_SE; + +int tui_enter_dfu_loading_progress = 1; + +void tui_screen_enter_dfu_nav(void) { + MOVETOT(80 - 22, 23); + printf("%s[ Cancel ]" COLOR(FG_WHITE, BG_BLACK) " %s[ %s ]" COLOR(FG_WHITE, BG_BLACK), + tui_device_is_entering_dfu || tui_enter_dfu_status == 1 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : tui_enter_dfu_nav_selection == 0 ? "\033[30;107m" : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 23 && tui_mouse_x <= tui_x_offset + 80 - 23 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), + tui_device_is_entering_dfu || tui_enter_dfu_status == 1 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : tui_enter_dfu_nav_selection == 1 ? "\033[30;107m" : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), + tui_enter_dfu_status == 2 ? "Retry" : "Start" + ); +} + +void tui_screen_enter_dfu_redraw(void) { + SETCOLOR(FG_WHITE, BG_BLACK); + switch(tui_enter_dfu_status) { + case 0: + PRINTATT(3, 3, "Time to put the device into DFU mode. Locate the buttons as marked below on"); + PRINTATT(3, 4, "your device and check the instructions on the right *before* clicking Start."); + break; + case 1: + PRINTATT(3, 3, "Device entered DFU mode successfully."); + break; + case 2: + PRINTATT(3, 3, "Whoops, the device didn't enter DFU mode. Click Retry to try again."); + break; + } + + tui_screen_enter_dfu_nav(); + + switch(tui_enter_dfu_device_type) { + case DEVICE_TYPE_IPHONE_SE: + case DEVICE_TYPE_IPAD: + if (tui_enter_dfu_loading_progress > 0 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 6, "1. Click Start"); + if (tui_enter_dfu_loading_progress > 0) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + + if (!tui_device_is_entering_dfu || tui_enter_dfu_loading_progress > 4 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 7, "2. Press and hold the Top and"); + MOVETOT(54, 8); + printf("Home buttons together (%d)", tui_enter_dfu_loading_progress > 4 ? 0 : tui_enter_dfu_loading_progress < 1 ? 4 : 5 - tui_enter_dfu_loading_progress); + if (!tui_device_is_entering_dfu || tui_enter_dfu_loading_progress > 4) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + + if (tui_enter_dfu_loading_progress < 5 || tui_enter_dfu_loading_progress > 14 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 9, "3. Release the Top button BUT"); + PRINTATT(54, 10, "KEEP HOLDING the Home"); + MOVETOT(54, 11); + printf("button (%d)", tui_enter_dfu_loading_progress > 14 ? 0 : tui_enter_dfu_loading_progress < 5 ? 10 : 15 - tui_enter_dfu_loading_progress); + if (tui_enter_dfu_loading_progress < 5 || tui_enter_dfu_loading_progress > 14) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + break; + case DEVICE_TYPE_IPHONE_6S: + if (tui_enter_dfu_loading_progress > 0 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 6, "1. Click Start"); + if (tui_enter_dfu_loading_progress > 0) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + + if (!tui_device_is_entering_dfu || tui_enter_dfu_loading_progress > 4 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 7, "2. Press and hold the Side"); + PRINTATT(54, 8, "and Home buttons together"); + MOVETOT(54, 9); + printf("(%d)", tui_enter_dfu_loading_progress > 4 ? 0 : tui_enter_dfu_loading_progress < 1 ? 4 : 5 - tui_enter_dfu_loading_progress); + if (!tui_device_is_entering_dfu || tui_enter_dfu_loading_progress > 4) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + + if (tui_enter_dfu_loading_progress < 5 || tui_enter_dfu_loading_progress > 14 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 10, "3. Release the Side button"); + PRINTATT(54, 11, "BUT KEEP HOLDING the Home"); + MOVETOT(54, 12); + printf("button (%d)", tui_enter_dfu_loading_progress > 14 ? 0 : tui_enter_dfu_loading_progress < 5 ? 10 : 15 - tui_enter_dfu_loading_progress); + if (tui_enter_dfu_loading_progress < 5 || tui_enter_dfu_loading_progress > 14) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + break; + case DEVICE_TYPE_IPHONE_7_8: + case DEVICE_TYPE_IPHONE_X: + tui_draw_rectangle(17, 5, 33, 21); + PRINTATT(17, 10, "|"); + MOVETOT(5, 11); + printf("%sVolume down-", tui_enter_dfu_loading_progress > 14 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + putchar('|'); + DSGON; + MOVETOT(35, 10); + putchar(0x78); + DSGOFF; + printf("%s-Side button", tui_enter_dfu_loading_progress > 4 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + + if (tui_enter_dfu_loading_progress > 0 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 6, "1. Click Start"); + if (tui_enter_dfu_loading_progress > 0) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + + if (!tui_device_is_entering_dfu || tui_enter_dfu_loading_progress > 4 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 7, "2. Press and hold the Side"); + PRINTATT(54, 8, "and Volume down buttons"); + MOVETOT(54, 9); + printf("together (%d)", tui_enter_dfu_loading_progress > 4 ? 0 : tui_enter_dfu_loading_progress < 1 ? 4 : 5 - tui_enter_dfu_loading_progress); + if (!tui_device_is_entering_dfu || tui_enter_dfu_loading_progress > 4) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + + if (tui_enter_dfu_loading_progress < 5 || tui_enter_dfu_loading_progress > 14 || tui_enter_dfu_status == 2) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } + PRINTATT(51, 10, "3. Release the Side button"); + PRINTATT(54, 11, "BUT KEEP HOLDING the"); + MOVETOT(54, 12); + printf("Volume down button (%d)", tui_enter_dfu_loading_progress > 14 ? 0 : tui_enter_dfu_loading_progress < 5 ? 10 : 15 - tui_enter_dfu_loading_progress); + if (tui_enter_dfu_loading_progress < 5 || tui_enter_dfu_loading_progress > 14) { + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + break; + } + + switch(tui_enter_dfu_device_type) { + case DEVICE_TYPE_IPHONE_SE: + tui_draw_rectangle(18, 6, 32, 21); + tui_draw_rectangle(24, 19, 26, 20); + for (int y = 9; y < 20; y++) { + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + PRINTATT(20, y, " "); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + PRINTATT(23, 8, "o ==="); + PRINTATT(18, 11, "|"); + PRINTATT(18, 12, "|"); + MOVETOT(30, 6); + printf("__ %s-Top button", tui_enter_dfu_loading_progress > 4 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + MOVETOT(31, 20); + printf("%s-Home button", tui_enter_dfu_loading_progress > 14 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + + break; + case DEVICE_TYPE_IPHONE_6S: + tui_draw_rectangle(17, 5, 33, 21); + tui_draw_rectangle(24, 19, 26, 20); + for (int y = 8; y < 20; y++) { + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + PRINTATT(19, y, " "); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + PRINTATT(23, 7, "o ==="); + PRINTATT(17, 10, "|"); + PRINTATT(17, 11, "|"); + MOVETOT(35, 10); + printf("|%s-Side button", tui_enter_dfu_loading_progress > 4 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + MOVETOT(30, 20); + printf("%s-Home button", tui_enter_dfu_loading_progress > 14 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + break; + case DEVICE_TYPE_IPHONE_7_8: + tui_draw_rectangle(24, 19, 26, 20); + for (int y = 8; y < 20; y++) { + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + PRINTATT(19, y, " "); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + PRINTATT(23, 7, "o ==="); + + break; + case DEVICE_TYPE_IPHONE_X: + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + PRINTATT(19, 7, " "); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + printf(" "); + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + printf(" "); + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + for (int y = 8; y < 22; y++) { + PRINTATT(19, y, " "); + } + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + + DSGON; + MOVETOT(35, 11); + putchar(0x78); + DSGOFF; + + break; + case DEVICE_TYPE_IPAD: + tui_draw_rectangle(14, 6, 36, 21); + tui_draw_rectangle(24, 19, 26, 20); + for (int y = 9; y < 20; y++) { + SETCOLOR(FG_BLACK, BG_BRIGHT_BLACK); + PRINTATT(16, y, " "); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + } + PRINTATT(23, 8, "o ==="); + PRINTATT(14, 11, "|"); + PRINTATT(14, 12, "|"); + MOVETOT(33, 6); + printf("__ %s-Top button", tui_enter_dfu_loading_progress > 4 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + MOVETOT(29, 21); + printf("%s-Home button", tui_enter_dfu_loading_progress > 14 ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : COLOR(FG_YELLOW, BG_BLACK)); + SETCOLOR(FG_BRIGHT_WHITE, BG_BLACK); + + break; + } + fflush(stdout); +} + +// TODO: IMPLEMENT REAL ENTER RECOVERY +int dfu_time = 0; + +tui_screen_t tui_enter_dfu(void) { + if (tui_connected_devices && !tui_connected_devices->next) { + if (tui_connected_devices->mode == TUI_DEVICE_MODE_NORMAL) { + tui_enter_dfu_status = 0; + return ENTER_RECOVERY_SCREEN; + } + } + int i = 0; + tui_enter_dfu_loading_progress = 1; + while(1) { + if (++i % 10 == 0) { + tui_enter_dfu_loading_progress++; + } + redraw_screen(); + usleep(100000); + int event = tui_try_get_event(); + if (event == TUI_EVENT_CONNECTED_DEVICES_CHANGED) { + if (tui_connected_devices && !tui_connected_devices->next) { + if (tui_connected_devices->mode == TUI_DEVICE_MODE_RECOVERY || tui_connected_devices->mode == TUI_DEVICE_MODE_NORMAL) { + tui_enter_dfu_status = 2; + tui_device_is_entering_dfu = false; + return ENTER_DFU_SCREEN; + } else { + tui_enter_dfu_status = 1; + tui_device_is_entering_dfu = false; + tui_enter_dfu_loading_progress = 15; + redraw_screen(); + sleep(3); + tui_jailbreak(); + return JAILBREAK_SCREEN; + } + } + } + if (i > 10 * (60 + 15)) { + return MAIN_SCREEN; + } + if (i == 10 * 2) { + exitrecv_cmd(tui_connected_devices->ecid); + } + } + redraw_screen(); + fflush(stdout); + sleep(3); + return JAILBREAK_SCREEN; +} + +int tui_enter_dfu_nav_mouse_select = -1; + +tui_screen_t tui_screen_enter_dfu(void) { + if (tui_connected_devices && !tui_connected_devices->next) { + tui_enter_dfu_device_type = tui_product_type_to_device_type(tui_connected_devices->product_type); + } + + tui_device_is_entering_dfu = false; + tui_enter_dfu_loading_progress = 0; + tui_enter_dfu_nav_selection = 1; + redraw_screen(); + + tui_device_is_entering_dfu = false; + tui_enter_dfu_loading_progress = 0; + + while(1) { + int event = tui_get_event(); + switch (event) { + case TUI_EVENT_CONNECTED_DEVICES_CHANGED: + break; + case TUI_EVENT_INPUT: { + int input = tui_last_input; + if (input == TUI_INPUT_NONE) continue; + if (tui_device_is_entering_dfu) continue; + + switch (input) { + case TUI_INPUT_LEFT: + case TUI_INPUT_RIGHT: + tui_enter_dfu_nav_selection = !tui_enter_dfu_nav_selection; + redraw_screen(); + break; + case TUI_INPUT_SELECT: + switch(tui_enter_dfu_nav_selection) { + case 0: + return MAIN_SCREEN; + case 1: + tui_device_is_entering_dfu = true; + redraw_screen(); + return tui_enter_dfu(); + } + case TUI_INPUT_MOUSE_MOVE: + tui_screen_enter_dfu_nav(); + fflush(stdout); + break; + case TUI_INPUT_MOUSE_DOWN: + if (tui_mouse_y == tui_y_offset + 22) { + if (tui_mouse_x >= tui_x_offset + 80 - 23 && tui_mouse_x <= tui_x_offset + 80 - 23 + 10) { + tui_enter_dfu_nav_selection = 0; + tui_enter_dfu_nav_mouse_select = 0; + redraw_screen(); + } else if (tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10) { + tui_enter_dfu_nav_selection = 1; + tui_enter_dfu_nav_mouse_select = 1; + redraw_screen(); + } + } + break; + case TUI_INPUT_MOUSE_UP: + if (tui_mouse_y == tui_y_offset + 22) { + if (tui_mouse_x >= tui_x_offset + 80 - 23 && tui_mouse_x <= tui_x_offset + 80 - 23 + 10) { + return MAIN_SCREEN; + } else if (tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10) { + tui_device_is_entering_dfu = true; + redraw_screen(); + return tui_enter_dfu(); + } + } + tui_enter_dfu_nav_mouse_select = -1; + break; + } + break; + } + } + } + return MAIN_SCREEN; +} #else /* ISO C forbids an empty translation unit */ extern char** environ; diff --git a/src/tui_screen_enter_recovery.c b/src/tui_screen_enter_recovery.c index f1e1d5f..d977694 100644 --- a/src/tui_screen_enter_recovery.c +++ b/src/tui_screen_enter_recovery.c @@ -9,12 +9,200 @@ #include #include #include - +#include +#include #include #include -tui_screen_t tui_screen_enter_recovery(void) { return ENTER_DFU_SCREEN; } +int tui_enter_recovery_nav_selection = 1; +bool tui_device_is_entering_recovery = false; +bool tui_enter_recovery_mode_failed = false; +void tui_screen_enter_recovery_nav(void) { + MOVETOT(80 - 22, 23); + printf("%s[ Back ]" COLOR(FG_WHITE, BG_BLACK) " %s[ Next ]" COLOR(FG_WHITE, BG_BLACK), + tui_device_is_entering_recovery ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : tui_enter_recovery_nav_selection == 0 ? "\033[30;107m" : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 23 && tui_mouse_x <= tui_x_offset + 80 - 23 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), + tui_device_is_entering_recovery ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : tui_enter_recovery_nav_selection == 1 ? "\033[30;107m" : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ) + ); +} + +char enter_recovery_loading[9][8] = { + "........", + "|.......", + ".|......", + "..|.....", + "...|....", + "....|...", + ".....|..", + "......|.", + ".......|" +}; + +char enter_recovery_loading_troll[9][8] = { + ".......", + "t......", + ".r.....", + "..o....", + "...l...", + "....l..", + ".....e.", + "......d", +}; + +bool is_troll; +int tui_enter_recovery_loading_progress = 0; + +void tui_screen_enter_recovery_loading(void) { + SETCOLOR(FG_YELLOW, BG_BLACK); + PRINTATT(3, 8, "Entering recovery mode "); + printf("%.8s", is_troll ? enter_recovery_loading_troll[tui_enter_recovery_loading_progress] : enter_recovery_loading[tui_enter_recovery_loading_progress]); + SETCOLOR(FG_WHITE, BG_BLACK); + fflush(stdout); +} + +void tui_screen_enter_recovery_redraw(void) { + PRINTATT(3, 3, "The device needs to be put into DFU mode to apply the jailbreak. This is a"); + PRINTATT(3, 4, "manual process and we will guide you through it."); + PRINTATT(3, 5, "In order to prevent filesystem corruption through hard reset, the device"); + PRINTATT(3, 6, "will be put into recovery mode first. Click Next when you are ready."); + + if (tui_enter_recovery_mode_failed) { + SETCOLOR(FG_YELLOW, BG_BLACK); + PRINTATT(3, 8, "Hmm... device did not enter recovery mode!? Click Next to try again..."); + SETCOLOR(FG_WHITE, BG_BLACK); + } + + tui_screen_enter_recovery_nav(); + if (tui_device_is_entering_recovery) { + tui_screen_enter_recovery_loading(); + } + + fflush(stdout); +} + +int recovery_time = 0; + +tui_screen_t tui_enter_recovery(void) { + enter_recovery_cmd(tui_connected_devices->udid); + is_troll = false; + if (rand() % 1000 == 0) { + is_troll = true; + } + int i = 0; + recovery_time = 0; + while(1) { + redraw_screen(); + tui_enter_recovery_loading_progress++; + tui_enter_recovery_loading_progress %= 9; + // 100ms sleep + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep(&ts, NULL); + + int event = tui_try_get_event(); + if (event == TUI_EVENT_CONNECTED_DEVICES_CHANGED) { + if (tui_connected_devices && !tui_connected_devices->next && tui_connected_devices->mode == TUI_DEVICE_MODE_RECOVERY) { + SETCOLOR(FG_YELLOW, BG_BLACK); + PRINTATT(3, 8, "Device is now in recovery mode."); + SETCOLOR(FG_WHITE, BG_BLACK); + fflush(stdout); + + sleep(3); + + return ENTER_DFU_SCREEN; + } + } + if (i > 60 * 10) { + tui_enter_recovery_mode_failed = true; + return ENTER_RECOVERY_SCREEN; + } + } +} + +int tui_enter_recovery_nav_mouse_select = -1; + +tui_screen_t tui_screen_enter_recovery(void) { + tui_device_is_entering_recovery = false; + tui_enter_recovery_loading_progress = 0; + tui_enter_recovery_nav_selection = 1; + redraw_screen(); + + while(1) { + int event = tui_get_event(); + switch (event) { + case TUI_EVENT_CONNECTED_DEVICES_CHANGED: + tui_enter_recovery_mode_failed = false; + return MAIN_SCREEN; + case TUI_EVENT_INPUT: { + int input = tui_last_input; + if (input == TUI_INPUT_NONE) continue; + if (tui_device_is_entering_recovery) continue; + + switch (input) { + case TUI_INPUT_LEFT: + case TUI_INPUT_RIGHT: + tui_enter_recovery_nav_selection = !tui_enter_recovery_nav_selection; + redraw_screen(); + break; + case TUI_INPUT_SELECT: + switch(tui_enter_recovery_nav_selection) { + case 0: + tui_enter_recovery_mode_failed = false; + return MAIN_SCREEN; + case 1: + tui_device_is_entering_recovery = true; + redraw_screen(); + return tui_enter_recovery(); + } + break; + case TUI_INPUT_MOUSE_MOVE: + tui_screen_enter_recovery_nav(); + fflush(stdout); + break; + case TUI_INPUT_MOUSE_DOWN: + if (tui_mouse_y == tui_y_offset + 22) { + if (tui_mouse_x >= tui_x_offset + 80 - 23 && tui_mouse_x <= tui_x_offset + 80 - 23 + 10) { + tui_enter_recovery_nav_selection = 0; + tui_enter_recovery_nav_mouse_select = 0; + tui_screen_enter_recovery_nav(); + fflush(stdout); + } else if (tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10) { + tui_enter_recovery_nav_selection = 1; + tui_enter_recovery_nav_mouse_select = 1; + tui_screen_enter_recovery_nav(); + fflush(stdout); + } + } + break; + case TUI_INPUT_MOUSE_UP: + if (tui_mouse_y == tui_y_offset + 22) { + if (tui_mouse_x >= tui_x_offset + 80 - 23 && tui_mouse_x <= tui_x_offset + 80 - 23 + 10) { + return MAIN_SCREEN; + } else if (tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10) { + tui_device_is_entering_recovery = true; + redraw_screen(); + return tui_enter_recovery(); + } + } + tui_enter_recovery_nav_mouse_select = -1; + break; + } + break; + } + } + } + tui_enter_recovery_mode_failed = false; + return MAIN_SCREEN; +} #else /* ISO C forbids an empty translation unit */ extern char** environ; diff --git a/src/tui_screen_jailbreak.c b/src/tui_screen_jailbreak.c index c533180..7719178 100644 --- a/src/tui_screen_jailbreak.c +++ b/src/tui_screen_jailbreak.c @@ -13,7 +13,161 @@ #include #include -tui_screen_t tui_screen_jailbreak(void) { return EXIT_SCREEN; } +bool tui_is_jailbreaking = false; + +void tui_screen_jailbreak_nav(void) { + if (tui_is_jailbreaking) { + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + } else { + SETCOLOR(FG_BLACK, BG_BRIGHT_WHITE); + } + PRINTATT(80 - 11, 23, "[ Done ]"); + SETCOLOR(FG_WHITE, BG_BLACK); +} + +pthread_t tui_jailbreak_thread_id; +int tui_jailbreak_stage = 0; +char *tui_jailbreak_status = NULL; + +void tui_jailbreak_status_changed(void) { + tui_last_event = TUI_EVENT_JAILBREAK_STATUS_CHANGED; + sem_post(tui_event_semaphore); +} + +void *tui_jailbreak_thread(void *arg) { + tui_jailbreak_stage = 1; + tui_jailbreak_status = "About to execute checkra1n"; + + tui_jailbreak_status_changed(); + + if (!tui_connected_devices || tui_connected_devices->next || tui_connected_devices->mode != TUI_DEVICE_MODE_DFU) { + tui_jailbreak_status = "ERROR: No single device in DFU mode found"; + tui_jailbreak_status_changed(); + pthread_exit(NULL); + return NULL; + } + + tui_jailbreak_stage = 2; + tui_jailbreak_status = "Running exploit"; + tui_jailbreak_status_changed(); + + if (exec_checkra1n() != 0) { + tui_jailbreak_status = "ERROR: Failed to run exploit"; + tui_jailbreak_status_changed(); + pthread_exit(NULL); + return NULL; + } + + tui_jailbreak_stage = 3; + tui_jailbreak_status = "Waiting for PongoOS"; + tui_jailbreak_status_changed(); + + sleep(2); + pthread_create(&pongo_thread, NULL, pongo_helper, NULL); + + // pongo helper will take care of the rest + + pthread_exit(NULL); +} + +void tui_jailbreak(void) { + tui_is_jailbreaking = true; + if (tui_options_verbose_boot) { + palerain_flags |= palerain_option_verbose_boot; + } else { + palerain_flags &= ~palerain_option_verbose_boot; + } + + if (tui_options_safe_mode) { + palerain_flags |= palerain_option_safemode; + } else { + palerain_flags &= ~palerain_option_safemode; + } + + if (tui_options_force_revert) { + palerain_flags |= palerain_option_force_revert; + } else { + palerain_flags &= ~palerain_option_force_revert; + } + + snprintf(palerain_flags_cmd, 0x30, "palera1n_flags 0x%" PRIx64, palerain_flags); + snprintf(xargs_cmd, sizeof(xargs_cmd), "xargs %s", tui_options_boot_args); + + pthread_create(&tui_jailbreak_thread_id, NULL, tui_jailbreak_thread, NULL); +} + +void tui_screen_jailbreak_redraw(void) { + PRINTATT(3, 3, "Installing jailbreak, this will take a moment. If the device asks for a"); + PRINTATT(3, 4, "passcode please enter it. Do not disconnect the device until finished."); + + if (tui_jailbreak_status) { + SETCOLOR(FG_YELLOW, BG_BLACK); + PRINTATT(3, 6, tui_jailbreak_status); + SETCOLOR(FG_WHITE, BG_BLACK); + } + + tui_draw_rectangle(5, 9, 80 - 6, 9 + 2); + MOVETOT(6 + 1, 10 + 1); + SETCOLOR(FG_BLACK, BG_WHITE); + for (int i = 0; i < ((80 - 12) * ((float)tui_jailbreak_stage / 9)); i++) { + putchar(' '); + } + SETCOLOR(FG_WHITE, BG_BLACK); + + tui_screen_jailbreak_nav(); +} + +int tui_jailbreak_nav_mouse_select = -1; + +tui_screen_t tui_screen_jailbreak(void) { + redraw_screen(); + + while(1) { + int event = tui_get_event(); + switch (event) { + case TUI_EVENT_INPUT: { + int input = tui_last_input; + if (input == TUI_INPUT_NONE) continue; + + switch (input) { + case TUI_INPUT_SELECT: + if (!tui_is_jailbreaking) { + tui_is_restarting = true; + tui_terminate(0); + } + break; + case TUI_INPUT_MOUSE_DOWN: + if (tui_mouse_y == tui_y_offset + 24 - 2 && + tui_mouse_x >= tui_x_offset + 80 - 12 && + tui_mouse_x <= tui_x_offset + 80 - 12 + 10) { + tui_jailbreak_nav_mouse_select = 0; + redraw_screen(); + } + break; + case TUI_INPUT_MOUSE_UP: + if (tui_jailbreak_nav_mouse_select == 0) { + tui_jailbreak_nav_mouse_select = -1; + if (!tui_is_jailbreaking) { + tui_is_restarting = true; + tui_terminate(0); + } + } + break; + } + break; + } + case TUI_EVENT_JAILBREAK_STATUS_CHANGED: + redraw_screen(); + break; + } + } + + return EXIT_SCREEN; +} #else /* ISO C forbids an empty translation unit */ diff --git a/src/tui_screen_main.c b/src/tui_screen_main.c index c74f9ad..962d9c6 100644 --- a/src/tui_screen_main.c +++ b/src/tui_screen_main.c @@ -13,38 +13,355 @@ #include #include -tui_screen_t tui_screen_main(void) { - int ret = MAIN_SCREEN; - bool can_start = false; - newtCenteredWindow(WIDTH, HEIGHT, NULL); - newtComponent optionsButton = newtCompactButton(46, 18, "Options"); - newtComponent startButton = newtCompactButton(57, 18, "Start"); - newtComponent exitButton = newtCompactButton(66, 18, "Exit"); - newtComponent welcome = newtLabel(1, 0, "Welcome to palera1n!"); - newtComponent deviceMsg = newtTextbox(1, 2, 40, 3, NEWT_FLAG_WRAP); - set_tui_log(deviceMsg); - LOG(LOG_INFO, "Connect your iPhone, iPad or iPod Touch to begin."); - newtTextboxSetColors(deviceMsg, PI_LOG_COLOR, PI_LOG_COLOR); - set_tui_log(deviceMsg); - newtComponent form = newtForm(NULL, NULL, 0); - newtFormAddComponents(form, optionsButton, startButton, exitButton, welcome, - deviceMsg, NULL); - newtRunForm(form); - newtRefresh(); - newtComponent buttonPressed = newtFormGetCurrent(form); - if (buttonPressed == optionsButton) { - ret = OPTIONS_SCREEN; - } else if (buttonPressed == startButton) { - if (can_start) - ret = ENTER_RECOVERY_SCREEN; - else - ret = MAIN_SCREEN; - } else if (buttonPressed == exitButton) { - ret = EXIT_SCREEN; +bool showing_ecid = false; + +char palera1n_logo[17][16] = { +" ++ ", +" #@@# ", +" +@@@@+ ", +" :@@@@@@: ", +" #@@@@@@# ", +" +@@@@@@@@+ ", +" :#*@@@@@@*#: ", +" %###@@@@###% ", +" .####%@@%####. ", +" @############@ ", +"=@@*########*@@=", +"+@@@@%####%@@@@+", +":@@@@%%**%%@@@@:", +" +@@%%*@@*%%@@+ ", +" ++%@@@@%++ ", +" :++: " +}; + +char random_quotes[][150] = { + "panic(cpu 1 caller 0xfffffff0232bd958): SEP Panic", + "Now with Apple TV support!", + "checkra1n will open source in 2020", + "Try running palera1n on a Intel 80486!", + "\"iOS 15 with SSV is unhackable\", but here we are.", + "initproc exited -- exit reason namespace 1 subcode0x7 description: none", + "totally not checkra1n", + "Because the command line wasn't easy enough", + "Checkra1n wrapper?", + "" +}; + +#define PALERA1N_URL "https://palera.in" + +int tui_main_nav_selection = 1; +bool quick_mode_enabled = false; +bool tui_can_start = false; +int random_quote; + +bool easter_egg = false; + +void tui_screen_main_nav(void) { + MOVETOT(80 - 52, 23); + printf("[%c] %sQuick Mode " COLOR(FG_WHITE, BG_BLACK) " %s[ Options ]" COLOR(FG_WHITE, BG_BLACK) " %s[ Start ]" COLOR(FG_WHITE, BG_BLACK) " %s[ Quit ]" COLOR(FG_WHITE, BG_BLACK), quick_mode_enabled ? 'x' : ' ', + tui_main_nav_selection == 0 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 49 && tui_mouse_x <= tui_x_offset + 80 - 49 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), + tui_main_nav_selection == 1 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 37 && tui_mouse_x <= tui_x_offset + 80 - 37 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), + tui_main_nav_selection == 2 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : !tui_can_start ? (supports_bright_colors ? COLOR(FG_BRIGHT_BLACK, BG_BLACK) : COLOR(FG_BLUE, BG_BLACK)) : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 25 && tui_mouse_x <= tui_x_offset + 80 - 25 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), + tui_main_nav_selection == 3 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 13 && tui_mouse_x <= tui_x_offset + 80 - 13 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ) + ); +} + +void tui_screen_main_redraw(void) { + PRINTATT(3, 2, "Welcome to palera1n!"); + + SETCOLOR(FG_WHITE, BG_BLACK); + PRINTATT(3, 9, "Made by: Nick Chan, Ploosh, Samara, Mineek"); + PRINTATT(3, 10, "staturnz, kok3shidoll, "); + if ((tui_mouse_y == tui_y_offset + 9 && tui_mouse_x >= tui_x_offset + 25 && tui_mouse_x <= tui_x_offset + 25 + 8) || easter_egg) { + SETCOLORA(FG_BRIGHT_WHITE, BG_BLACK, BOLD); } - set_tui_log(NULL); - newtFormDestroy(form); - return ret; + printf("HAHALOSAH"); + RESETFONT; + SETCOLOR(FG_WHITE, BG_BLACK); + PRINTATT(3, 12, "Thanks to: llsc12, nebula,"); + PRINTATT(3, 13, "nikias (libimobiledevice), checkra1n"); + PRINTATT(3, 14, "(Siguza, axi0mx, littlelailo et al.), Procursus"); + PRINTATT(3, 15, "Team (Hayden Seay, Cameron Katri, Keto et.al),"); + PRINTATT(80 - (int)sizeof(PALERA1N_URL), 21, PALERA1N_URL); + PRINTATT(80 - (int)sizeof("@palera1n"), 20, "@palera1n"); + PRINTATT(3, 20, "With <3 from HAHALOSAH"); + PRINTATT(3, 21, "Note: Backup your stuff. Use at your own risk."); + DRAWLINET(2, 22, 78); + DRAWLINET(2, 3, 50); + + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + DRAWLINET(2, 11, 50); + DRAWLINET(2, 16, 50); + + for (int y = 0; y < 16; y++) { + PRINTATLENT(80 - 22, y + 4, palera1n_logo[y], 16); + } + + SETCOLOR(FG_YELLOW, BG_BLACK); + if (tui_connected_devices == NULL) { + PRINTATT(3, 5, "Connect your iPhone, iPad, iPod Touch, or Apple"); + PRINTATT(3, 6, "TV to begin."); + tui_can_start = false; + } else if (tui_connected_devices->next != NULL) { + PRINTATT(3, 5, "Please attach only one device."); + tui_can_start = false; + } else { + if (strlen(tui_connected_devices->display_name) == 0) { + PRINTATT(3, 5, "ERROR: Failed to open device in recovery/DFU mode"); + PRINTATT(3, 6, "Please reopen palera1n and try again."); + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_NORMAL) { + MOVETOT(3, 5); + int ecid_y; + if (!tui_connected_devices->arm64) { + printf("Sorry, %s (iOS %s) is not supported.", tui_connected_devices->display_name, tui_connected_devices->version); + ecid_y = 6; + tui_can_start = false; + } else if (tui_compare_versions(tui_connected_devices->version, "15.0") < 0 || tui_compare_versions(tui_connected_devices->version, "17.3.1") > 0) { + printf("Sorry, %s is supported, but iOS", tui_connected_devices->display_name); + MOVETOT(3, 6); + printf("%s is not.", tui_connected_devices->version); + PRINTATT(3, 7, "Supported versions are 15.0 - 17.3.1."); + ecid_y = 8; + tui_can_start = false; + } else { + printf("%s (%s) connected in Normal mode.", tui_connected_devices->display_name, tui_connected_devices->version); + ecid_y = 6; + tui_can_start = true; + } + if (showing_ecid) { + MOVETOT(3, ecid_y); + printf("ECID: 0x%" PRIx64 " ", tui_connected_devices->ecid); + } else { + PRINTATT(3, ecid_y, "Press (E) to show ECID."); + } + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_RECOVERY) { + MOVETOT(3, 5); + printf("%s connected in Recovery mode.", tui_connected_devices->display_name); + if (showing_ecid) { + MOVETOT(3, 6); + printf("ECID: 0x%" PRIx64 " ", tui_connected_devices->ecid); + } else { + PRINTATT(3, 6, "Press (E) to show ECID."); + } + PRINTATT(3, 7, "NOTE: Ensure installed iOS is in range 15.0 - 17.3.1!"); + tui_can_start = true; + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_DFU) { + MOVETOT(3, 5); + printf("%s connected in DFU mode.", tui_connected_devices->display_name); + if (showing_ecid) { + MOVETOT(3, 6); + printf("ECID: 0x%" PRIx64 " ", tui_connected_devices->ecid); + } else { + PRINTATT(3, 6, "Press (E) to show ECID."); + } +#ifdef DEV_BUILD + tui_can_start = true; +#else + PRINTATT(3, 7, "Please connect device in Normal/Recovery mode"); + PRINTATT(3, 8, "or run palera1n in CLI mode"); + tui_can_start = false; +#endif + } + } + + if (!tui_can_start && tui_main_nav_selection == 2) { + tui_main_nav_selection = 1; + } + + SETCOLOR(FG_WHITE, BG_BLACK); + + for (int y = 0; y < 3; y++) { + PRINTATLEN(tui_x_offset + 3, tui_y_offset + 17 + y, random_quotes[random_quote] + y * 50, 50); + } + + tui_screen_main_nav(); + fflush(stdout); +} + +int tui_main_nav_mouse_select = -1; + +tui_screen_t tui_screen_main(void) { + random_quote = ((unsigned int)((rand()+rand())/2)) % 8; + redraw_screen(); + + while(1) { + int event = tui_get_event(); + switch (event) { + case TUI_EVENT_CONNECTED_DEVICES_CHANGED: + redraw_screen(); + break; + case TUI_EVENT_INPUT: { + int input = tui_last_input; + + switch (input) { + case TUI_INPUT_NONE: + if (tui_last_key == 'E' || tui_last_key == 'e') { + showing_ecid = !showing_ecid; + tui_screen_main_redraw(); + } + break; + case TUI_INPUT_LEFT: + case TUI_INPUT_TAB_BACK: + if (--tui_main_nav_selection == -1) tui_main_nav_selection = 3; + if (tui_main_nav_selection == 2 && !tui_can_start) tui_main_nav_selection = 1; + tui_screen_main_nav(); + fflush(stdout); + break; + case TUI_INPUT_RIGHT: + case TUI_INPUT_TAB: + if (++tui_main_nav_selection == 4) tui_main_nav_selection = 0; + if (tui_main_nav_selection == 2 && !tui_can_start) tui_main_nav_selection = 3; + tui_screen_main_nav(); + fflush(stdout); + break; + case TUI_INPUT_SELECT: + switch(tui_main_nav_selection) { + case 0: + quick_mode_enabled = !quick_mode_enabled; + tui_screen_main_nav(); + fflush(stdout); + break; + case 1: + return OPTIONS_SCREEN; + case 2: + if (tui_can_start) { + if (tui_connected_devices->mode == TUI_DEVICE_MODE_NORMAL) { + return ENTER_RECOVERY_SCREEN; + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_RECOVERY) { + return ENTER_DFU_SCREEN; + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_DFU) { + tui_jailbreak(); + return JAILBREAK_SCREEN; + } + } + break; + case 3: + return EXIT_SCREEN; + } + break; + case TUI_INPUT_MOUSE_MOVE: + tui_screen_main_redraw(); + break; + case TUI_INPUT_MOUSE_DOWN: + if ((tui_mouse_y == tui_y_offset + 9 && tui_mouse_x >= tui_x_offset + 25 && tui_mouse_x <= tui_x_offset + 25 + 8)) { + easter_egg = true; + break; + } + if (tui_mouse_y == tui_y_offset + 22) { + if (tui_mouse_x >= tui_x_offset + 80 - 49 && tui_mouse_x <= tui_x_offset + 80 - 49 + 10) { + tui_main_nav_selection = 0; + tui_main_nav_mouse_select = 0; + } else if (tui_mouse_x >= tui_x_offset + 80 - 37 && tui_mouse_x <= tui_x_offset + 80 - 37 + 10) { + tui_main_nav_selection = 1; + tui_main_nav_mouse_select = 1; + } else if (tui_mouse_x >= tui_x_offset + 80 - 25 && tui_mouse_x <= tui_x_offset + 80 - 25 + 10) { + if (tui_can_start) { + tui_main_nav_selection = 2; + tui_main_nav_mouse_select = 2; + } + } else if (tui_mouse_x >= tui_x_offset + 80 - 13 && tui_mouse_x <= tui_x_offset + 80 - 13 + 10) { + tui_main_nav_selection = 3; + tui_main_nav_mouse_select = 3; + } + tui_screen_main_nav(); + fflush(stdout); + } + break; + case TUI_INPUT_MOUSE_UP: + if (tui_mouse_y == tui_y_offset + 22) { + if (tui_mouse_x >= tui_x_offset + 80 - 49 && tui_mouse_x <= tui_x_offset + 80 - 49 + 10 && tui_main_nav_mouse_select == 0) { + quick_mode_enabled = !quick_mode_enabled; + redraw_screen(); + } else if (tui_mouse_x >= tui_x_offset + 80 - 37 && tui_mouse_x <= tui_x_offset + 80 - 37 + 10 && tui_main_nav_mouse_select == 1) { + return OPTIONS_SCREEN; + } else if (tui_mouse_x >= tui_x_offset + 80 - 25 && tui_mouse_x <= tui_x_offset + 80 - 25 + 10 && tui_main_nav_mouse_select == 2) { + if (tui_can_start) { + if (tui_connected_devices->mode == TUI_DEVICE_MODE_NORMAL) { + return ENTER_RECOVERY_SCREEN; + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_RECOVERY) { + return ENTER_DFU_SCREEN; + } else if (tui_connected_devices->mode == TUI_DEVICE_MODE_DFU) { + tui_jailbreak(); + return JAILBREAK_SCREEN; + } + } + } else if (tui_mouse_x >= tui_x_offset + 80 - 13 && tui_mouse_x <= tui_x_offset + 80 - 13 + 10 && tui_main_nav_mouse_select == 3) { + return EXIT_SCREEN; + } + } + tui_main_nav_mouse_select = -1; + break; + } + break; + } + } + + } + + return MAIN_SCREEN; +} + +int tui_version_extract_component(const char *version, int index) { + int component = 0; + int componentIndex = 0; + for (int i = 0; version[i] != '\0'; i++) { + if (version[i] == '.') { + componentIndex++; + if (componentIndex > index) { + break; + } + continue; + } + if (componentIndex == index) { + component *= 10; + component += version[i] - '0'; + } + } + return component; +} + +int tui_compare_versions(const char *firstVersion, const char *secondVersion) { + if (strcmp(firstVersion, secondVersion) == 0) { + return 0; + } + + int firstVersionMajor = tui_version_extract_component(firstVersion, 0); + int firstVersionMinor = tui_version_extract_component(firstVersion, 1); + int firstVersionPatch = tui_version_extract_component(firstVersion, 2); + + int secondVersionMajor = tui_version_extract_component(secondVersion, 0); + int secondVersionMinor = tui_version_extract_component(secondVersion, 1); + int secondVersionPatch = tui_version_extract_component(secondVersion, 2); + + if (firstVersionMajor != secondVersionMajor) { + return firstVersionMajor - secondVersionMajor; + } + + if (firstVersionMinor != secondVersionMinor) { + return firstVersionMinor - secondVersionMinor; + } + + return firstVersionPatch - secondVersionPatch; } #else diff --git a/src/tui_screen_options.c b/src/tui_screen_options.c index e5f17d2..2a7f151 100644 --- a/src/tui_screen_options.c +++ b/src/tui_screen_options.c @@ -13,66 +13,331 @@ #include #include -void bitfield_check_cb(newtComponent box, void* data) { - if (newtCheckboxGetValue(box) == ' ') { - *((tui_bit_info_t*)data)->flags_p = *((tui_bit_info_t*)data)->flags_p &~ ((tui_bit_info_t*)data)->opt; - } else if (newtCheckboxGetValue(box) == '*') { - *((tui_bit_info_t*)data)->flags_p |= ((tui_bit_info_t*)data)->opt; - } else assert(0); +int tui_options_nav_selection = 0; +int tui_options_nav_mouse_select = 0; + +bool tui_options_allow_untested = false; +bool tui_options_safe_mode = false; +bool tui_options_verbose_boot = false; +bool tui_options_force_revert = false; +bool tui_options_flower_chain = true; + +bool tui_options_is_editing_boot_args = false; + +char tui_options_boot_args[0x1e0 + 1] = {0}; + +int tui_options_boot_args_cursor = 0; +int tui_options_boot_args_offset = 0; + +void tui_screen_options_nav(void) { + SETCOLOR(FG_WHITE, BG_BLACK); + MOVETOT(80 - 11, 23); + printf("%s[ Back ]" COLOR(FG_WHITE, BG_BLACK), + tui_options_nav_selection == 0 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 80 - 12 && tui_mouse_x <= tui_x_offset + 80 - 12 + 10 + ) && (tui_mouse_y == tui_y_offset + 22) ? COLOR(FG_BLACK, BG_WHITE) : "" + ) + ); +#ifdef DEV_BUILD + PRINTATT(3, 23, "DEV_BUILD"); +#endif } +extern bool easter_egg; + +void tui_screen_options_options(void) { + SETCOLOR(FG_WHITE, BG_BLACK); + MOVETOT(3, 8); + printf("[%c] %sAllow untested iOS/iPadOS versions" COLOR(FG_WHITE, BG_BLACK), + tui_options_allow_untested ? 'x' : ' ', + tui_options_nav_selection == 1 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 6 && tui_mouse_x <= tui_x_offset + 6 + 34 + ) && (tui_mouse_y == tui_y_offset + 7) ? COLOR(FG_BLACK, BG_WHITE) : "" + )); + MOVETOT(3, 9); + printf("[%c] %sSafe Mode " COLOR(FG_WHITE, BG_BLACK), + tui_options_safe_mode ? 'x' : ' ', + tui_options_nav_selection == 2 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 6 && tui_mouse_x <= tui_x_offset + 6 + 34 + ) && (tui_mouse_y == tui_y_offset + 8) ? COLOR(FG_BLACK, BG_WHITE) : "" + )); + MOVETOT(3, 10); + printf("[%c] %sVerbose Boot " COLOR(FG_WHITE, BG_BLACK), + tui_options_verbose_boot ? 'x' : ' ', + tui_options_nav_selection == 3 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 6 && tui_mouse_x <= tui_x_offset + 6 + 34 + ) && (tui_mouse_y == tui_y_offset + 9) ? COLOR(FG_BLACK, BG_WHITE) : "" + )); + MOVETOT(3, 11); + printf("[%c] %sForce Revert " COLOR(FG_WHITE, BG_BLACK), + tui_options_force_revert ? 'x' : ' ', + tui_options_nav_selection == 4 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 6 && tui_mouse_x <= tui_x_offset + 6 + 34 + ) && (tui_mouse_y == tui_y_offset + 10) ? COLOR(FG_BLACK, BG_WHITE) : "" + )); + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + DRAWLINET(3, 13, 76); + SETCOLOR(FG_WHITE, BG_BLACK); + MOVETOT(7, 15); + printf("%sBoot Arguments: " COLOR(FG_WHITE, BG_BLACK), + tui_options_nav_selection == 5 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 6 && tui_mouse_x <= tui_x_offset + 6 + 34 + ) && ( + tui_mouse_y == tui_y_offset + 14 || tui_mouse_y == tui_y_offset + 15 + ) ? COLOR(FG_BLACK, BG_WHITE) : "" + )); + const char* boot_args_hint = tui_options_is_editing_boot_args ? "(press ENTER when done)" : " (press ENTER to edit)"; + MOVETOT((int)(80 - 5 - strlen(boot_args_hint)), 15); + printf("%s", boot_args_hint); + MOVETOT(3, 17); + printf("[%c] %s%s " COLOR(FG_WHITE, BG_BLACK), + tui_options_flower_chain ? 'x' : ' ', + tui_options_nav_selection == 6 ? COLOR(FG_BLACK, BG_BRIGHT_WHITE) : ( + ( + tui_mouse_x >= tui_x_offset + 6 && tui_mouse_x <= tui_x_offset + 6 + 34 + ) && (tui_mouse_y == tui_y_offset + 16) ? COLOR(FG_BLACK, BG_WHITE) : "" + ), easter_egg ? "Neko Chain " : "Flower Chain"); + + MOVETOT(7, 16); + if (supports_bright_colors) { + SETCOLOR(tui_options_is_editing_boot_args ? FG_YELLOW : FG_WHITE, BG_BRIGHT_BLACK); + } else { + SETCOLOR(tui_options_is_editing_boot_args ? FG_YELLOW : FG_WHITE, BG_BLUE); + } + int boot_args_len = strlen(tui_options_boot_args); + + if ((tui_options_boot_args_cursor - tui_options_boot_args_offset) > (68 - 1)) { + tui_options_boot_args_offset += (tui_options_boot_args_cursor - tui_options_boot_args_offset) - (68 - 1); + } + if ((tui_options_boot_args_cursor - tui_options_boot_args_offset) < 0) { + tui_options_boot_args_offset = tui_options_boot_args_cursor; + } + if ((tui_options_boot_args_offset + 68 - 1) > boot_args_len && boot_args_len >= 68 - 1) { + tui_options_boot_args_offset = boot_args_len - 68 + 1; + } + + for (int i = 0; i < 68; i++) { + putchar(((i + tui_options_boot_args_offset) < boot_args_len) ? tui_options_boot_args[i + tui_options_boot_args_offset] : ' '); + } + + if (tui_options_is_editing_boot_args) { + MOVETOT((int)(7 + tui_options_boot_args_cursor - tui_options_boot_args_offset), 16); + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_YELLOW); + } else { + SETCOLOR(FG_BLUE, BG_YELLOW); + } + putchar(tui_options_boot_args_cursor < boot_args_len ? tui_options_boot_args[tui_options_boot_args_cursor] : ' '); + } + + SETCOLOR(FG_WHITE, BG_BLACK); + MOVETOT(5, 16); + printf(tui_options_boot_args_offset > 0 ? "<<" : " "); + MOVETOT(75, 16); + printf((strlen(tui_options_boot_args) - tui_options_boot_args_offset) > 68 ? ">>" : " "); +} + +void tui_screen_options_redraw(void) { + SETCOLOR(FG_WHITE, BG_BLACK); + PRINTATT(3, 3, "You may set the following options. If you don't know what they mean you'll"); + PRINTATT(3, 4, "probably have no reason to set them."); + if (supports_bright_colors) { + SETCOLOR(FG_BRIGHT_BLACK, BG_BLACK); + } else { + SETCOLOR(FG_BLUE, BG_BLACK); + } + DRAWLINET(3, 6, 76); + tui_screen_options_nav(); + tui_screen_options_options(); + fflush(stdout); +} tui_screen_t tui_screen_options(void) { - tui_bit_info_t verbose_info = { &palerain_flags, palerain_option_verbose_boot }; - tui_bit_info_t rootful_info = { &palerain_flags, palerain_option_rootful }; - tui_bit_info_t setup_rootful_info = { &palerain_flags, palerain_option_setup_rootful }; - tui_bit_info_t force_revert_info = { &palerain_flags, palerain_option_force_revert }; - tui_bit_info_t safemode_info = { &palerain_flags, palerain_option_safemode }; - tui_bit_info_t flower_chain_info = { &palerain_flags, palerain_option_flower_chain }; + redraw_screen(); - const char* bootargs_entered = NULL; - int ret = MAIN_SCREEN; + while(1) { + int event = tui_get_event(); + if (event != TUI_EVENT_INPUT) continue; + int input = tui_last_input; - newtCenteredWindow(WIDTH, HEIGHT, NULL); - newtComponent backButton = newtCompactButton(66, 18, "Back"); + switch (input) { + case TUI_INPUT_DOWN: + case TUI_INPUT_TAB: + if (tui_options_is_editing_boot_args) break; + if (++tui_options_nav_selection > 6) tui_options_nav_selection = 0; + tui_screen_options_nav(); + tui_screen_options_options(); + fflush(stdout); + break; + case TUI_INPUT_UP: + case TUI_INPUT_TAB_BACK: + if (tui_options_is_editing_boot_args) break; + if (--tui_options_nav_selection < 0) tui_options_nav_selection = 6; + tui_screen_options_nav(); + tui_screen_options_options(); + fflush(stdout); + break; + case TUI_INPUT_SELECT: + if (tui_options_is_editing_boot_args && tui_last_key == ' ' && tui_options_boot_args[strlen(tui_options_boot_args)] == '\x00') { + int len = strlen(tui_options_boot_args); + tui_options_boot_args[len] = ' '; + tui_options_boot_args[len + 1] = '\x00'; + tui_options_boot_args_cursor++; + tui_screen_options_options(); + fflush(stdout); + break; + } + switch(tui_options_nav_selection) { + case 0: + return MAIN_SCREEN; + case 1: + tui_options_allow_untested = !tui_options_allow_untested; + break; + case 2: + tui_options_safe_mode = !tui_options_safe_mode; + break; + case 3: + tui_options_verbose_boot = !tui_options_verbose_boot; + break; + case 4: + tui_options_force_revert = !tui_options_force_revert; + break; + case 5: + tui_options_is_editing_boot_args = !tui_options_is_editing_boot_args; + tui_options_boot_args_cursor = tui_options_is_editing_boot_args ? strlen(tui_options_boot_args) : 0; + break; + case 6: + tui_options_flower_chain = !tui_options_flower_chain; + break; + } + tui_screen_options_nav(); + tui_screen_options_options(); + fflush(stdout); + break; + case TUI_INPUT_MOUSE_MOVE: + tui_screen_options_nav(); + tui_screen_options_options(); + fflush(stdout); + break; + case TUI_INPUT_MOUSE_DOWN: + if (tui_mouse_y == tui_y_offset + 24 - 2 && + tui_mouse_x >= tui_x_offset + 80 - 12 && + tui_mouse_x <= tui_x_offset + 80 - 12 + 10) { + tui_options_nav_selection = 0; + tui_options_nav_mouse_select = 0; + redraw_screen(); + } - newtComponent optionsNotice = newtTextbox(1, 0, WIDTH - 2, 3, NEWT_FLAG_WRAP); - newtTextboxSetText(optionsNotice, "You may set the following options. If you don't know what they mean you'll probably have no reason to set them."); - // newtTextboxSetColors(optionsNotice, NEWT_COLORSET_LABEL, NEWT_COLORSET_LABEL); +#define MOUSEDOWN_HANDLER(y, val) \ + if (tui_mouse_y == tui_y_offset + y && \ + tui_mouse_x >= tui_x_offset + 6 - 4 && \ + tui_mouse_x <= tui_x_offset + 6 + 34) { \ + tui_options_nav_selection = val; \ + tui_options_nav_mouse_select = val; \ + tui_screen_options_nav(); \ + tui_screen_options_options(); \ + fflush(stdout); \ + } - newtComponent verboseBootBox = newtCheckbox(1, 3, "Verbose boot", CHECKBOX_STATE(palerain_flags, palerain_option_verbose_boot), NULL, NULL); - newtComponent rootfulBox = newtCheckbox(1, 4, "Rootful", CHECKBOX_STATE(palerain_flags, palerain_option_rootful), NULL, NULL); - newtComponent rootfulSetupBox = newtCheckbox(1, 5, "Setup fakefs", CHECKBOX_STATE(palerain_flags, palerain_option_setup_rootful), NULL, NULL); - newtComponent forceRevertBox = newtCheckbox(1, 6, "Restore system", CHECKBOX_STATE(palerain_flags, palerain_option_force_revert), NULL, NULL); - newtComponent safeModeBox = newtCheckbox(1, 7, "Safe mode", CHECKBOX_STATE(palerain_flags, palerain_option_safemode), NULL, NULL); + if (!tui_options_is_editing_boot_args) { + MOUSEDOWN_HANDLER(7, 1); + MOUSEDOWN_HANDLER(8, 2); + MOUSEDOWN_HANDLER(9, 3); + MOUSEDOWN_HANDLER(10, 4); + MOUSEDOWN_HANDLER(16, 6); + } + + MOUSEDOWN_HANDLER(14, 5); + MOUSEDOWN_HANDLER(15, 5); - newtComponentAddCallback(verboseBootBox, bitfield_check_cb, &verbose_info); - newtComponentAddCallback(rootfulBox, bitfield_check_cb, &rootful_info); - newtComponentAddCallback(rootfulSetupBox, bitfield_check_cb, &setup_rootful_info); - newtComponentAddCallback(forceRevertBox, bitfield_check_cb, &force_revert_info); - newtComponentAddCallback(safeModeBox, bitfield_check_cb, &safemode_info); +#undef MOUSEDOWN_HANDLER + break; + case TUI_INPUT_MOUSE_UP: + if (tui_mouse_y == tui_y_offset + 24 - 2 && + tui_mouse_x >= tui_x_offset + 80 - 12 && + tui_mouse_x <= tui_x_offset + 80 - 12 + 10 && + tui_options_nav_mouse_select == 0) { + return MAIN_SCREEN; + } - newtComponent bootCmdlineLabel = newtLabel(1, 8, "Kernel command line:"); - newtComponent bootCmdlineEntry = newtEntry(1, 9, &xargs_cmd[6], WIDTH - 2, &bootargs_entered, NEWT_ENTRY_SCROLL); +#define MOUSEUP_HANDLER(y, val, option, e) \ + if (tui_mouse_y == tui_y_offset + y && \ + tui_mouse_x >= tui_x_offset + 6 - 4 && \ + tui_mouse_x <= tui_x_offset + 6 + 34 && \ + tui_options_nav_mouse_select == val) { \ + tui_options_##option = !tui_options_##option; \ + e \ + tui_screen_options_nav(); \ + tui_screen_options_options(); \ + fflush(stdout); \ + } - newtComponent flowerChainBox = newtCheckbox(1, 10, "Flower chain", CHECKBOX_STATE(palerain_flags, palerain_option_flower_chain), NULL, NULL); - newtComponentAddCallback(flowerChainBox, bitfield_check_cb, &flower_chain_info); + if (!tui_options_is_editing_boot_args) { + MOUSEUP_HANDLER(7, 1, allow_untested, ); + MOUSEUP_HANDLER(8, 2, safe_mode, ); + MOUSEUP_HANDLER(9, 3, verbose_boot, ); + MOUSEUP_HANDLER(10, 4, force_revert, ); + MOUSEUP_HANDLER(16, 6, flower_chain, ); + } + #define BOOTARGS_HANDLER \ + tui_options_boot_args_cursor = tui_options_is_editing_boot_args ? strlen(tui_options_boot_args) : 0; - newtComponent form = newtForm(NULL, NULL, 0); - newtFormAddComponents(form, backButton, verboseBootBox, rootfulBox, - rootfulSetupBox, forceRevertBox, safeModeBox, bootCmdlineLabel, - bootCmdlineEntry, flowerChainBox, optionsNotice, - NULL); - newtRunForm(form); - newtRefresh(); - snprintf(xargs_cmd, 0x270, "xargs %s", bootargs_entered); - newtComponent buttonPressed = newtFormGetCurrent(form); - if (buttonPressed == backButton) { - ret = MAIN_SCREEN; - } else ret = MAIN_SCREEN; - newtFormDestroy(form); - return ret; + MOUSEUP_HANDLER(14, 5, is_editing_boot_args, BOOTARGS_HANDLER); + MOUSEUP_HANDLER(15, 5, is_editing_boot_args, BOOTARGS_HANDLER); +#undef MOUSEUP_HANDLER + tui_options_nav_mouse_select = -1; + break; + case TUI_INPUT_BACKSPACE: + if (tui_options_is_editing_boot_args && tui_options_boot_args_cursor > 0) { + memmove(tui_options_boot_args + tui_options_boot_args_cursor - 1, tui_options_boot_args + tui_options_boot_args_cursor, strlen(tui_options_boot_args) - tui_options_boot_args_cursor); + tui_options_boot_args[strlen(tui_options_boot_args) - 1] = '\x00'; + tui_options_boot_args_cursor--; + tui_screen_options_options(); + fflush(stdout); + } + break; + case TUI_INPUT_NONE: + if (tui_options_is_editing_boot_args && tui_options_boot_args[strlen(tui_options_boot_args)] == '\x00') { + int len = strlen(tui_options_boot_args); + memmove(tui_options_boot_args + tui_options_boot_args_cursor + 1, tui_options_boot_args + tui_options_boot_args_cursor, strlen(tui_options_boot_args) - tui_options_boot_args_cursor); + tui_options_boot_args[tui_options_boot_args_cursor] = tui_last_key; + tui_options_boot_args[len + 1] = '\x00'; + tui_options_boot_args_cursor++; + tui_screen_options_options(); + fflush(stdout); + } + break; + case TUI_INPUT_LEFT: + if (tui_options_is_editing_boot_args) { + if (tui_options_boot_args_cursor > 0) { + tui_options_boot_args_cursor--; + tui_screen_options_options(); + fflush(stdout); + } + } + break; + case TUI_INPUT_RIGHT: + if (tui_options_is_editing_boot_args) { + if (tui_options_boot_args_cursor < (int)strlen(tui_options_boot_args)) { + tui_options_boot_args_cursor++; + tui_screen_options_options(); + fflush(stdout); + } + } + break; + } + } } #else