1 #include "main.h"
2
3 #include "debug.h"
4 #include "settings.h"
5 #include "theme.h"
6
7 #include "native/filesys.h"
8 #include "native/main.h"
9 #include "native/thread.h"
10
11 #include "av/utox_av.h"
12
13 #include <getopt.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17
18 /* The utox_ functions contained in src/main.c are wrappers for the platform native_ functions
19 * if you need to localize them to a specific platform, move them from here, to each
20 * src/<platform>/main.x and change from utox_ to native_
21 */
22
utox_data_save_tox(uint8_t * data,size_t length)23 bool utox_data_save_tox(uint8_t *data, size_t length) {
24 FILE *fp = utox_get_file("tox_save.tox", NULL, UTOX_FILE_OPTS_WRITE);
25 if (!fp) {
26 LOG_ERR("uTox", "Can not open tox_save.tox to write to it.");
27 return true;
28 }
29
30 if (fwrite(data, length, 1, fp) != 1) {
31 LOG_ERR("uTox", "Unable to write Tox save to file.");
32 fclose(fp);
33 return true;
34 }
35
36 flush_file(fp);
37 fclose(fp);
38
39 return false;
40 }
41
utox_data_load_tox(size_t * size)42 uint8_t *utox_data_load_tox(size_t *size) {
43 const char name[][20] = { "tox_save.tox", "tox_save.tox.atomic", "tox_save.tmp", "tox_save" };
44
45 for (uint8_t i = 0; i < 4; i++) {
46 size_t length = 0;
47
48 FILE *fp = utox_get_file(name[i], &length, UTOX_FILE_OPTS_READ);
49 if (!fp) {
50 continue;
51 }
52
53 uint8_t *data = calloc(1, length + 1);
54
55 if (!data) {
56 LOG_ERR("uTox", "Could not allocate memory for tox save.");
57 fclose(fp);
58 // Quit. We're out of memory, calloc will fail again.
59 return NULL;
60 }
61
62 if (fread(data, length, 1, fp) != 1) {
63 LOG_ERR("uTox", "Could not read: %s.", name[i]);
64 fclose(fp);
65 free(data);
66 // Return NULL, because if a Tox save exits we don't want to fall
67 // back to an old version, we need the user to decide what to do.
68 return NULL;
69 }
70
71 fclose(fp);
72 *size = length;
73 return data;
74 }
75
76 return NULL;
77 }
78
utox_data_save_ftinfo(char hex[TOX_PUBLIC_KEY_SIZE * 2],uint8_t * data,size_t length)79 bool utox_data_save_ftinfo(char hex[TOX_PUBLIC_KEY_SIZE * 2], uint8_t *data, size_t length) {
80 char name[TOX_PUBLIC_KEY_SIZE * 2 + sizeof(".ftinfo")];
81 snprintf(name, sizeof(name), "%.*s.ftinfo", TOX_PUBLIC_KEY_SIZE * 2, hex);
82
83 FILE *fp = utox_get_file(name, NULL, UTOX_FILE_OPTS_WRITE);
84
85 if (fp == NULL) {
86 return false;
87 }
88
89 if (fwrite(data, length, 1, fp) != 1) {
90 LOG_ERR("uTox", "Unable to write ftinfo to file.");
91 fclose(fp);
92 return false;
93 }
94
95 fclose(fp);
96
97 return true;
98 }
99
100 /* Shared function between all four platforms */
parse_args(int argc,char * argv[],int8_t * should_launch_at_startup,int8_t * set_show_window,bool * allow_root)101 void parse_args(int argc, char *argv[],
102 int8_t *should_launch_at_startup,
103 int8_t *set_show_window,
104 bool *allow_root
105 ) {
106 // set default options
107 if (should_launch_at_startup) {
108 *should_launch_at_startup = 0;
109 }
110
111 if (set_show_window) {
112 *set_show_window = 0;
113 }
114
115 if (allow_root) {
116 *allow_root = false;
117 }
118
119 static struct option long_options[] = {
120 { "theme", required_argument, NULL, 't' }, { "portable", no_argument, NULL, 'p' },
121 { "set", required_argument, NULL, 's' }, { "unset", required_argument, NULL, 'u' },
122 { "version", no_argument, NULL, 0 }, { "silent", no_argument, NULL, 'S' },
123 { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' },
124 { "debug", required_argument, NULL, 1 }, { "allow-root", no_argument, NULL, 2 },
125 { 0, 0, 0, 0 }
126 };
127
128 settings.debug_file = stdout;
129
130 int opt, long_index = 0;
131 while ((opt = getopt_long(argc, argv, "t:ps:u:nvh", long_options, &long_index)) != -1) {
132 // loop through each option; ":" after each option means an argument is required
133 switch (opt) {
134 case 't': {
135 if (!strcmp(optarg, "default")) {
136 settings.theme = THEME_DEFAULT;
137 } else if (!strcmp(optarg, "dark")) {
138 settings.theme = THEME_DARK;
139 } else if (!strcmp(optarg, "light")) {
140 settings.theme = THEME_LIGHT;
141 } else if (!strcmp(optarg, "highcontrast")) {
142 settings.theme = THEME_HIGHCONTRAST;
143 } else if (!strcmp(optarg, "zenburn")) {
144 settings.theme = THEME_ZENBURN;
145 } else if (!strcmp(optarg, "solarized-light")) {
146 settings.theme = THEME_SOLARIZED_LIGHT;
147 } else if (!strcmp(optarg, "solarized-dark")) {
148 settings.theme = THEME_SOLARIZED_DARK;
149 } else {
150 LOG_NORM("Please specify correct theme (please check user manual for list of correct values).\n");
151 exit(EXIT_FAILURE);
152 }
153 break;
154 }
155
156 case 'p': {
157 LOG_INFO("uTox", "Launching uTox in portable mode: All data will be saved to the tox folder in the current "
158 "working directory\n");
159 settings.portable_mode = 1;
160 break;
161 }
162
163 case 's': {
164 if (!strcmp(optarg, "start-on-boot")) {
165 if (should_launch_at_startup) {
166 *should_launch_at_startup = 1;
167 }
168 } else if (!strcmp(optarg, "show-window")) {
169 if (set_show_window) {
170 *set_show_window = 1;
171 }
172 } else if (!strcmp(optarg, "hide-window")) {
173 if (set_show_window) {
174 *set_show_window = -1;
175 }
176 } else {
177 LOG_NORM("Please specify a correct set option (please check user manual for list of correct values).\n");
178 exit(EXIT_FAILURE);
179 }
180 break;
181 }
182
183 case 'u': {
184 if (!strcmp(optarg, "start-on-boot")) {
185 if (should_launch_at_startup) {
186 *should_launch_at_startup = -1;
187 }
188 } else {
189 LOG_NORM("Please specify a correct unset option (please check user manual for list of correct values).\n");
190 exit(EXIT_FAILURE);
191 }
192 break;
193 }
194
195 case 0: {
196 LOG_NORM("uTox version: %s\n", VERSION);
197 #ifdef GIT_VERSION
198 LOG_NORM("git version %s\n", GIT_VERSION);
199 #endif
200 exit(EXIT_SUCCESS);
201 break;
202 }
203
204 case 'S': {
205 settings.verbose = LOG_LVL_FATAL;
206 break;
207 }
208
209 case 'v': {
210 settings.verbose++;
211 break;
212 }
213
214 case 1: {
215 settings.debug_file = fopen(optarg, "a+");
216 if (!settings.debug_file) {
217 settings.debug_file = stdout;
218 LOG_NORM("Could not open %s. Logging to stdout.\n", optarg);
219 }
220 break;
221 }
222
223 case 2: {
224 if (allow_root) {
225 *allow_root = true;
226 }
227 break;
228 }
229
230 case 'h': {
231 LOG_NORM("µTox - Lightweight Tox client version %s.\n\n", VERSION);
232 LOG_NORM("The following options are available:\n");
233 LOG_NORM(" -t --theme=<theme-name> Specify a UI theme, where <theme-name> can be one of default, "
234 "dark, light, highcontrast, zenburn.\n");
235 LOG_NORM(" -p --portable Launch in portable mode: All data will be saved to the tox "
236 "folder in the current working directory.\n");
237 LOG_NORM(" -s --set=<option> Set an option: start-on-boot, show-window, hide-window.\n");
238 LOG_NORM(" -u --unset=<option> Unset an option: start-on-boot.\n");
239 LOG_NORM(" -v --verbose Increase the amount of output, use -v multiple times to get "
240 "full debug output.\n");
241 LOG_NORM(" -h --help Shows this help text.\n");
242 LOG_NORM(" --version Print the version and exit.\n");
243 LOG_NORM(" --silent Set the verbosity level to 0, disable all debugging output.\n");
244 LOG_NORM(" --debug Set a file for utox to log errors to.\n");
245 exit(EXIT_SUCCESS);
246 break;
247 }
248
249 case '?': LOG_TRACE("uTox", "%c", (char)optopt ); break;
250 }
251 }
252 }
253
254 /** Does all of the init work for uTox across all platforms
255 *
256 * it's expect this will be called AFTER you parse argc/v and will act accordingly. */
utox_init(void)257 void utox_init(void) {
258 atexit(utox_raze);
259
260 if (settings.debug_file == NULL) {
261 settings.debug_file = stdout;
262 }
263
264 UTOX_SAVE *save = config_load();
265 free(save);
266
267 /* Called by the native main for every platform after loading utox setting,
268 * before showing/drawing any windows. */
269 if (settings.curr_version != settings.last_version) {
270 settings.show_splash = true;
271 }
272
273 // We likely want to start this on every system.
274 thread(utox_av_ctrl_thread, NULL);
275 }
276
utox_raze(void)277 void utox_raze(void) {
278 LOG_WARN("uTox", "Clean exit.");
279 if (settings.debug_file != stdout) {
280 fclose(settings.debug_file);
281 }
282 }
283