diff --git a/client/Makefile b/client/Makefile index 87cf03a19..e46e51eb2 100644 --- a/client/Makefile +++ b/client/Makefile @@ -253,7 +253,7 @@ CMDSRCS = crapto1/crapto1.c \ wiegand_formats.c \ wiegand_formatutils.c \ cardhelper.c \ - settings.c + preferences.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) diff --git a/client/cliparser/cliparser.c b/client/cliparser/cliparser.c index 02746c0f4..4e0fb4d9c 100644 --- a/client/cliparser/cliparser.c +++ b/client/cliparser/cliparser.c @@ -38,6 +38,7 @@ int CLIParserParseArg(int argc, char **argv, void *vargtable[], size_t vargtable if (arg_nullcheck(argtable) != 0) { /* NULL entries were detected, some allocations must have failed */ printf("ERROR: Insufficient memory\n"); + fflush(stdout); return 2; } /* Parse the command line as defined by argtable[] */ @@ -54,6 +55,7 @@ int CLIParserParseArg(int argc, char **argv, void *vargtable[], size_t vargtable if (programHelp) printf("%s \n", programHelp); + fflush(stdout); return 1; } @@ -62,7 +64,7 @@ int CLIParserParseArg(int argc, char **argv, void *vargtable[], size_t vargtable /* Display the error details contained in the arg_end struct.*/ arg_print_errors(stdout, ((struct arg_end *)argtable[vargtableLen - 1]), programName); printf("Try '%s --help' for more information.\n", programName); - + fflush(stdout); return 3; } @@ -155,18 +157,24 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int int ibuf = 0; uint8_t tmp_buf[256] = {0}; int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX - if (res || !ibuf) + if (res || !ibuf){ + printf("Parameter error: buffer overflow.\n"); + fflush(stdout); return res; - + } + switch (param_gethex_to_eol((char *)tmp_buf, 0, data, maxdatalen, datalen)) { case 1: printf("Parameter error: Invalid HEX value.\n"); + fflush(stdout); return 1; case 2: printf("Parameter error: parameter too large.\n"); + fflush(stdout); return 2; case 3: printf("Parameter error: Hex string must have even number of digits.\n"); + fflush(stdout); return 3; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index c3042d874..8d82ed32c 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -2096,9 +2096,9 @@ static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, u xor_div_key[i] = old_div_key[i] ^ new_div_key[i]; } if (verbose) { - PrintAndLogEx(SUCCESS, "Old div key : %s\n", sprint_hex(old_div_key, 8)); - PrintAndLogEx(SUCCESS, "New div key : %s\n", sprint_hex(new_div_key, 8)); - PrintAndLogEx(SUCCESS, "Xor div key : %s\n", sprint_hex(xor_div_key, 8)); + PrintAndLogEx(SUCCESS, "Old div key : %s", sprint_hex(old_div_key, 8)); + PrintAndLogEx(SUCCESS, "New div key : %s", sprint_hex(new_div_key, 8)); + PrintAndLogEx(SUCCESS, "Xor div key : " _YELLOW_("%s") "\n", sprint_hex(xor_div_key, 8)); } } @@ -2111,7 +2111,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { uint8_t dataLen = 0; char tempStr[50] = {0}; bool givenCSN = false; - bool oldElite = false; + bool old_elite = false; bool elite = false; bool errors = false; uint8_t cmdp = 0; @@ -2122,7 +2122,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { case 'e': dataLen = param_getstr(Cmd, cmdp, tempStr, sizeof(tempStr)); if (dataLen == 2) - oldElite = true; + old_elite = true; elite = true; cmdp++; break; @@ -2184,7 +2184,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { } } - HFiClassCalcNewKey(CSN, OLDKEY, NEWKEY, xor_div_key, elite, oldElite, true); + HFiClassCalcNewKey(CSN, OLDKEY, NEWKEY, xor_div_key, elite, old_elite, true); return PM3_SUCCESS; } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index e43461591..8d2614ea7 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -3564,7 +3564,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto snprintf(strB, sizeof(strB), "%012" PRIx64, e_sector[i].Key[1]); if (e_sector[i].foundKey[0] > 1) { - PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")"| " _GREEN_("%s")" | " _YELLOW_("%c")"| " _GREEN_("%s")" | " _YELLOW_("%c")"|" + PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")"| " _GREEN_("%s")" | " _YELLOW_("%c")"| " _GREEN_("%s")" | " _YELLOW_("%c")"|" , i , strA, e_sector[i].foundKey[0] , strB, e_sector[i].foundKey[1] diff --git a/client/cmdmain.c b/client/cmdmain.c index 8d4b1c8b7..906a354f6 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -37,6 +37,7 @@ #include "ui.h" #include "util_posix.h" #include "commonutil.h" // ARRAYLEN +#include "preferences.h" static int CmdHelp(const char *Cmd); @@ -241,6 +242,11 @@ static int CmdRev(const char *Cmd) { return PM3_SUCCESS; } +static int CmdPref(const char *Cmd) { + CmdPreferences(Cmd); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help. Use ' help' for details of a particular command."}, {"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"}, @@ -259,6 +265,7 @@ static command_t CommandTable[] = { {"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"}, {"", CmdHelp, AlwaysAvailable, ""}, {"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"}, + {"pref", CmdPref, AlwaysAvailable, "Edit preferences"}, {"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"}, {"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"}, {"quit", CmdQuit, AlwaysAvailable, ""}, diff --git a/client/fileutils.c b/client/fileutils.c index 05a7e8949..1eb82e57c 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -38,7 +38,7 @@ // this define is needed for scandir/alphasort to work #define _GNU_SOURCE #include "fileutils.h" -#include "settings.h" +#include "preferences.h" #include #include @@ -427,7 +427,7 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s } break; case jsfSettings: - settings_save_callback (root); + preferences_save_callback (root); break; default: break; @@ -868,7 +868,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ *datalen = sptr; } if (!strcmp(ctype,"settings")) { - settings_load_callback (root); + preferences_load_callback (root); } PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), fileName); out: diff --git a/client/preferences.c b/client/preferences.c new file mode 100644 index 000000000..21c38fb2e --- /dev/null +++ b/client/preferences.c @@ -0,0 +1,564 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + ****************************************************************************/ + +//----------------------------------------------------------------------------- +// Preferences Functions +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Notes +// To add a new setting +// Add the new setting to the session_arg_t; in ui.h +// Add the default value for the setting in the settings_load page below +// Update the preferences_load_callback to load your setting into the stucture +// Update the preferences_save_callback to enusre your setting gets saved when needed. +// use the preference as needed : session. +// Can use (session.preferences_loaded) to check if json settings file was used +//----------------------------------------------------------------------------- + +#include "preferences.h" +#include "comms.h" +#include "emv/emvjson.h" +#include +#include "cmdparser.h" +#include + +static int CmdHelp(const char *Cmd); + +// Load all settings into memory (struct) +int preferences_load (void) { + + // Set all defaults + session.client_debug_level = OFF; + session.window_plot_xpos = 10; + session.window_plot_ypos = 30; + session.window_plot_hsize = 400; + session.window_plot_wsize = 800; + session.window_overlay_xpos = session.window_plot_xpos; + session.window_overlay_ypos = 60+session.window_plot_ypos + session.window_plot_hsize; + session.window_overlay_hsize = 200; + session.window_overlay_wsize = session.window_plot_wsize; + session.emoji_mode = ALIAS; + session.show_hints = false; + session.supports_colors = false; + + // loadFileJson wants these, so pass in place holder values, though not used + // in settings load; + uint8_t dummyData = 0x00; + size_t dummyDL = 0x00; + + if (loadFileJSON(preferencesFilename, &dummyData, sizeof(dummyData), &dummyDL) == PM3_SUCCESS) { + session.preferences_loaded = true; + } + // Note, if session.settings_loaded == false then the settings_save + // will be called in main () to save settings as set in defaults and main() checks. + + return PM3_SUCCESS; +} + +// Save all settings from memory (struct) to file +int preferences_save (void) { + // Note sure if backup has value ? + char backupFilename[500]; + + snprintf (backupFilename,sizeof(backupFilename),"%s.bak",preferencesFilename); + + if (fileExists (backupFilename)) { + if (remove (backupFilename) != 0) { + PrintAndLogEx (FAILED, "Error - could not delete old settings backup file \"%s\"",backupFilename); + return PM3_ESOFT; + } + } + + if (fileExists (preferencesFilename)) { + if (rename (preferencesFilename,backupFilename) != 0) { + PrintAndLogEx (FAILED, "Error - could not backup settings file \"%s\" to \"%s\"",preferencesFilename,backupFilename); + return PM3_ESOFT; + } + } + + uint8_t dummyData = 0x00; + size_t dummyDL = 0x00; + + if (saveFileJSON(preferencesFilename, jsfSettings, &dummyData, dummyDL) != PM3_SUCCESS) + PrintAndLogEx (ERR, "Error saving preferences to \"%s\"",preferencesFilename); + + return PM3_SUCCESS; +} + +void preferences_save_callback (json_t *root) { + + JsonSaveStr (root,"FileType","settings"); + + // Log level, convert to text + switch (session.client_debug_level) { + case OFF: JsonSaveStr (root,"client.debug.level","off"); break; + case SIMPLE: JsonSaveStr (root,"client.debug.level","simple"); break; + case FULL: JsonSaveStr (root,"client.debug.level","full"); break; + default: + JsonSaveStr (root,"logging.level","NORMAL"); + } + + // Plot window + JsonSaveInt (root,"window.plot.xpos",session.window_plot_xpos); + JsonSaveInt (root,"window.plot.ypos",session.window_plot_ypos); + JsonSaveInt (root,"window.plot.hsize",session.window_plot_hsize); + JsonSaveInt (root,"window.plot.wsize",session.window_plot_wsize); + + // Overlay/Slider window + JsonSaveInt (root,"window.overlay.xpos",session.window_overlay_xpos); + JsonSaveInt (root,"window.overlay.ypos",session.window_overlay_ypos); + JsonSaveInt (root,"window.overlay.hsize",session.window_overlay_hsize); + JsonSaveInt (root,"window.overlay.wsize",session.window_overlay_wsize); + + // Emoji + switch (session.emoji_mode) { + case ALIAS: JsonSaveStr (root,"show.emoji","alias"); break; + case EMOJI: JsonSaveStr (root,"show.emoji","emoji"); break; + case ALTTEXT: JsonSaveStr (root,"show.emoji","alttext"); break; + case ERASE: JsonSaveStr (root,"show.emoji","erase"); break; + default: + JsonSaveStr (root,"show.emoji","ALIAS"); + } + + JsonSaveBoolean (root,"show.hints",session.show_hints); + + JsonSaveBoolean (root,"os.supports.colors",session.supports_colors); +} + +void preferences_load_callback (json_t *root) { + json_error_t up_error = {0}; + bool b1; + int i1; + const char *s1; + char tempStr [500]; // to use str_lower() since json unpack uses const char * + + // Logging Level + if (json_unpack_ex(root,&up_error, 0, "{s:s}","client.debug.level",&s1) == 0) { + strncpy (tempStr,s1,sizeof(tempStr)-1); + str_lower (tempStr); + if (strncmp (tempStr,"off",3) == 0) session.client_debug_level = OFF; + if (strncmp (tempStr,"simple",6) == 0) session.client_debug_level = SIMPLE; + if (strncmp (tempStr,"full",4) == 0) session.client_debug_level = FULL; + } + + // window plot + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.xpos",&i1) == 0) + session.window_plot_xpos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.ypos",&i1) == 0) + session.window_plot_ypos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.hsize",&i1) == 0) + session.window_plot_hsize = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.plot.wsize",&i1) == 0) + session.window_plot_wsize = i1; + + // overlay/slider plot + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.xpos",&i1) == 0) + session.window_overlay_xpos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.ypos",&i1) == 0) + session.window_overlay_ypos = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.hsize",&i1) == 0) + session.window_overlay_hsize = i1; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.overlay.wsize",&i1) == 0) + session.window_overlay_wsize = i1; + + // show options + if (json_unpack_ex(root,&up_error, 0, "{s:s}","show.emoji",&s1) == 0) { + strncpy (tempStr,s1,sizeof(tempStr)-1); + str_lower (tempStr); + if (strncmp (tempStr,"alias",5) == 0) session.emoji_mode = ALIAS; + if (strncmp (tempStr,"emoji",5) == 0) session.emoji_mode = EMOJI; + if (strncmp (tempStr,"alttext",7) == 0) session.emoji_mode = ALTTEXT; + if (strncmp (tempStr,"erase",5) == 0) session.emoji_mode = ERASE; + } + + if (json_unpack_ex(root,&up_error, 0, "{s:b}","show.hints",&b1) == 0) + session.show_hints = b1; + + if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.supports.colors",&b1) == 0) + session.supports_colors = b1; + +} + +// Help Functions +static int usage_pref_set() { + PrintAndLogEx(NORMAL, "Usage: pref set [(h)elp] [(e)moji ...] [(c)olor ...] [(hi)nts ...] [debug ...]"); + PrintAndLogEx(NORMAL, " [(p)lot ...] [(o)verlay ...]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " help - This help"); + PrintAndLogEx(NORMAL, " emoji <(ali)as | (em)oji | (alt)text | (er)ase> - Set the level of emoji support"); + PrintAndLogEx(NORMAL, " alias : show alias"); + PrintAndLogEx(NORMAL, " emoji : show emoji"); + PrintAndLogEx(NORMAL, " alttext : show alternative text"); + PrintAndLogEx(NORMAL, " erase : dont show any emoji"); + + PrintAndLogEx(NORMAL, " color <(o)ff|(a)nsi> - Color support level"); + PrintAndLogEx(NORMAL, " off : dont use color"); + PrintAndLogEx(NORMAL, " ansi : use ansi color (linux, mac, windows terminal)"); + + PrintAndLogEx(NORMAL, " hints <(of)f | on> - Show hints on/off"); + + PrintAndLogEx(NORMAL, " debug <(o)ff | (s)imple | (f)ull> - Client debug level"); + PrintAndLogEx(NORMAL, " off : no debug output"); + PrintAndLogEx(NORMAL, " simple : information level debug"); + PrintAndLogEx(NORMAL, " full : full debug information"); + + PrintAndLogEx(NORMAL, " plot [x ] [y ] [h ] [w ] - Position the plot window"); + PrintAndLogEx(NORMAL, " overlay [x ] [y ] [h ] [w ] - Position the overlay/slider window"); + + return PM3_SUCCESS; +} + +static int usage_pref_show() { + PrintAndLogEx(NORMAL, "Usage: pref show [help] [emoji|color]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " help - This help"); + PrintAndLogEx(NORMAL, " emoji - show current settings for emoji"); + PrintAndLogEx(NORMAL, " color - show current settings for color"); + + return PM3_SUCCESS; +} + +// Preference Processing Functions +typedef enum preferenceId {prefNONE,prefHELP,prefEMOJI,prefCOLOR,prefPLOT,prefOVERLAY,prefHINTS,prefCLIENTDEBUG} preferenceId_t; + +// Enumerate text to ID +preferenceId_t prefGetID (char* cmdOpt) +{ + str_lower (cmdOpt); + + if (strncmp (cmdOpt,"hi",2) == 0) return prefHINTS; + if (strncmp (cmdOpt,"h",1) == 0) return prefHELP; + if (strncmp (cmdOpt,"e",1) == 0) return prefEMOJI; + if (strncmp (cmdOpt,"c",1) == 0) return prefCOLOR; + if (strncmp (cmdOpt,"p",1) == 0) return prefPLOT; + if (strncmp (cmdOpt,"o",1) == 0) return prefOVERLAY; + if (strncmp (cmdOpt,"d",1) == 0) return prefCLIENTDEBUG; + + return NONE; +} + +void showEmojiState (void) { + switch (session.emoji_mode) { + case ALIAS: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("show alias")); + break; + case EMOJI: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("show emoji")); + break; + case ALTTEXT: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("show alt text")); + break; + case ERASE: PrintAndLogEx(NORMAL, " emoji.................. "_GREEN_("dont show emoji")); + break; + default: + PrintAndLogEx(NORMAL, " emoji.................. "_RED_("unknown")); + } +} + +void showColorState (void) { +/* + switch (session.supports_colors) { + case false: PrintAndLogEx(NORMAL, "Color : "_GREEN_("off")); + break; + case true: PrintAndLogEx(NORMAL, "Color : "_GREEN_("ansi")); + break; + default: + PrintAndLogEx(NORMAL, "Color support set to : "_RED_("unknown")); + } +*/ + // this will change to 1 of a set from bool + if (session.supports_colors) + PrintAndLogEx(NORMAL, " color.................. "_GREEN_("ansi")); + else + PrintAndLogEx(NORMAL, " color.................. "_GREEN_("off")); +} + +void showClientDebugState (void) { + switch (session.client_debug_level) { + case OFF: PrintAndLogEx (NORMAL," client debug........... "_GREEN_("off")); + break; + case SIMPLE: PrintAndLogEx (NORMAL," client debug........... "_GREEN_("simple")); + break; + case FULL: PrintAndLogEx (NORMAL," client debug........... "_GREEN_("full")); + break; + default: + PrintAndLogEx(NORMAL, " client debug........... "_RED_("unknown")); + } +} + +void showPlotPosState (void){ + PrintAndLogEx (NORMAL," Plot window............ X "_GREEN_("%4d")" Y "_GREEN_("%4d")" H "_GREEN_("%4d")" W "_GREEN_("%4d"), + session.window_plot_xpos,session.window_plot_ypos,session.window_plot_hsize,session.window_plot_wsize); +} + +void showOverlayPosState (void){ + PrintAndLogEx (NORMAL," Slider/Overlay window.. X "_GREEN_("%4d")" Y "_GREEN_("%4d")" H "_GREEN_("%4d")" W "_GREEN_("%4d"), + session.window_overlay_xpos,session.window_overlay_ypos,session.window_overlay_hsize,session.window_overlay_wsize); +} + +void showHintsState (void){ + if (session.show_hints) + PrintAndLogEx (NORMAL," Hints.................. "_GREEN_("on")); + else + PrintAndLogEx (NORMAL," Hints.................. "_GREEN_("off")); +} + +static int CmdPrefShow (const char *Cmd) { + uint8_t cmdp = 0; + preferenceId_t CmdPref; + bool errors = false; + char strOpt[50]; + + PrintAndLogEx(NORMAL,""); + PrintAndLogEx(NORMAL,_BLUE_("Preferences")); + + if (!session. preferences_loaded) { + PrintAndLogEx (ERR,"Preferneces not loaded"); + return PM3_ESOFT; + } + + if (param_getchar(Cmd, cmdp) == 0x00) { // No options - Show all + showEmojiState (); + showColorState (); + showPlotPosState (); + showOverlayPosState (); + showClientDebugState(); + showHintsState (); + } + else { + + while ((param_getchar(Cmd, cmdp) != 0x00) && !errors) { + + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + CmdPref = prefGetID(strOpt); + } + else + CmdPref = prefNONE; + + switch (CmdPref) { + case prefHELP: + return usage_pref_show(); + case prefEMOJI: + showEmojiState (); + break; + case prefCOLOR: // color + showColorState (); + break; + case prefPLOT: + showPlotPosState (); + break; + case prefOVERLAY: + showOverlayPosState (); + break; + case prefCLIENTDEBUG: + showClientDebugState(); + break; + case prefHINTS: + showHintsState(); + break; + case prefNONE: + PrintAndLogEx (ERR,"Invalid option supplied"); + errors = true; + break; + // errors + } + cmdp ++; + } + } + PrintAndLogEx(NORMAL,""); + return PM3_SUCCESS; +} + +static int CmdPrefSet (const char *Cmd) +{ + uint8_t cmdp = 0; + preferenceId_t CmdPref; + bool errors = false; + // char charOpt; + char strOpt[50]; + int x,y,h,w; + + if (param_getchar(Cmd, cmdp) == 0x00) + return usage_pref_set(); + + while ((param_getchar(Cmd, cmdp) != 0x00) && !errors) { + + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + CmdPref = prefGetID(strOpt); + } + else + CmdPref = prefNONE; + + switch (CmdPref) { + case prefHELP: + return usage_pref_set(); + case prefEMOJI: + showEmojiState (); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp (strOpt,"ali",3) == 0) { session.emoji_mode = ALIAS; showEmojiState (); break; } + if (strncmp (strOpt,"em",2) == 0) { session.emoji_mode = EMOJI; showEmojiState (); break; } + if (strncmp (strOpt,"alt",3) == 0) { session.emoji_mode = ALTTEXT; showEmojiState (); break; } + if (strncmp (strOpt,"er",2) == 0) { session.emoji_mode = ERASE; showEmojiState (); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid emoji option"); + errors = true; + } + else + errors = true; + break; + case prefCOLOR: // color + showColorState (); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp(strOpt,"a",1) == 0) { session.supports_colors = true; showColorState (); break; } + if (strncmp(strOpt,"o",1) == 0) { session.supports_colors = false; showColorState (); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid color option"); + errors = true; + } + else + errors = true; + break; + case prefPLOT: + showPlotPosState (); + cmdp++; + x = y = h = w = -99999; // Some invalid value + for (int i = 0; i < 4; i++) { // upto 4 values X, Y, H, WARNING + if (param_getchar(Cmd, cmdp) != 0){ + switch (tolower(param_getchar(Cmd, cmdp++))) { + case 'x': x = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'y': y = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'h': h = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'w': w = param_get32ex(Cmd,cmdp++,-99999,10); break; + default: + errors = true; + } + } + } + if (x != -99999) session.window_plot_xpos = x; + if (y != -99999) session.window_plot_ypos = y; + if (h != -99999) session.window_plot_hsize = h; + if (w != -99999) session.window_plot_wsize = w; + // Need to work out how to change live.... + // calling data plot seems to work + + showPlotPosState (); + break; + case prefOVERLAY: + showOverlayPosState (); + cmdp++; + x = y = h = w = -99999; // Some invalid value + for (int i = 0; i < 4; i++) { // upto 4 values X, Y, H, WARNING + if (param_getchar(Cmd, cmdp) != 0){ + switch (tolower(param_getchar(Cmd, cmdp++))) { + case 'x': x = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'y': y = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'h': h = param_get32ex(Cmd,cmdp++,-99999,10); break; + case 'w': w = param_get32ex(Cmd,cmdp++,-99999,10); break; + default: + errors = true; + } + } + } + if (x != -99999) session.window_overlay_xpos = x; + if (y != -99999) session.window_overlay_ypos = y; + if (h != -99999) session.window_overlay_hsize = h; + if (w != -99999) session.window_overlay_wsize = w; + showOverlayPosState (); + // Need to work out how to change live.... + break; + case prefCLIENTDEBUG: + showClientDebugState(); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp(strOpt,"o",1) == 0) { session.client_debug_level = OFF; g_debugMode = OFF; showClientDebugState(); break; } + if (strncmp(strOpt,"s",1) == 0) { session.client_debug_level = SIMPLE; g_debugMode = SIMPLE; showClientDebugState(); break; } + if (strncmp(strOpt,"f",1) == 0) { session.client_debug_level = FULL; g_debugMode = FULL; showClientDebugState(); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid client debug option"); + errors = true; + } + else + errors = true; + break; + case prefHINTS: + showHintsState (); + cmdp++; + if (param_getstr(Cmd, cmdp, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); + if (strncmp(strOpt,"on",2) == 0) { session.show_hints = true; showHintsState (); break; } + if (strncmp(strOpt,"of",2) == 0) { session.show_hints = false; showHintsState (); break; } + // if we get this far, then an error in the mode + PrintAndLogEx(ERR,"Invalid hint option"); + errors = true; + } + else + errors = true; + break; + case prefNONE: + PrintAndLogEx (ERR,"Invalid option supplied"); + errors = true; + break; + } + cmdp ++; + } + preferences_save(); + return PM3_SUCCESS; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"set", CmdPrefSet, AlwaysAvailable, "Set a preference"}, + {"show", CmdPrefShow, AlwaysAvailable, "Show (a preference)"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + + return PM3_SUCCESS; +} + +int CmdPreferences (const char *Cmd) +{ + clearCommandBuffer(); + + return CmdsParse(CommandTable, Cmd); +} \ No newline at end of file diff --git a/client/preferences.h b/client/preferences.h new file mode 100644 index 000000000..7dce07fc6 --- /dev/null +++ b/client/preferences.h @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2009 Michael Gernoth +// Copyright (C) 2010 iZsh +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Settings Functions +//----------------------------------------------------------------------------- +#ifndef PREFERENCES_H_ +#define PREFERENCES_H_ + +#include "fileutils.h" + +#define preferencesFilename "preferences.json" + +int CmdPreferences (const char *Cmd); +int preferences_load (void); +int preferences_save (void); + +void preferences_save_callback (json_t *root); +void preferences_load_callback (json_t *root); + +#endif diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index dc67953e6..cbe4ade8d 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -26,6 +26,7 @@ #include #include "proxgui.h" #include +#include "ui.h" extern "C" { #include "util_darwin.h" @@ -168,7 +169,11 @@ void ProxWidget::vchange_dthr_down(int v) { } ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) { this->master = master; - resize(800, 400); + // Set the initail postion and size from settings + if (session.preferences_loaded) + setGeometry (session.window_plot_xpos,session.window_plot_ypos,session.window_plot_wsize,session.window_plot_hsize); + else + resize(800, 400); // Setup the controller widget controlWidget = new QWidget(); @@ -205,9 +210,13 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) { // shows plot window on the screen. show(); - // Move controller widget below plot - controlWidget->move(x(), y() + frameSize().height()); - controlWidget->resize(size().width(), 200); + if (session.preferences_loaded) + controlWidget->setGeometry (session.window_overlay_xpos,session.window_overlay_ypos,session.window_overlay_wsize,session.window_overlay_hsize); + else { + // Move controller widget below plot + controlWidget->move(x(), y() + frameSize().height()); + controlWidget->resize(size().width(), 200); + } // Olverlays / slider window title QString ct = QString("[*]Slider [ %1 ]").arg((char *)gui_serial_port_name); diff --git a/client/proxmark3.c b/client/proxmark3.c index 0438f81ad..bfc7b6212 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -27,9 +27,58 @@ #include "comms.h" #include "fileutils.h" #include "flash.h" -#include "settings.h" +#include "preferences.h" + +// Used to enable/disable use of preferences json file +// #define USE_PREFERENCE_FILE + +#ifdef _WIN32 + +static void utf8_showBanner (void) { + + char sq[] = { 0xE2,0x96,0x88,0x00 }; // square block + char tr[] = { 0xE2,0x95,0x97,0x00 }; // top rigth corner + char tl[] = { 0xE2,0x95,0x94,0x00 }; // top left corner + char br[] = { 0xE2,0x95,0x9D,0x00 }; // bottom right corner + char bl[] = { 0xE2,0x95,0x9A,0x00 }; // bottom left corner + char hl[] = { 0xE2,0x95,0x90,0x00 }; // horiz line + char vl[] = { 0xE2,0x95,0x91,0x00 }; // vert line + char msg1 [60]; + char msg2 [60]; + char msg3 [60]; + + strcpy (msg1," :snowflake: iceman@icesql.net :coffee:"); + strcpy (msg2," https://github.com/rfidresearchgroup/proxmark3/"); + strcpy (msg3,"pre-release v4.0"); + + g_printAndLog = PRINTANDLOG_PRINT; + + PrintAndLogEx(NORMAL, "\n"); + + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s %s%s%s%s %s%s%s%s %s%s%s%s%s "),sq,sq,sq,sq,sq,sq,tr,sq,sq,sq,tr,sq,sq,sq,tr,sq,sq,sq,sq,tr); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s %s%s%s%s%s %s%s%s%s"),sq,sq,tl,hl,hl,sq,sq,tr,sq,sq,sq,sq,tr,sq,sq,sq,sq,vl,hl,hl,sq,vl); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s %s%s%s%s%s%s"),sq,sq,sq,sq,sq,sq,tl,br,sq,sq,tl,sq,sq,sq,sq,tl,sq,sq,vl,sq,sq,sq,sq,tl,br); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s %s%s%s%s%s%s%s%s%s%s%s %s%s%s%s")"%s",sq,sq,tr,hl,hl,hl,br,sq,sq,vl,bl,sq,sq,tl,br,sq,sq,vl,hl,hl,sq,vl,msg1); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s %s%s%s %s%s%s %s%s%s %s%s%s%s%s%s")"%s",sq,sq,vl,sq,sq,vl,bl,hl,br,sq,sq,vl,sq,sq,sq,sq,tl,br,msg2); + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s %s%s%s %s%s%s %s%s%s%s%s ")"%s",bl,hl,br,bl,hl,br,bl,hl,br,bl,hl,hl,hl,br,msg3); + + PrintAndLogEx(NORMAL, ""); + fflush(stdout); + g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; +} + +#endif static void showBanner(void) { + +#ifdef _WIN32 + // If on windows and using UTF-8 then we need utf-8 ascii art for banner. + if (GetConsoleCP() == 65001) { + utf8_showBanner (); + return; + } +#endif + g_printAndLog = PRINTANDLOG_PRINT; PrintAndLogEx(NORMAL, "\n"); @@ -56,6 +105,7 @@ static void showBanner(void) { g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; } + static int check_comm(void) { // If communications thread goes down. Device disconnected then this should hook up PM3 again. if (IsCommunicationThreadDead() && session.pm3_present) { @@ -489,12 +539,15 @@ finish2: return ret; } +#ifndef USE_PREFERENCE_FILE + // Check if windows AnsiColor Support is enabled in the registery // [HKEY_CURRENT_USER\Console] // "VirtualTerminalLevel"=dword:00000001 // 2nd Key needs to be enabled... This key takes the console out of legacy mode. // [HKEY_CURRENT_USER\Console] // "ForceV2"=dword:00000001 + static bool DetectWindowsAnsiSupport(void) { bool ret = false; #if defined(_WIN32) @@ -543,6 +596,8 @@ static bool DetectWindowsAnsiSupport(void) { return ret; } +#endif + int main(int argc, char *argv[]) { srand(time(0)); @@ -582,12 +637,20 @@ int main(int argc, char *argv[]) { set_my_executable_path(); set_my_user_directory(); - // Settings Load and Test - // settings_load (); +#ifdef USE_PREFERENCE_FILE + // Load Settings and assign + // This will allow the command line to override the settings.json values + preferences_load (); + // Change height/width (Rows,Cols) - Testing + // printf ("\e[8;50;100t"); + // printf ("\e[3;50;50t"); // x,y + //printf ("Path : %s \n",my_user_directory); + // quick patch for debug level + g_debugMode = session.client_debug_level; // settings_save (); - // printf ("Ver : %s\n",mySettings.version); // End Settings - +#endif + for (int i = 1; i < argc; i++) { if (argv[i][0] != '-') { @@ -766,8 +829,11 @@ int main(int argc, char *argv[]) { return 1; } +#ifndef USE_PREFERENCE_FILE + // comment next 2 lines to use session values set from settings_load session.supports_colors = DetectWindowsAnsiSupport(); session.emoji_mode = ALTTEXT; +#endif session.stdinOnTTY = isatty(STDIN_FILENO); session.stdoutOnTTY = isatty(STDOUT_FILENO); @@ -837,6 +903,14 @@ int main(int argc, char *argv[]) { if (!script_cmds_file && !script_cmd && session.stdinOnTTY && session.stdoutOnTTY && !flash_mode) showBanner(); +#ifdef USE_PREFERENCE_FILE + // Save settings if not load from settings json file. + // Doing this here will ensure other checks and updates are saved to over rule default + // e.g. Linux color use check + if (!session.preferences_loaded) + preferences_save (); +#endif + #ifdef HAVE_GUI # ifdef _WIN32 diff --git a/client/resources/aid_desfire.json b/client/resources/aid_desfire.json new file mode 100644 index 000000000..56caf14b6 --- /dev/null +++ b/client/resources/aid_desfire.json @@ -0,0 +1,18 @@ +[ + { + "AID": "D3494F", + "Vendor": "HID", + "Country": "United States", + "Name": "SIO DESFire Ev1", + "Description": "", + "Type": "" + }, + { + "AID": "4F5931", + "Vendor": "Transport of London", + "Country": "UK", + "Name": "Oyster Card", + "Description": "", + "Type": "" + }, +] \ No newline at end of file diff --git a/client/settings.c b/client/settings.c deleted file mode 100644 index 79fa00fd1..000000000 --- a/client/settings.c +++ /dev/null @@ -1,194 +0,0 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, or, at your option, any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - ****************************************************************************/ - -//----------------------------------------------------------------------------- -// Settings Functions -//----------------------------------------------------------------------------- - -#include "settings.h" -#include "comms.h" -#include "emv/emvjson.h" - -// Load all settings into memory (struct) -int settings_load (void) { - // loadFileJson wants these, so pass in place holder values, though not used - // in settings load; - uint8_t dummyData = 0x00; - size_t dummyDL = 0x00; - - // clear all settings - memset (&mySettings,0x00,sizeof(mySettings)); - - if (loadFileJSON(settingsFilename, &dummyData, sizeof(dummyData), &dummyDL) == PM3_SUCCESS) { - printf ("==> Settings Loaded\n"); - mySettings.loaded = true; - } - - - // Test results - /* - bool os_windows_usecolor; - bool os_windows_useansicolor; - int window_xpos; - int window_ypos; - int window_hsize; - int window_wsize; - bool use_emojis - bool use_hints - */ - printf (" Settings Version : [%s]\n", mySettings.version); - printf (" os_windows_usecolor (bool) : [%d]\n", mySettings.os_windows_usecolor); - printf (" os_windows_useAnsicolor (bool) : [%d]\n", mySettings.os_windows_useansicolor); - printf (" window_xpos (int) : [%d]\n", mySettings.window_xpos); - printf (" window_ypos (int) : [%d]\n", mySettings.window_ypos); - printf (" window_hsize (int) : [%d]\n", mySettings.window_hsize); - printf (" window_wsize (int) : [%d]\n", mySettings.window_wsize); - printf (" use emoji (bool) : [%d]\n", mySettings.use_emojis); - printf (" use hints (bool) : [%d]\n", mySettings.use_hints); - return PM3_SUCCESS; -} - -// Save all settings from memory (struct) to file -int settings_save(void) { - // Note sure if backup has value ? - char backupFilename[500]; - - snprintf(backupFilename, sizeof(backupFilename),"%s.bak",settingsFilename); - - if (fileExists (backupFilename)) { - if (remove (backupFilename) != 0) { - PrintAndLogEx (FAILED, "Error - could not delete old settings backup file \"%s\"",backupFilename); - return PM3_ESOFT; - } - } - - if (fileExists (settingsFilename)) { - if (rename (settingsFilename,backupFilename) != 0) { - PrintAndLogEx (FAILED, "Error - could not backup settings file \"%s\" to \"%s\"",settingsFilename,backupFilename); - return PM3_ESOFT; - } - } - - uint8_t dummyData = 0x00; - size_t dummyDL = 0x00; - - if (saveFileJSON(settingsFilename, jsfSettings, &dummyData, dummyDL) == PM3_SUCCESS) - PrintAndLogEx (NORMAL, "settings have been saved to \"%s\"",settingsFilename); - - return PM3_SUCCESS; -} - -void settings_save_callback(json_t *root) { - - printf ("==> Save Settings\n"); - //JsonSaveStr(root, "FileType", "settings"); - //JsonSaveStr (root,"Test1.Test2","test settings"); - /* - "version": "1.0 Nov 2019", - "os.windows.usecolor": true, - "os.windows.useAnsiColor": true, - "window.xpos": 10, - "window.ypos": 10, - "window.hsize": 300, - "window.wsize": 600 - */ - JsonSaveStr (root,"FileType","settings"); - JsonSaveStr (root,"version","1.0 Nov 2019");//mySettings.version); - JsonSaveBoolean (root,"os.windows.useColor", mySettings.os_windows_usecolor); - JsonSaveBoolean (root,"os.windows.useAnsiColor", mySettings.os_windows_useansicolor); - JsonSaveInt (root,"window.xpos", mySettings.window_xpos); - JsonSaveInt (root,"window.ypos", mySettings.window_ypos); - JsonSaveInt (root,"window.hsize", mySettings.window_hsize); - JsonSaveInt (root,"window.wsize", mySettings.window_wsize); - JsonSaveBoolean (root,"client.useEmojis", mySettings.use_emojis); - JsonSaveBoolean (root,"client.useHints", mySettings.use_hints); -} - -void settings_load_callback(json_t *root) { - - json_error_t up_error = {0}; - int b1; - int i1; - const char *s1; - - if (json_unpack_ex(root, &up_error , 0, "{s:s}","version", &s1) == 0) - strncpy (mySettings.version,s1,sizeof (mySettings.version) - 1); - else - strncpy (mySettings.version,"unknown",sizeof (mySettings.version) - 1); - - // os.windows... - if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.windows.useColor",&b1) == 0) - mySettings.os_windows_usecolor = b1; - else // default - mySettings.os_windows_useansicolor = false; - - if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.windows.useAnsiColor",&b1) == 0) - mySettings.os_windows_useansicolor = b1; - else // default - mySettings.os_windows_useansicolor = false; - - // window... - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.xpos",&i1) == 0) - mySettings.window_xpos = i1; - else // default - mySettings.window_xpos = 0; - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.ypos",&i1) == 0) - mySettings.window_ypos = i1; - else // default - mySettings.window_ypos = 0; - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.hsize",&i1) == 0) - mySettings.window_hsize = i1; - else // default - mySettings.window_hsize = 0; - if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.wsize",&i1) == 0) - mySettings.window_wsize = i1; - else // default - mySettings.window_wsize = 0; - - // Use EMOJIS - if (json_unpack_ex(root,&up_error, 0, "{s:b}","client.useEmojis",&b1) == 0) - mySettings.use_emojis = b1; - else // default - mySettings.use_emojis = false; - - // Use Hints - if (json_unpack_ex(root,&up_error, 0, "{s:b}","client.useHints",&b1) == 0) - mySettings.use_hints = b1; - else // default - mySettings.use_hints = false; - -} diff --git a/client/settings.h b/client/settings.h deleted file mode 100644 index 4bf8b2a5e..000000000 --- a/client/settings.h +++ /dev/null @@ -1,40 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2009 Michael Gernoth -// Copyright (C) 2010 iZsh -// -// This code is licensed to you under the terms of the GNU GPL, version 2 or, -// at your option, any later version. See the LICENSE.txt file for the text of -// the license. -//----------------------------------------------------------------------------- -// Settings Functions -//----------------------------------------------------------------------------- -#ifndef settings_h -#define settings_h - -#include "fileutils.h" - -#define settingsFilename "settings.json" - -typedef struct { - bool loaded; - char version[20]; - bool os_windows_usecolor; - bool os_windows_useansicolor; - int window_xpos; - int window_ypos; - int window_hsize; - int window_wsize; - bool use_emojis; - bool use_hints; -} settings_t; - -// Settings struct so as to be available to other modules by including settings.h -settings_t mySettings; - -int settings_load (void); -int settings_save (void); - -void settings_save_callback (json_t *root); -void settings_load_callback (json_t *root); - -#endif diff --git a/client/ui.h b/client/ui.h index 5bb814b81..3875c27c8 100644 --- a/client/ui.h +++ b/client/ui.h @@ -19,8 +19,10 @@ typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLACE, HINT} logLevel_t; typedef enum emojiMode {ALIAS, EMOJI, ALTTEXT, ERASE} emojiMode_t; +typedef enum clientdebugLevel {OFF,SIMPLE,FULL} clientdebugLevel_t; typedef struct { + bool preferences_loaded; bool stdinOnTTY; bool stdoutOnTTY; bool supports_colors; @@ -28,6 +30,15 @@ typedef struct { bool pm3_present; bool help_dump_mode; bool show_hints; + int window_plot_xpos; + int window_plot_ypos; + int window_plot_hsize; + int window_plot_wsize; + int window_overlay_xpos; + int window_overlay_ypos; + int window_overlay_hsize; + int window_overlay_wsize; + clientdebugLevel_t client_debug_level; } session_arg_t; extern session_arg_t session;