1 module updater;
2 
3 import filemanager;
4 import nspire;
5 import nspire.device;
6 import std.stdio;
7 import std.string;
8 import std.file;
9 import std.format;
10 import std.path;
11 import std.zip;
12 
13 int updaterFun(NSpire nspire, DeviceInfo deviceInfo, string[] args) {
14     writeln("NSpire Tools - Operating System Updater\n");
15     
16     if (args.length < 1) {
17         writeln("Usage: nspire-tools updater <operating system image path>");
18         writeln("\tor: nspire-updater <operating system image path>\n");
19         return 1;
20     }
21     
22     writeln("\033[1mWARNING: Updating your operating system may cause a permanent hard brick");
23     writeln("of your TI-NSpire, always check what you are doing\033[22m");
24     writeln();
25     writeln();
26     
27     if (!checkExtOs(deviceInfo, args[0])) {
28         return ErrorCodes.NSPIRE_ERR_INVALID;
29     }
30     
31     if (!args[0].exists || !args[0].isFile) {
32         writeln(args[0], " is not a valid file");
33         return ErrorCodes.NSPIRE_ERR_INVALID;
34     }
35     
36     writeln("Update file: ", args[0].absolutePath);
37     writeln("Update size: ", args[0].getSize); 
38     
39     void[] fileBuf;
40     ZipArchive zip;
41     string manifest;
42     
43     try {
44         fileBuf = read(args[0]);
45     } catch (FileException e) {
46         writeln("Error: failed file read on local side");
47         return ErrorCodes.NSPIRE_ERR_INVALID;
48     }
49     
50     try {
51         zip = new ZipArchive(fileBuf);
52     } catch (ZipException e) {
53         writeln(args[0], " is not a valid file");
54         return ErrorCodes.NSPIRE_ERR_INVALID;
55     }
56     
57     if (("manifest.txt" in zip.directory) is null) {
58         writeln(args[0], " is not a valid file");
59         return ErrorCodes.NSPIRE_ERR_INVALID;
60     }
61     
62     try {
63         manifest = (cast(char[]) zip.expand(zip.directory["manifest.txt"])).dup;
64     } catch (ZipException e) {
65         writeln(args[0], " is not a valid file");
66         return ErrorCodes.NSPIRE_ERR_INVALID;
67     }
68     
69     auto updateVersion =  manifest.splitLines[1].strip;
70     auto currentVersion = format!"%u.%u.%u"(deviceInfo.versionOs.major, deviceInfo.versionOs.minor, deviceInfo.versionOs.build);
71     
72     writeln("Update OS version: ", updateVersion);
73     writeln("Current OS version: ", currentVersion);
74     
75     if (updateVersion == currentVersion) {
76         writeln("\033[1mWarning: you have already installed this update!\033[22m");
77     }
78     
79     writeln();
80     writeln("\033[1mDuring the update, make sure not to disconnect the USB cable and not turn off the computer!\033[22m");
81     writeln("\033[1mIf you are using a laptop connected to the power supply before continue.\033[22m");
82     writeln();
83     write("Enter the version of the OS you want to update to confirm the start of the updater: ");
84     auto checkVersion = stdin.readln.strip;
85     
86     if (checkVersion != updateVersion) {
87         writeln("Error: Update process aborted, user check failed!");
88         return ErrorCodes.NSPIRE_ERR_INVALID;
89     }
90     
91     writeln();
92     writeln("\033[1mUpdate in progress (it takes a long time)... DO NOT DISCONNECT THE USB CABLE OR TURN OFF THE COMPUTER\033[22m");
93     auto error = nspire.sendOs(fileBuf);
94     writeln();
95     
96     if (error != ErrorCodes.NSPIRE_ERR_SUCCESS) {
97         writeln("Error: ", NSpire.errorStr(error));
98         writeln("\033[1mAn An error in the update process can have serious consequences,\033[22m");
99         writeln("\033[1mAn make sure you understand what happened before taking any action\033[22m");
100         
101         return error;
102     }
103     
104     writeln("\033[1mUpdate successful! Your NSpire is restarting with the OS version ", updateVersion, "\033[22m");
105     return 0;
106 }