1 #include "argoat.h"
2 #include "configator.h"
3 #include "dragonfail.h"
4 #include "termbox.h"
5 #include "ctypes.h"
6
7 #include "draw.h"
8 #include "inputs.h"
9 #include "login.h"
10 #include "utils.h"
11 #include "config.h"
12
13 #include <stddef.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18
19 #define ARG_COUNT 7
20 // things you can define:
21 // GIT_VERSION_STRING
22
23 // global
24 struct lang lang;
25 struct config config;
26
27 // args handles
arg_help(void * data,char ** pars,const int pars_count)28 void arg_help(void* data, char** pars, const int pars_count)
29 {
30 printf("RTFM\n");
31 }
32
arg_version(void * data,char ** pars,const int pars_count)33 void arg_version(void* data, char** pars, const int pars_count)
34 {
35 #ifdef GIT_VERSION_STRING
36 printf("Ly version %s\n", GIT_VERSION_STRING);
37 #else
38 printf("Ly version unknown\n");
39 #endif
40 }
41
42 // low-level error messages
log_init(char ** log)43 void log_init(char** log)
44 {
45 log[DGN_OK] = lang.err_dgn_oob;
46 log[DGN_NULL] = lang.err_null;
47 log[DGN_ALLOC] = lang.err_alloc;
48 log[DGN_BOUNDS] = lang.err_bounds;
49 log[DGN_DOMAIN] = lang.err_domain;
50 log[DGN_MLOCK] = lang.err_mlock;
51 log[DGN_XSESSIONS_DIR] = lang.err_xsessions_dir;
52 log[DGN_XSESSIONS_OPEN] = lang.err_xsessions_open;
53 log[DGN_PATH] = lang.err_path;
54 log[DGN_CHDIR] = lang.err_chdir;
55 log[DGN_PWNAM] = lang.err_pwnam;
56 log[DGN_USER_INIT] = lang.err_user_init;
57 log[DGN_USER_GID] = lang.err_user_gid;
58 log[DGN_USER_UID] = lang.err_user_uid;
59 log[DGN_PAM] = lang.err_pam;
60 log[DGN_HOSTNAME] = lang.err_hostname;
61 }
62
arg_config(void * data,char ** pars,const int pars_count)63 void arg_config(void* data, char** pars, const int pars_count)
64 {
65 *((char **)data) = *pars;
66 }
67
68 // ly!
main(int argc,char ** argv)69 int main(int argc, char** argv)
70 {
71 // init error lib
72 log_init(dgn_init());
73
74 // load config
75 config_defaults();
76 lang_defaults();
77
78 char *config_path = NULL;
79 // parse args
80 const struct argoat_sprig sprigs[ARG_COUNT] =
81 {
82 {NULL, 0, NULL, NULL},
83 {"config", 0, &config_path, arg_config},
84 {"c", 0, &config_path, arg_config},
85 {"help", 0, NULL, arg_help},
86 {"h", 0, NULL, arg_help},
87 {"version", 0, NULL, arg_version},
88 {"v", 0, NULL, arg_version},
89 };
90
91 struct argoat args = {sprigs, ARG_COUNT, NULL, 0, 0};
92 argoat_graze(&args, argc, argv);
93
94 // init inputs
95 struct desktop desktop;
96 struct text login;
97 struct text password;
98 input_desktop(&desktop);
99 input_text(&login, config.max_login_len);
100 input_text(&password, config.max_password_len);
101
102 if (dgn_catch())
103 {
104 config_free();
105 lang_free();
106 return 1;
107 }
108
109 config_load(config_path);
110
111 if (strcmp(config.lang, "en") != 0)
112 {
113 lang_load();
114 }
115
116 void* input_structs[3] =
117 {
118 (void*) &desktop,
119 (void*) &login,
120 (void*) &password,
121 };
122
123 void (*input_handles[3]) (void*, struct tb_event*) =
124 {
125 handle_desktop,
126 handle_text,
127 handle_text,
128 };
129
130 desktop_load(&desktop);
131 load(&desktop, &login);
132
133 // start termbox
134 tb_init();
135 tb_select_output_mode(TB_OUTPUT_NORMAL);
136 tb_clear();
137
138 // init visible elements
139 struct tb_event event;
140 struct term_buf buf;
141 u8 active_input = config.default_input;
142
143 (*input_handles[active_input])(input_structs[active_input], NULL);
144
145 // init drawing stuff
146 draw_init(&buf);
147
148 if (config.animate)
149 {
150 animate_init(&buf);
151
152 if (dgn_catch())
153 {
154 config.animate = false;
155 dgn_reset();
156 }
157 }
158
159 // init state info
160 int error;
161 bool run = true;
162 bool update = true;
163 bool reboot = false;
164 bool shutdown = false;
165 u8 auth_fails = 0;
166
167 switch_tty(&buf);
168
169 // main loop
170 while (run)
171 {
172 if (update)
173 {
174 if (auth_fails < 10)
175 {
176 tb_clear();
177 animate(&buf);
178 draw_box(&buf);
179 draw_labels(&buf);
180 draw_f_commands();
181 draw_lock_state(&buf);
182 position_input(&buf, &desktop, &login, &password);
183 draw_desktop(&desktop);
184 draw_input(&login);
185 draw_input_mask(&password);
186 update = config.animate;
187 }
188 else
189 {
190 usleep(10000);
191 update = cascade(&buf, &auth_fails);
192 }
193
194 tb_present();
195 }
196
197 error = tb_peek_event(&event, config.min_refresh_delta);
198
199 if (error < 0)
200 {
201 continue;
202 }
203
204 if (event.type == TB_EVENT_KEY)
205 {
206 switch (event.key)
207 {
208 case TB_KEY_F1:
209 shutdown = true;
210 run = false;
211 break;
212 case TB_KEY_F2:
213 reboot = true;
214 run = false;
215 break;
216 case TB_KEY_CTRL_C:
217 run = false;
218 break;
219 case TB_KEY_CTRL_U:
220 if (active_input > 0)
221 {
222 input_text_clear(input_structs[active_input]);
223 }
224 break;
225 case TB_KEY_ARROW_UP:
226 if (active_input > 0)
227 {
228 --active_input;
229 update = true;
230 }
231 break;
232 case TB_KEY_ARROW_DOWN:
233 if (active_input < 2)
234 {
235 ++active_input;
236 update = true;
237 }
238 break;
239 case TB_KEY_TAB:
240 ++active_input;
241
242 if (active_input > 2)
243 {
244 active_input = PASSWORD_INPUT;
245 }
246 update = true;
247 break;
248 case TB_KEY_ENTER:
249 save(&desktop, &login);
250 auth(&desktop, &login, &password, &buf);
251 update = true;
252
253 if (dgn_catch())
254 {
255 ++auth_fails;
256 // move focus back to password input
257 active_input = PASSWORD_INPUT;
258
259 if (dgn_output_code() != DGN_PAM)
260 {
261 buf.info_line = dgn_output_log();
262 }
263
264 if (config.blank_password)
265 {
266 input_text_clear(&password);
267 }
268
269 dgn_reset();
270 }
271 else
272 {
273 buf.info_line = lang.logout;
274 }
275
276 load(&desktop, &login);
277 system("tput cnorm");
278 break;
279 default:
280 (*input_handles[active_input])(
281 input_structs[active_input],
282 &event);
283 update = true;
284 break;
285 }
286 }
287 }
288
289 // stop termbox
290 tb_shutdown();
291
292 // free inputs
293 input_desktop_free(&desktop);
294 input_text_free(&login);
295 input_text_free(&password);
296 free_hostname();
297
298 // unload config
299 draw_free(&buf);
300 lang_free();
301
302 if (shutdown)
303 {
304 execl("/bin/sh", "sh", "-c", config.shutdown_cmd, NULL);
305 }
306
307 if (reboot)
308 {
309 execl("/bin/sh", "sh", "-c", config.restart_cmd, NULL);
310 }
311
312 config_free();
313
314 return 0;
315 }
316