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