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