mirror of https://github.com/fairyglade/ly
completed
parent
d285d558cd
commit
ce745bf9f4
@ -0,0 +1,2 @@
|
||||
bin
|
||||
obj
|
@ -0,0 +1,6 @@
|
||||
[submodule "sub/inih"]
|
||||
path = sub/inih
|
||||
url = https://github.com/benhoyt/inih.git
|
||||
[submodule "sub/termbox-next"]
|
||||
path = sub/termbox-next
|
||||
url = https://github.com/cylgom/termbox-next.git
|
@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
@ -0,0 +1,78 @@
|
||||
### Ly - a TUI display manager
|
||||
|
||||
![ly screenshot](https://user-images.githubusercontent.com/5473047/42466218-8cb53d3c-83ae-11e8-8e53-bae3669f959c.png "ly on st")
|
||||
|
||||
Ly is a lightweight, TUI (ncurses-like) display manager for linux.
|
||||
|
||||
### Dependencies
|
||||
Make sure all the following packages are properly installed and configured
|
||||
on your linux distribution before going further:
|
||||
- a c99 compiler (tested with gcc and tcc)
|
||||
- a c standard library
|
||||
- make
|
||||
- linux-pam
|
||||
- xorg
|
||||
- xorg-xinit
|
||||
- xorg-xauth
|
||||
- mcookie
|
||||
- tput
|
||||
- shutdown
|
||||
|
||||
### Cloning and Compiling
|
||||
This repository uses submodules, so you must clone it like so
|
||||
```
|
||||
git clone --recurse-submodules https://github.com/cylgom/ly.git
|
||||
```
|
||||
|
||||
To compile you just need to launch make in the created folder
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
Check if it works on the tty you configured (default is tty2). You can
|
||||
also run it in terminal emulators, but desktop environments won't start
|
||||
```
|
||||
sudo make run
|
||||
```
|
||||
|
||||
Then, install Ly and the systemd service file
|
||||
```
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Now enable the systemd service to make it spawn on startup
|
||||
```
|
||||
sudo systemctl enable ly.service
|
||||
```
|
||||
|
||||
If you need to switch between ttys after Ly's start you also have to
|
||||
disable getty on Ly's tty to prevent "login" from spawning on top of it
|
||||
```
|
||||
sudo systemctl disable getty@tty2.service
|
||||
```
|
||||
|
||||
If messages from other services pop over the login prompt,
|
||||
edit open the configuration and make sure `force_update` is enabled
|
||||
```
|
||||
[box_main]
|
||||
force_update=1
|
||||
```
|
||||
|
||||
### Configuration
|
||||
All the configuration takes place in `/etc/ly/config.ini`.
|
||||
A complete reference is available on the wiki.
|
||||
|
||||
### Controls
|
||||
Use the up and down arrow keys to change the current field, and the
|
||||
left and right arrow keys to change the target desktop environment
|
||||
while on the desktop field (above the login field).
|
||||
|
||||
### Tips
|
||||
The numlock and capslock state is printed in the top-right corner.
|
||||
Use the F1 and F2 keys to respectively shutdown and reboot.
|
||||
|
||||
### Additionnal informations
|
||||
The name "Ly" is a tribute to the fairy from the game Rayman.
|
||||
Ly was tested by oxodao, who is some seriously awesome dude.
|
||||
I wish to thank linux-pam, X11 and systemd developers for not
|
||||
providing anything close to a reference or documentation.
|
@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=TUI display manager
|
||||
After=systemd-user-sessions.service plymouth-quit-wait.service
|
||||
After=getty@tty2.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/ly
|
||||
StandardInput=tty
|
||||
TTYPath=/dev/tty2
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
|
||||
[Install]
|
||||
Alias=display-manager.service
|
@ -0,0 +1,71 @@
|
||||
NAME=ly
|
||||
CC=gcc
|
||||
#CC=gcc -O3
|
||||
#CC=tcc
|
||||
FLAGS=-std=c99 -pedantic -Wall -Werror=vla -Werror -g
|
||||
|
||||
BIND=bin
|
||||
SRCD=src
|
||||
SUBD=sub
|
||||
OBJD=obj
|
||||
RESD=res
|
||||
LANG=$(RESD)/lang
|
||||
INCL=-I$(SRCD) -I$(SUBD)/termbox-next/src -I$(SUBD)/inih
|
||||
LINK=-lm -lpam -lpam_misc
|
||||
|
||||
SRCS=$(SRCD)/main.c
|
||||
SRCS+=$(SRCD)/draw.c
|
||||
SRCS+=$(SRCD)/util.c
|
||||
SRCS+=$(SRCD)/config.c
|
||||
SRCS+=$(SRCD)/widgets.c
|
||||
SRCS+=$(SRCD)/desktop.c
|
||||
SRCS+=$(SRCD)/inputs.c
|
||||
SRCS+=$(SRCD)/login.c
|
||||
SRCS+=$(SUBD)/inih/ini.c
|
||||
|
||||
OBJS:=$(patsubst $(SRCD)/%.c,$(OBJD)/$(SRCD)/%.o,$(SRCS))
|
||||
OBJS+=$(SUBD)/termbox-next/bin/termbox.a
|
||||
|
||||
.PHONY:all
|
||||
all:$(BIND)/$(NAME)
|
||||
|
||||
$(OBJD)/%.o:%.c
|
||||
@echo "building source object $@"
|
||||
@mkdir -p $(@D)
|
||||
@$(CC) $(INCL) $(FLAGS) -c -o $@ $<
|
||||
|
||||
$(SUBD)/termbox-next/bin/termbox.a:
|
||||
@echo "building static object $@"
|
||||
@cd $(SUBD)/termbox-next && make
|
||||
|
||||
$(BIND)/$(NAME):$(OBJS)
|
||||
@echo "compiling $@"
|
||||
@mkdir -p $(BIND)
|
||||
@$(CC) $(INCL) $(FLAGS) $(LINK) -o $(BIND)/$(NAME) $(OBJS)
|
||||
@cp -r $(LANG) $(BIND)/lang
|
||||
@cp $(RESD)/config.ini $(BIND)
|
||||
|
||||
run:$(BIND)/$(NAME)
|
||||
@cd ./$(BIND) && ./$(NAME)
|
||||
|
||||
valgrind:$(BIND)/$(NAME)
|
||||
@cd ./$(BIND) && valgrind --show-leak-kinds=all --track-origins=yes --leak-check=full --suppressions=../res/valgrind.supp 2> ../valgrind.log ./ly
|
||||
|
||||
install:$(BIND)/$(NAME)
|
||||
install -dZ ${DESTDIR}/etc/ly
|
||||
install -DZ $(BIND)/$(NAME) -t ${DESTDIR}/usr/bin
|
||||
install -DZ xsetup.sh -t ${DESTDIR}/etc/ly
|
||||
install -DZ $(RESD)/config.ini -t ${DESTDIR}/etc/ly
|
||||
install -dZ ${DESTDIR}/etc/ly/lang
|
||||
install -DZ $(RESD)/lang/* -t ${DESTDIR}/etc/ly/lang
|
||||
install -DZ ly.service -t ${DESTDIR}/usr/lib/systemd/system
|
||||
|
||||
uninstall:
|
||||
rm -rf ${DESTDIR}/etc/ly
|
||||
rm -f ${DESTDIR}/usr/bin/ly
|
||||
rm -f ${DESTDIR}/usr/lib/systemd/system/ly.service
|
||||
|
||||
clean:
|
||||
@echo "cleaning workspace"
|
||||
@rm -rf $(BIND)
|
||||
@rm -rf $(OBJD)
|
@ -0,0 +1,13 @@
|
||||
[box_main]
|
||||
bg=0x000000
|
||||
fg=0x00ff00
|
||||
margin_box_main_h=2
|
||||
margin_box_main_v=1
|
||||
input_len=34
|
||||
blank_box=1
|
||||
min_refresh_delta=10
|
||||
force_update=1
|
||||
animate=1
|
||||
save=1
|
||||
load=1
|
||||
hide_x=1
|
@ -0,0 +1,29 @@
|
||||
[box_main]
|
||||
login=login:
|
||||
password=password:
|
||||
f1=F1 shutdown
|
||||
f2=F2 reboot
|
||||
shell=shell
|
||||
xinitrc=xinitrc
|
||||
logout=logout
|
||||
capslock=capslock
|
||||
numlock=numlock
|
||||
err_pam_buf=memory buffer error
|
||||
err_pam_sys=system error
|
||||
err_pam_auth=authentication error
|
||||
err_pam_cred_insufficient=insufficient credentials
|
||||
err_pam_authinfo_unavail=failed to get user info
|
||||
err_pam_maxtries=reached maximum tries limit
|
||||
err_pam_user_unknown=unknown user
|
||||
err_pam_acct_expired=account expired
|
||||
err_pam_authok_reqd=token expired
|
||||
err_pam_perm_denied=permission denied
|
||||
err_pam_cred_err=failed to set credentials
|
||||
err_pam_cred_expired=credentials expired
|
||||
err_pam_cred_unavail=failed to get credentials
|
||||
err_pam_session=session error
|
||||
err_pam_abort=pam transaction aborted
|
||||
err_perm_group=failed to downgrade group permissions
|
||||
err_perm_user=failed to downgrade user permissions
|
||||
err_perm_dir=failed to change current directory
|
||||
err_console_dev=failed to access console
|
@ -0,0 +1,29 @@
|
||||
[box_main]
|
||||
login=identifiant :
|
||||
password=mot de passe :
|
||||
f1=F1 éteindre
|
||||
f2=F2 redémarrer
|
||||
shell=shell
|
||||
xinitrc=xinitrc
|
||||
logout=déconnection
|
||||
capslock=verr.maj
|
||||
numlock=verr.num
|
||||
err_pam_buf=erreur de mémoire tampon
|
||||
err_pam_sys=erreur système
|
||||
err_pam_auth=erreur d'authentification
|
||||
err_pam_cred_insufficient=identifiants insuffisants
|
||||
err_pam_authinfo_unavail=échec de l'obtention des infos utilisateur
|
||||
err_pam_maxtries=limite d'essais atteinte
|
||||
err_pam_user_unknown=utilisateur inconnu
|
||||
err_pam_acct_expired=compte expiré
|
||||
err_pam_authok_reqd=tiquet expiré
|
||||
err_pam_perm_denied=permission refusée
|
||||
err_pam_cred_err=échec de la modification des identifiants
|
||||
err_pam_cred_expired=identifiants expirés
|
||||
err_pam_cred_unavail=échec de l'obtention des identifiants
|
||||
err_pam_session=erreur de session
|
||||
err_pam_abort=transaction pam avortée
|
||||
err_perm_group=échec du déclassement des permissions de groupe
|
||||
err_perm_user=échec du déclassement des permissions utilisateur
|
||||
err_perm_dir=échec de changement de répertoire
|
||||
err_console_dev=échec d'accès à la console
|
@ -0,0 +1,31 @@
|
||||
{
|
||||
pam
|
||||
Memcheck:Leak
|
||||
...
|
||||
obj:/usr/lib/libpam.so.0.84.2
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
termbox
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:tb_init
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
libc/dynamic
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:_dl_catch_exception
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
libc/groups
|
||||
Memcheck:Leak
|
||||
...
|
||||
fun:initgroups
|
||||
...
|
||||
}
|
@ -0,0 +1,691 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include "config.h"
|
||||
#include "cylgom.h"
|
||||
#include "ini.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> // login max length
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
struct lang lang = {0};
|
||||
struct config config = {0};
|
||||
char* info_line = NULL;
|
||||
|
||||
u16 compute_box_main_width()
|
||||
{
|
||||
u16 login_len = strlen(lang.login);
|
||||
u16 password_len = strlen(lang.password);
|
||||
u16 label_len = login_len > password_len ? login_len : password_len;
|
||||
|
||||
return 2 * config.margin_box_main_h + config.input_len + 1 + label_len;
|
||||
}
|
||||
|
||||
// smart-dup for config loaders
|
||||
void cfg_dup(char** name, const char* value)
|
||||
{
|
||||
// this is not a mistake, struct was initialized with zeros
|
||||
// empty fields are zero-valued pointers because of that
|
||||
// we probably don't care about that, but let's pretend systems
|
||||
// where NULL != 0 actually exist and are used.
|
||||
if (*name != 0)
|
||||
{
|
||||
free(*name);
|
||||
}
|
||||
|
||||
*name = strdup(value);
|
||||
}
|
||||
|
||||
int config_lang_handler(void* user, const char* section, const char* name, const char* value)
|
||||
{
|
||||
(void)(user);
|
||||
|
||||
if (strcmp(section, "box_main") == 0)
|
||||
{
|
||||
if (strcmp(name, "login") == 0)
|
||||
{
|
||||
cfg_dup(&lang.login, value);
|
||||
}
|
||||
else if (strcmp(name, "password") == 0)
|
||||
{
|
||||
cfg_dup(&lang.password, value);
|
||||
}
|
||||
else if (strcmp(name, "f1") == 0)
|
||||
{
|
||||
cfg_dup(&lang.f1, value);
|
||||
}
|
||||
else if (strcmp(name, "f2") == 0)
|
||||
{
|
||||
cfg_dup(&lang.f2, value);
|
||||
}
|
||||
else if (strcmp(name, "shell") == 0)
|
||||
{
|
||||
cfg_dup(&lang.shell, value);
|
||||
}
|
||||
else if (strcmp(name, "xinitrc") == 0)
|
||||
{
|
||||
cfg_dup(&lang.xinitrc, value);
|
||||
}
|
||||
else if (strcmp(name, "logout") == 0)
|
||||
{
|
||||
cfg_dup(&lang.logout, value);
|
||||
}
|
||||
else if (strcmp(name, "capslock") == 0)
|
||||
{
|
||||
cfg_dup(&lang.capslock, value);
|
||||
}
|
||||
else if (strcmp(name, "numlock") == 0)
|
||||
{
|
||||
cfg_dup(&lang.numlock, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_buf") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_buf, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_sys") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_sys, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_auth") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_auth, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_cred_insufficient") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_cred_insufficient, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_authinfo_unavail") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_authinfo_unavail, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_maxtries") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_maxtries, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_user_unknown") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_user_unknown, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_acct_expired") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_acct_expired, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_authok_reqd") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_authok_reqd, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_perm_denied") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_perm_denied, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_cred_err") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_cred_err, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_cred_expired") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_cred_expired, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_cred_unavail") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_cred_unavail, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_session") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_session, value);
|
||||
}
|
||||
else if (strcmp(name, "err_pam_abort") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_pam_abort, value);
|
||||
}
|
||||
else if (strcmp(name, "err_perm_group") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_perm_group, value);
|
||||
}
|
||||
else if (strcmp(name, "err_perm_user") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_perm_user, value);
|
||||
}
|
||||
else if (strcmp(name, "err_perm_dir") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_perm_dir, value);
|
||||
}
|
||||
else if (strcmp(name, "err_console_dev") == 0)
|
||||
{
|
||||
cfg_dup(&lang.err_console_dev, value);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void config_lang_patch()
|
||||
{
|
||||
if (lang.login == 0)
|
||||
{
|
||||
lang.login = strdup("login:");
|
||||
}
|
||||
if (lang.password == 0)
|
||||
{
|
||||
lang.password = strdup("password:");
|
||||
}
|
||||
if (lang.f1 == 0)
|
||||
{
|
||||
lang.f1 = strdup("F1 shutdown");
|
||||
}
|
||||
if (lang.f2 == 0)
|
||||
{
|
||||
lang.f2 = strdup("F2 reboot");
|
||||
}
|
||||
if (lang.shell == 0)
|
||||
{
|
||||
lang.shell = strdup("shell");
|
||||
}
|
||||
if (lang.xinitrc == 0)
|
||||
{
|
||||
lang.xinitrc = strdup("xinitrc");
|
||||
}
|
||||
if (lang.logout == 0)
|
||||
{
|
||||
lang.logout = strdup("logout");
|
||||
}
|
||||
if (lang.capslock == 0)
|
||||
{
|
||||
lang.capslock = strdup("capslock");
|
||||
}
|
||||
if (lang.numlock == 0)
|
||||
{
|
||||
lang.numlock = strdup("numlock");
|
||||
}
|
||||
if (lang.err_pam_buf == 0)
|
||||
{
|
||||
lang.err_pam_buf = strdup("memory buffer error");
|
||||
}
|
||||
if (lang.err_pam_sys == 0)
|
||||
{
|
||||
lang.err_pam_sys = strdup("system error");
|
||||
}
|
||||
if (lang.err_pam_auth == 0)
|
||||
{
|
||||
lang.err_pam_auth = strdup("authentication error");
|
||||
}
|
||||
if (lang.err_pam_cred_insufficient == 0)
|
||||
{
|
||||
lang.err_pam_cred_insufficient = strdup("insufficient credentials");
|
||||
}
|
||||
if (lang.err_pam_authinfo_unavail == 0)
|
||||
{
|
||||
lang.err_pam_authinfo_unavail = strdup("failed to get user info");
|
||||
}
|
||||
if (lang.err_pam_maxtries == 0)
|
||||
{
|
||||
lang.err_pam_maxtries = strdup("reached maximum tries limit");
|
||||
}
|
||||
if (lang.err_pam_user_unknown == 0)
|
||||
{
|
||||
lang.err_pam_user_unknown = strdup("unknown user");
|
||||
}
|
||||
if (lang.err_pam_acct_expired == 0)
|
||||
{
|
||||
lang.err_pam_acct_expired = strdup("account expired");
|
||||
}
|
||||
if (lang.err_pam_authok_reqd == 0)
|
||||
{
|
||||
lang.err_pam_authok_reqd = strdup("token expired");
|
||||
}
|
||||
if (lang.err_pam_perm_denied == 0)
|
||||
{
|
||||
lang.err_pam_perm_denied = strdup("permission denied");
|
||||
}
|
||||
if (lang.err_pam_cred_err == 0)
|
||||
{
|
||||
lang.err_pam_cred_err = strdup("failed to set credentials");
|
||||
}
|
||||
if (lang.err_pam_cred_expired == 0)
|
||||
{
|
||||
lang.err_pam_cred_expired = strdup("credentials expired");
|
||||
}
|
||||
if (lang.err_pam_cred_unavail == 0)
|
||||
{
|
||||
lang.err_pam_cred_unavail = strdup("failed to get credentials");
|
||||
}
|
||||
if (lang.err_pam_session == 0)
|
||||
{
|
||||
lang.err_pam_session = strdup("session error");
|
||||
}
|
||||
if (lang.err_pam_abort == 0)
|
||||
{
|
||||
lang.err_pam_abort = strdup("pam transaction aborted");
|
||||
}
|
||||
if (lang.err_perm_group == 0)
|
||||
{
|
||||
lang.err_perm_group = strdup("failed to downgrade group permissions");
|
||||
}
|
||||
if (lang.err_perm_user == 0)
|
||||
{
|
||||
lang.err_perm_user = strdup("failed to downgrade user permissions");
|
||||
}
|
||||
if (lang.err_perm_dir == 0)
|
||||
{
|
||||
lang.err_perm_dir = strdup("failed to change current directory");
|
||||
}
|
||||
if (lang.err_console_dev == 0)
|
||||
{
|
||||
lang.err_console_dev = strdup("failed to access console");
|
||||
}
|
||||
}
|
||||
|
||||
void config_lang_free()
|
||||
{
|
||||
free(lang.login);
|
||||
free(lang.password);
|
||||
free(lang.f1);
|
||||
free(lang.f2);
|
||||
free(lang.shell);
|
||||
free(lang.xinitrc);
|
||||
free(lang.logout);
|
||||
free(lang.capslock);
|
||||
free(lang.numlock);
|
||||
free(lang.err_pam_buf);
|
||||
free(lang.err_pam_sys);
|
||||
free(lang.err_pam_auth);
|
||||
free(lang.err_pam_cred_insufficient);
|
||||
free(lang.err_pam_authinfo_unavail);
|
||||
free(lang.err_pam_maxtries);
|
||||
free(lang.err_pam_user_unknown);
|
||||
free(lang.err_pam_acct_expired);
|
||||
free(lang.err_pam_authok_reqd);
|
||||
free(lang.err_pam_perm_denied);
|
||||
free(lang.err_pam_cred_err);
|
||||
free(lang.err_pam_cred_expired);
|
||||
free(lang.err_pam_cred_unavail);
|
||||
free(lang.err_pam_session);
|
||||
free(lang.err_pam_abort);
|
||||
free(lang.err_perm_group);
|
||||
free(lang.err_perm_user);
|
||||
free(lang.err_perm_dir);
|
||||
free(lang.err_console_dev);
|
||||
}
|
||||
|
||||
int config_config_handler(void* user, const char* section, const char* name, const char* value)
|
||||
{
|
||||
(void)(user);
|
||||
|
||||
if (strcmp(section, "box_main") == 0)
|
||||
{
|
||||
if (strcmp(name, "margin_box_main_h") == 0)
|
||||
{
|
||||
config.margin_box_main_h = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "margin_box_main_v") == 0)
|
||||
{
|
||||
config.margin_box_main_v = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "input_len") == 0)
|
||||
{
|
||||
config.input_len = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "bg") == 0)
|
||||
{
|
||||
config.bg = strtoul(value, NULL, 16);
|
||||
}
|
||||
else if (strcmp(name, "fg") == 0)
|
||||
{
|
||||
config.fg = strtoul(value, NULL, 16);
|
||||
}
|
||||
else if (strcmp(name, "max_desktop_len") == 0)
|
||||
{
|
||||
config.max_desktop_len = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "max_login_len") == 0)
|
||||
{
|
||||
config.max_login_len = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "max_password_len") == 0)
|
||||
{
|
||||
config.max_password_len = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "min_refresh_delta") == 0)
|
||||
{
|
||||
config.min_refresh_delta = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "blank_box") == 0)
|
||||
{
|
||||
config.blank_box = (atoi(value) > 0) ? true : false;
|
||||
}
|
||||
else if (strcmp(name, "force_update") == 0)
|
||||
{
|
||||
config.force_update = (atoi(value) > 0) ? true : false;
|
||||
}
|
||||
else if (strcmp(name, "animate") == 0)
|
||||
{
|
||||
config.animate = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "xsessions") == 0)
|
||||
{
|
||||
cfg_dup(&config.xsessions, value);
|
||||
}
|
||||
else if (strcmp(name, "service_name") == 0)
|
||||
{
|
||||
cfg_dup(&config.service_name, value);
|
||||
}
|
||||
else if (strcmp(name, "tty_id") == 0)
|
||||
{
|
||||
config.tty_id = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "x_cmd") == 0)
|
||||
{
|
||||
cfg_dup(&config.x_cmd, value);
|
||||
}
|
||||
else if (strcmp(name, "x_cmd_setup") == 0)
|
||||
{
|
||||
cfg_dup(&config.x_cmd_setup, value);
|
||||
}
|
||||
else if (strcmp(name, "mcookie_cmd") == 0)
|
||||
{
|
||||
cfg_dup(&config.mcookie_cmd, value);
|
||||
}
|
||||
else if (strcmp(name, "xauthority") == 0)
|
||||
{
|
||||
cfg_dup(&config.xauthority, value);
|
||||
}
|
||||
else if (strcmp(name, "path") == 0)
|
||||
{
|
||||
cfg_dup(&config.path, value);
|
||||
}
|
||||
else if (strcmp(name, "shutdown_cmd") == 0)
|
||||
{
|
||||
cfg_dup(&config.shutdown_cmd, value);
|
||||
}
|
||||
else if (strcmp(name, "console_dev") == 0)
|
||||
{
|
||||
cfg_dup(&config.console_dev, value);
|
||||
}
|
||||
else if (strcmp(name, "tty") == 0)
|
||||
{
|
||||
config.tty = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "save") == 0)
|
||||
{
|
||||
config.save = (atoi(value) > 0) ? true : false;
|
||||
}
|
||||
else if (strcmp(name, "load") == 0)
|
||||
{
|
||||
config.load = (atoi(value) > 0) ? true : false;
|
||||
}
|
||||
else if (strcmp(name, "save_file") == 0)
|
||||
{
|
||||
cfg_dup(&config.save_file, value);
|
||||
}
|
||||
else if (strcmp(name, "custom_res") == 0)
|
||||
{
|
||||
config.custom_res = (atoi(value) > 0) ? true : false;
|
||||
}
|
||||
else if (strcmp(name, "res_width") == 0)
|
||||
{
|
||||
config.res_width = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "res_height") == 0)
|
||||
{
|
||||
config.res_height = abs(atoi(value));
|
||||
}
|
||||
else if (strcmp(name, "hide_x") == 0)
|
||||
{
|
||||
config.hide_x = (atoi(value) > 0) ? true : false;
|
||||
}
|
||||
else if (strcmp(name, "hide_x_save_log") == 0)
|
||||
{
|
||||
cfg_dup(&config.hide_x_save_log, value);
|
||||
}
|
||||
else if (strcmp(name, "lang") == 0)
|
||||
{
|
||||
cfg_dup(&config.lang, value);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void config_config_patch()
|
||||
{
|
||||
if (config.margin_box_main_h == 0)
|
||||
{
|
||||
config.margin_box_main_h = 2;
|
||||
}
|
||||
if (config.margin_box_main_v == 0)
|
||||
{
|
||||
config.margin_box_main_v = 1;
|
||||
}
|
||||
if (config.input_len == 0)
|
||||
{
|
||||
config.input_len = 34;
|
||||
}
|
||||
if (config.bg == 0)
|
||||
{
|
||||
config.bg = 0x000000;
|
||||
}
|
||||
if (config.fg == 0)
|
||||
{
|
||||
config.fg = 0xffffff;
|
||||
}
|
||||
if (config.max_desktop_len == 0)
|
||||
{
|
||||
// arbitrary one
|
||||
config.max_desktop_len = 100;
|
||||
}
|
||||
if (config.max_login_len == 0)
|
||||
{
|
||||
// for "useradd" the max is 32
|
||||
config.max_login_len = 32;
|
||||
|
||||
#ifdef LOGIN_NAME_MAX
|
||||
if (config.max_login_len < LOGIN_NAME_MAX)
|
||||
{
|
||||
// the posix standard specifies it includes the terminating NULL
|
||||
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/limits.h.html
|
||||
config.max_login_len = LOGIN_NAME_MAX - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_LOGIN_NAME_MAX
|
||||
if (config.max_login_len < _POSIX_LOGIN_NAME_MAX)
|
||||
{
|
||||
config.max_login_len = _POSIX_LOGIN_NAME_MAX - 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (config.max_password_len == 0)
|
||||
{
|
||||
// for "passwd" the max is 200
|
||||
// https://github.com/shadow-maint/shadow/blob/master/src/passwd.c#L217
|
||||
// for "sudo" it is 255
|
||||
// https://www.sudo.ws/repos/sudo/file/tip/include/sudo_plugin.h
|
||||
// https://www.sudo.ws/repos/sudo/file/tip/src/sudo.c
|
||||
// "su" and "login" user linux-pam and do not seem to have a limit
|
||||
config.max_password_len = 255;
|
||||
}
|
||||
if (config.min_refresh_delta == 0)
|
||||
{
|
||||
config.min_refresh_delta = 1000;
|
||||
}
|
||||
|
||||
// commenting theses because the defaults are 0
|
||||
//#if 0
|
||||
if (config.blank_box == 0)
|
||||
{
|
||||
config.blank_box = false;
|
||||
}
|
||||
if (config.force_update == 0)
|
||||
{
|
||||
config.force_update = false;
|
||||
}
|
||||
if (config.animate == 0)
|
||||
{
|
||||
config.animate = 0;
|
||||
}
|
||||
//#endif
|
||||
|
||||
if (config.xsessions == 0)
|
||||
{
|
||||
config.xsessions = strdup("/usr/share/xsessions");
|
||||
}
|
||||
if (config.service_name == 0)
|
||||
{
|
||||
config.service_name = strdup("login");
|
||||
}
|
||||
if (config.tty_id == 0)
|
||||
{
|
||||
config.tty_id = 2;
|
||||
}
|
||||
if (config.x_cmd == 0)
|
||||
{
|
||||
config.x_cmd = strdup("/usr/bin/X");
|
||||
}
|
||||
if (config.x_cmd_setup == 0)
|
||||
{
|
||||
config.x_cmd_setup = strdup("/etc/ly/xsetup.sh");
|
||||
}
|
||||
if (config.mcookie_cmd == 0)
|
||||
{
|
||||
config.mcookie_cmd = strdup("/usr/bin/mcookie");
|
||||
}
|
||||
if (config.xauthority == 0)
|
||||
{
|
||||
config.xauthority = strdup(".lyxauth");
|
||||
}
|
||||
if (config.path == 0)
|
||||
{
|
||||
config.path = strdup("/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/env");
|
||||
}
|
||||
if (config.shutdown_cmd == 0)
|
||||
{
|
||||
config.shutdown_cmd = strdup("/sbin/shutdown");
|
||||
}
|
||||
if (config.console_dev == 0)
|
||||
{
|
||||
config.console_dev = strdup("/dev/console");
|
||||
}
|
||||
if (config.tty == 0)
|
||||
{
|
||||
config.tty = 2;
|
||||
}
|
||||
if (config.save_file == 0)
|
||||
{
|
||||
config.save_file = strdup("/etc/ly/ly.save");
|
||||
}
|
||||
if ((config.res_width == 0) || (config.res_height == 0))
|
||||
{
|
||||
config.custom_res = false;
|
||||
}
|
||||
if (config.hide_x_save_log == 0)
|
||||
{
|
||||
config.hide_x_save_log = strdup("/dev/null");
|
||||
}
|
||||
if (config.lang == 0)
|
||||
{
|
||||
config.lang = strdup("/etc/ly/lang/en.ini");
|
||||
}
|
||||
|
||||
// fill secret parameters
|
||||
config.box_main_w = compute_box_main_width();
|
||||
config.box_main_h = 9;
|
||||
}
|
||||
|
||||
void config_config_free()
|
||||
{
|
||||
free(config.xsessions);
|
||||
free(config.service_name);
|
||||
free(config.x_cmd);
|
||||
free(config.x_cmd_setup);
|
||||
free(config.mcookie_cmd);
|
||||
free(config.xauthority);
|
||||
free(config.path);
|
||||
free(config.shutdown_cmd);
|
||||
free(config.console_dev);
|
||||
free(config.save_file);
|
||||
free(config.hide_x_save_log);
|
||||
free(config.lang);
|
||||
}
|
||||
|
||||
// loads the ini configs
|
||||
void config_load(const char* file_config)
|
||||
{
|
||||
// we don't care about this function's success
|
||||
ini_parse(file_config, config_config_handler, NULL);
|
||||
ini_parse(config.lang, config_lang_handler, NULL);
|
||||
// because we check for missing strings anyway
|
||||
config_lang_patch(); // config patch depends on lang
|
||||
config_config_patch(); // so we call them in this order
|
||||
}
|
||||
|
||||
void set_error(enum err error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case ERR_PERM_GROUP:
|
||||
info_line = lang.err_perm_group;
|
||||
break;
|
||||
case ERR_PERM_USER:
|
||||
info_line = lang.err_perm_user;
|
||||
break;
|
||||
case ERR_PERM_DIR:
|
||||
info_line = lang.err_perm_dir;
|
||||
break;
|
||||
default:
|
||||
info_line = lang.err_pam_abort;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pam_diagnose(int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case PAM_BUF_ERR:
|
||||
info_line = lang.err_pam_buf;
|
||||
break;
|
||||
case PAM_SYSTEM_ERR:
|
||||
info_line = lang.err_pam_sys;
|
||||
break;
|
||||
case PAM_AUTH_ERR:
|
||||
info_line = lang.err_pam_auth;
|
||||
break;
|
||||
case PAM_CRED_INSUFFICIENT:
|
||||
info_line = lang.err_pam_cred_insufficient;
|
||||
break;
|
||||
case PAM_AUTHINFO_UNAVAIL:
|
||||
info_line = lang.err_pam_authinfo_unavail;
|
||||
break;
|
||||
case PAM_MAXTRIES:
|
||||
info_line = lang.err_pam_maxtries;
|
||||
break;
|
||||
case PAM_USER_UNKNOWN:
|
||||
info_line = lang.err_pam_user_unknown;
|
||||
break;
|
||||
case PAM_ACCT_EXPIRED:
|
||||
info_line = lang.err_pam_acct_expired;
|
||||
break;
|
||||
case PAM_NEW_AUTHTOK_REQD:
|
||||
info_line = lang.err_pam_authok_reqd;
|
||||
break;
|
||||
case PAM_PERM_DENIED:
|
||||
info_line = lang.err_pam_perm_denied;
|
||||
break;
|
||||
case PAM_CRED_ERR:
|
||||
info_line = lang.err_pam_cred_err;
|
||||
break;
|
||||
case PAM_CRED_EXPIRED:
|
||||
info_line = lang.err_pam_cred_expired;
|
||||
break;
|
||||
case PAM_CRED_UNAVAIL:
|
||||
info_line = lang.err_pam_cred_unavail;
|
||||
break;
|
||||
case PAM_SESSION_ERR:
|
||||
info_line = lang.err_pam_session;
|
||||
break;
|
||||
case PAM_ABORT:
|
||||
default:
|
||||
info_line = lang.err_pam_abort;
|
||||
break;
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
#ifndef H_CONFIG
|
||||
#define H_CONFIG
|
||||
|
||||
#include "cylgom.h"
|
||||
|
||||
extern char* info_line;
|
||||
|
||||
#define LY_SYSTEMD
|
||||
enum err {OK, ERR, SECURE_RAM, XSESSIONS_MISSING, XSESSIONS_READ, ERR_PERM_GROUP, ERR_PERM_USER, ERR_PERM_DIR};
|
||||
enum display_server {DS_WAYLAND, DS_SHELL, DS_XINITRC, DS_XORG};
|
||||
|
||||
struct lang
|
||||
{
|
||||
char* login;
|
||||
char* password;
|
||||
char* f1;
|
||||
char* f2;
|
||||
char* shell;
|
||||
char* xinitrc;
|
||||
char* logout;
|
||||
char* capslock;
|
||||
char* numlock;
|
||||
|
||||
// errors
|
||||
char* err_pam_buf;
|
||||
char* err_pam_sys;
|
||||
char* err_pam_auth;
|
||||
char* err_pam_cred_insufficient;
|
||||
char* err_pam_authinfo_unavail;
|
||||
char* err_pam_maxtries;
|
||||
char* err_pam_user_unknown;
|
||||
char* err_pam_acct_expired;
|
||||
char* err_pam_authok_reqd;
|
||||
char* err_pam_perm_denied;
|
||||
char* err_pam_cred_err;
|
||||
char* err_pam_cred_expired;
|
||||
char* err_pam_cred_unavail;
|
||||
char* err_pam_session;
|
||||
char* err_pam_abort;
|
||||
char* err_perm_group;
|
||||
char* err_perm_user;
|
||||
char* err_perm_dir;
|
||||
char* err_console_dev;
|
||||
};
|
||||
|
||||
struct config
|
||||
{
|
||||
u32 bg;
|
||||
u32 fg;
|
||||
u16 box_main_w;
|
||||
u16 box_main_h;
|
||||
u16 margin_box_main_h;
|
||||
u16 margin_box_main_v;
|
||||
u16 input_len;
|
||||
u16 max_desktop_len;
|
||||
u16 max_login_len;
|
||||
u16 max_password_len;
|
||||
u16 min_refresh_delta;
|
||||
u16 old_min_refresh_delta;
|
||||
bool blank_box;
|
||||
bool force_update;
|
||||
bool old_force_update;
|
||||
u16 animate;
|
||||
char* xsessions;
|
||||
char* service_name;
|
||||
u16 tty_id;
|
||||
char* x_cmd;
|
||||
char* x_cmd_setup;
|
||||
char* mcookie_cmd;
|
||||
char* xauthority;
|
||||
char* path;
|
||||
char* shutdown_cmd;
|
||||
char* console_dev;
|
||||
u8 tty;
|
||||
bool save;
|
||||
bool load;
|
||||
char* save_file;
|
||||
bool custom_res;
|
||||
u16 res_width;
|
||||
u16 res_height;
|
||||
bool hide_x;
|
||||
char* hide_x_save_log;
|
||||
u8 auth_fails;
|
||||
char* lang;
|
||||
};
|
||||
|
||||
extern struct lang lang;
|
||||
extern struct config config;
|
||||
|
||||
void config_load(const char* file_config);
|
||||
void config_config_free();
|
||||
void config_lang_free();
|
||||
void set_error(enum err error);
|
||||
void pam_diagnose(int error);
|
||||
|
||||
#endif
|
@ -0,0 +1,73 @@
|
||||
#ifndef H_CYLGOM
|
||||
#define H_CYLGOM
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// typedefs for convenience and optimizations
|
||||
|
||||
// 0 to save ram and optimize for embedded systems
|
||||
// 1 to gain extra speed by replacing all floats by doubles
|
||||
// 2 to gain extra speed by using bigger integers depending on arch
|
||||
// level 2 includes *heavy* optimizations that will definitely eat your ram
|
||||
#define SPEED 0
|
||||
|
||||
///////////////////
|
||||
// regular stuff //
|
||||
///////////////////
|
||||
|
||||
// 100% standard
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
|
||||
// float and double are not fixed-size by the C standard
|
||||
// however, the C standard strongly suggests using IEEE 754
|
||||
// in IEEE 754, float is 32 bits and double 64 bits
|
||||
// howevevr, long double is whatever size the compiler prefers
|
||||
// this is why we redefine float and double but not long double
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
///////////////////////////////
|
||||
// black magic optimizations //
|
||||
///////////////////////////////
|
||||
|
||||
// the best optimization out there
|
||||
// doubles are usually slower than floats for various reasons
|
||||
// on embedded systems though, it is usually the opposite
|
||||
#if SPEED > 0
|
||||
typedef f64 f32;
|
||||
#endif
|
||||
|
||||
// the following block tries to optimize speed at the cost of ram
|
||||
// we are testing the architecturee in the most portable way possible
|
||||
// the following macro is not mandatory, obscure systems might not provide it
|
||||
// on 16 bits systems, 16-bit integer operations can be the fastest
|
||||
// on 32 bits systems, 32-bit integer operations can be the fastest
|
||||
// on 64 bits systems, 64-bit integer operations can be the fastest
|
||||
#if SPEED > 1
|
||||
#if UINTPTR_MAX == 0xffff
|
||||
typedef uint16_t u8;
|
||||
typedef int16_t i8;
|
||||
#elif UINTPTR_MAX == 0xffffffff
|
||||
typedef uint32_t u8;
|
||||
typedef int32_t i8;
|
||||
typedef uint32_t u16;
|
||||
typedef int32_t i16;
|
||||
#elif UINTPTR_MAX == 0xffffffffffffffff
|
||||
typedef uint64_t u8;
|
||||
typedef int64_t i8;
|
||||
typedef uint64_t u16;
|
||||
typedef int64_t i16;
|
||||
typedef uint64_t u32;
|
||||
typedef int64_t i32;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,91 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include "desktop.h"
|
||||
#include "cylgom.h"
|
||||
#include "ini.h"
|
||||
#include "widgets.h"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
char* value_name = NULL;
|
||||
char* value_exec = NULL;
|
||||
|
||||
int desktop_handler(void* user, const char* section, const char* name, const char* value)
|
||||
{
|
||||
(void)(user);
|
||||
|
||||
if (strcmp(section, "Desktop Entry") == 0)
|
||||
{
|
||||
if ((strcmp(name, "Name") == 0) && (value_name == NULL))
|
||||
{
|
||||
value_name = strdup(value);
|
||||
}
|
||||
if ((strcmp(name, "Exec") == 0) && (value_exec == NULL))
|
||||
{
|
||||
value_exec = strdup(value);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum err desktop_load(struct desktop* target)
|
||||
{
|
||||
DIR* dir;
|
||||
struct dirent* dir_info;
|
||||
|
||||
#if defined(NAME_MAX)
|
||||
char path[NAME_MAX];
|
||||
#elif defined(_POSIX_PATH_MAX)
|
||||
char path[_POSIX_PATH_MAX];
|
||||
#else
|
||||
char path[1024];
|
||||
#endif
|
||||
|
||||
// checks dir existence
|
||||
if (access(config.xsessions, F_OK) == -1)
|
||||
{
|
||||
return XSESSIONS_MISSING;
|
||||
}
|
||||
|
||||
// requests read access
|
||||
dir = opendir(config.xsessions);
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
return XSESSIONS_READ;
|
||||
}
|
||||
|
||||
// reads the content
|
||||
dir_info = readdir(dir);
|
||||
|
||||
while (dir_info != NULL)
|
||||
{
|
||||
// skips the files starting with "."
|
||||
if ((dir_info->d_name)[0] == '.')
|
||||
{
|
||||
dir_info = readdir(dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(path, (sizeof (path)) - 1, "%s/", config.xsessions);
|
||||
strncat(path, dir_info->d_name, (sizeof (path)) - 1);
|
||||
ini_parse(path, desktop_handler, NULL);
|
||||
|
||||
if ((value_name != NULL) && (value_exec != NULL))
|
||||
{
|
||||
widget_desktop_add(target, value_name, value_exec, DS_XORG);
|
||||
value_name = NULL;
|
||||
value_exec = NULL;
|
||||
}
|
||||
|
||||
dir_info = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return OK;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#ifndef H_DESKTOP
|
||||
|
||||
#include "config.h"
|
||||
#include "widgets.h"
|
||||
|
||||
enum err desktop_load(struct desktop* target);
|
||||
|
||||
#endif
|
@ -0,0 +1,460 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include "draw.h"
|
||||
#include "cylgom.h"
|
||||
#include "termbox.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "widgets.h"
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/vt.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// border chars: ┌ └ ┐ ┘ ─ ─ │ │
|
||||
struct box box_main = {0x250c, 0x2514, 0x2510, 0x2518, 0x2500, 0x2500 ,0x2502, 0x2502};
|
||||
// alternative border chars:
|
||||
// struct box box_main = {'+', '+', '+', '+', '-', '-', '|', '|'};
|
||||
|
||||
u16 width = 0;
|
||||
u16 height = 0;
|
||||
u16 box_main_x = 0;
|
||||
u16 box_main_y = 0;
|
||||
u16 labels_max_len = 0;
|
||||
|
||||
void draw_init()
|
||||
{
|
||||
if (config.custom_res)
|
||||
{
|
||||
width = config.res_width;
|
||||
height = config.res_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = tb_width();
|
||||
height = tb_height();
|
||||
}
|
||||
|
||||
if (info_line == NULL)
|
||||
{
|
||||
hostname(&info_line);
|
||||
}
|
||||
}
|
||||
|
||||
// box outline
|
||||
void draw_box()
|
||||
{
|
||||
box_main_x = ((width - config.box_main_w) / 2);
|
||||
box_main_y = ((height - config.box_main_h) / 2);
|
||||
u16 box_main_x2 = ((width + config.box_main_w) / 2);
|
||||
u16 box_main_y2 = ((height + config.box_main_h) / 2);
|
||||
// corners
|
||||
tb_change_cell(box_main_x - 1,
|
||||
box_main_y - 1,
|
||||
box_main.left_up,
|
||||
config.fg,
|
||||
config.bg);
|
||||
tb_change_cell(box_main_x2 + 1,
|
||||
box_main_y - 1,
|
||||
box_main.right_up,
|
||||
config.fg,
|
||||
config.bg);
|
||||
tb_change_cell(box_main_x - 1,
|
||||
box_main_y2 + 1,
|
||||
box_main.left_down,
|
||||
config.fg,
|
||||
config.bg);
|
||||
tb_change_cell(box_main_x2 + 1,
|
||||
box_main_y2 + 1,
|
||||
box_main.right_down,
|
||||
config.fg,
|
||||
config.bg);
|
||||
|
||||
// top and bottom
|
||||
struct tb_cell c1 = {box_main.top, config.fg, config.bg};
|
||||
struct tb_cell c2 = {box_main.bot, config.fg, config.bg};
|
||||
|
||||
for(u8 i = 0; i <= config.box_main_w; ++i)
|
||||
{
|
||||
tb_put_cell(box_main_x + i,
|
||||
box_main_y - 1,
|
||||
&c1);
|
||||
tb_put_cell(box_main_x + i,
|
||||
box_main_y2 + 1,
|
||||
&c2);
|
||||
}
|
||||
|
||||
// left and right
|
||||
c1.ch = box_main.left;
|
||||
c2.ch = box_main.right;
|
||||
// blank
|
||||
struct tb_cell blank = {' ', config.fg, config.bg};
|
||||
|
||||
for(u8 i = 0; i <= config.box_main_h; ++i)
|
||||
{
|
||||
// testing in the height loop takes less cycles
|
||||
// (I know this is placebo optimization :D)
|
||||
if (config.blank_box)
|
||||
{
|
||||
for (u8 k = 0; k <= config.box_main_w; ++k)
|
||||
{
|
||||
tb_put_cell(box_main_x + k,
|
||||
box_main_y + i,
|
||||
&blank);
|
||||
}
|
||||
}
|
||||
|
||||
tb_put_cell(box_main_x - 1,
|
||||
box_main_y + i,
|
||||
&c1);
|
||||
tb_put_cell(box_main_x2 + 1,
|
||||
box_main_y + i,
|
||||
&c2);
|
||||
}
|
||||
}
|
||||
|
||||
struct tb_cell* strn_cell(char* s, u16 len)
|
||||
{
|
||||
struct tb_cell* cells = malloc((sizeof (struct tb_cell)) * len);
|
||||
char* s2 = s;
|
||||
u32 c;
|
||||
|
||||
if (cells != NULL)
|
||||
{
|
||||
for (u16 i = 0; i < len; ++i)
|
||||
{
|
||||
if ((s2 - s) >= len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
s2 += utf8_char_to_unicode(&c, s2);
|
||||
|
||||
cells[i].ch = c;
|
||||
cells[i].bg = config.bg;
|
||||
cells[i].fg = config.fg;
|
||||
}
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
struct tb_cell* str_cell(char* s)
|
||||
{
|
||||
return strn_cell(s, strlen(s));
|
||||
}
|
||||
|
||||
// input labels
|
||||
void draw_labels()
|
||||
{
|
||||
struct tb_cell* login = str_cell(lang.login);
|
||||
|
||||
tb_blit(box_main_x + config.margin_box_main_h,
|
||||
box_main_y + config.margin_box_main_v + 5,
|
||||
strlen(lang.login),
|
||||
1,
|
||||
login);
|
||||
|
||||
free(login);
|
||||
|
||||
struct tb_cell* password = str_cell(lang.password);
|
||||
|
||||
tb_blit(box_main_x + config.margin_box_main_h,
|
||||
box_main_y + config.margin_box_main_v + 7,
|
||||
strlen(lang.password),
|
||||
1,
|
||||
password);
|
||||
|
||||
free(password);
|
||||
|
||||
labels_max_len = strlen(lang.login);
|
||||
|
||||
if (labels_max_len < strlen(lang.password))
|
||||
{
|
||||
labels_max_len = strlen(lang.password);
|
||||
}
|
||||
|
||||
if (info_line != NULL)
|
||||
{
|
||||
u16 hostname_len = strlen(info_line);
|
||||
struct tb_cell* info_cell = str_cell(info_line);
|
||||
|
||||
tb_blit(box_main_x + ((config.box_main_w - hostname_len) / 2),
|
||||
box_main_y + config.margin_box_main_v,
|
||||
hostname_len,
|
||||
1,
|
||||
info_cell);
|
||||
free(info_cell);
|
||||
}
|
||||
}
|
||||
|
||||
// F1 and F2 labels
|
||||
void draw_f_commands()
|
||||
{
|
||||
struct tb_cell* f1 = str_cell(lang.f1);
|
||||
tb_blit(0, 0, strlen(lang.f1), 1, f1);
|
||||
free(f1);
|
||||
|
||||
struct tb_cell* f2 = str_cell(lang.f2);
|
||||
tb_blit(strlen(lang.f1) + 1, 0, strlen(lang.f2), 1, f2);
|
||||
free(f2);
|
||||
}
|
||||
|
||||
// numlock and capslock info
|
||||
void draw_lock_state()
|
||||
{
|
||||
FILE* console = fopen(config.console_dev, "w");
|
||||
|
||||
if (console == NULL)
|
||||
{
|
||||
info_line = lang.err_console_dev;
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = fileno(console);
|
||||
char ret;
|
||||
|
||||
ioctl(fd, KDGKBLED, &ret);
|
||||
fclose(console);
|
||||
|
||||
u16 pos_x = width - strlen(lang.numlock);
|
||||
|
||||
if (((ret >> 1) & 0x01) == 1)
|
||||
{
|
||||
struct tb_cell* numlock = str_cell(lang.numlock);
|
||||
tb_blit(pos_x, 0, strlen(lang.numlock), 1, numlock);
|
||||
free(numlock);
|
||||
}
|
||||
|
||||
pos_x -= strlen(lang.capslock) + 1;
|
||||
|
||||
if (((ret >> 2) & 0x01) == 1)
|
||||
{
|
||||
struct tb_cell* capslock = str_cell(lang.capslock);
|
||||
tb_blit(pos_x, 0, strlen(lang.capslock), 1, capslock);
|
||||
free(capslock);
|
||||
}
|
||||
}
|
||||
|
||||
// main box
|
||||
void draw_desktop(struct desktop* target)
|
||||
{
|
||||
u16 len = strlen(target->list[target->cur]);
|
||||
|
||||
if (len > (target->visible_len - 3))
|
||||
{
|
||||
len = target->visible_len - 3;
|
||||
}
|
||||
|
||||
tb_change_cell(target->x,
|
||||
target->y,
|
||||
'<',
|
||||
config.fg,
|
||||
config.bg);
|
||||
|
||||
tb_change_cell(target->x + target->visible_len - 1,
|
||||
target->y,
|
||||
'>',
|
||||
config.fg,
|
||||
config.bg);
|
||||
|
||||
for (u16 i = 0; i < len; ++i)
|
||||
{
|
||||
tb_change_cell(target->x + i + 2,
|
||||
target->y,
|
||||
target->list[target->cur][i],
|
||||
config.fg,
|
||||
config.bg);
|
||||
}
|
||||
}
|
||||
|
||||
// classic input
|
||||
void draw_input(struct input* input)
|
||||
{
|
||||
u16 len = strlen(input->text);
|
||||
u16 visible_len = input->visible_len;
|
||||
struct tb_cell* cells;
|
||||
|
||||
if (len > visible_len)
|
||||
{
|
||||
len = visible_len;
|
||||
}
|
||||
|
||||
cells = strn_cell(input->visible_start, len);
|
||||
|
||||
if (cells != NULL)
|
||||
{
|
||||
tb_blit(input->x, input->y, len, 1, cells);
|
||||
free(cells);
|
||||
|
||||
for (u16 i = input->end - input->visible_start; i < visible_len; ++i)
|
||||
{
|
||||
tb_change_cell(input->x + i,
|
||||
input->y,
|
||||
' ',
|
||||
config.fg,
|
||||
config.bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// password input (hidden text)
|
||||
void draw_input_mask(struct input* input)
|
||||
{
|
||||
u16 len = strlen(input->text);
|
||||
u16 visible_len = input->visible_len;
|
||||
|
||||
if (len > visible_len)
|
||||
{
|
||||
len = visible_len;
|
||||
}
|
||||
|
||||
for (u16 i = 0; i < visible_len; ++i)
|
||||
{
|
||||
if (input->visible_start + i < input->end)
|
||||
{
|
||||
tb_change_cell(input->x + i,
|
||||
input->y,
|
||||
'o',
|
||||
config.fg,
|
||||
config.bg);
|
||||
}
|
||||
else
|
||||
{
|
||||
tb_change_cell(input->x + i,
|
||||
input->y,
|
||||
' ',
|
||||
config.fg,
|
||||
config.bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// configures the inputs accroding to the size of the screen
|
||||
void position_input(struct desktop* desktop, struct input* login, struct input* password)
|
||||
{
|
||||
i32 len;
|
||||
u16 x;
|
||||
|
||||
x = box_main_x + config.margin_box_main_h + labels_max_len + 1;
|
||||
len = box_main_x + config.box_main_w - config.margin_box_main_h - x;
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
desktop->x = x;
|
||||
desktop->y = box_main_y + config.margin_box_main_v + 3;
|
||||
desktop->visible_len = len;
|
||||
|
||||
login->x = x;
|
||||
login->y = box_main_y + config.margin_box_main_v + 5;
|
||||
login->visible_len = len;
|
||||
|
||||
password->x = x;
|
||||
password->y = box_main_y + config.margin_box_main_v + 7;
|
||||
password->visible_len = len;
|
||||
}
|
||||
|
||||
// background animations
|
||||
// example implementation
|
||||
void spiral()
|
||||
{
|
||||
static struct timeval time;
|
||||
static uint64_t time_present = 0;
|
||||
static uint64_t time_past = 0;
|
||||
const struct tb_cell c1 = {'o', config.fg, config.bg};
|
||||
static f64 ini = 0;
|
||||
|
||||
gettimeofday(&time, NULL);
|
||||
time_present = time.tv_usec + ((uint64_t) 1000000) * time.tv_sec;
|
||||
|
||||
ini += 2 * M_PI * ((time_present - time_past) / 2000000.0);
|
||||
|
||||
if (ini > (5 * 2 * M_PI))
|
||||
{
|
||||
ini = 0;
|
||||
}
|
||||
|
||||
for (f64 t = 0; t < (5 * 2 * M_PI); t += 0.01)
|
||||
{
|
||||
f64 y = sin(t + ini) * (height / 2) * 0.3 * (t / (2 * M_PI)) * 1.2;
|
||||
f64 x = cos(t + ini) * (width / 2) * 0.2 * (t / (2 * M_PI)) * 1.2;
|
||||
|
||||
tb_put_cell((width / 2) + x, (height / 2) + y, &c1);
|
||||
}
|
||||
|
||||
time_past = time_present;
|
||||
}
|
||||
|
||||
void animate()
|
||||
{
|
||||
switch(config.animate)
|
||||
{
|
||||
case 1:
|
||||
spiral();
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// very important ;)
|
||||
void cascade(u8* fails)
|
||||
{
|
||||
u16 width = tb_width();
|
||||
u16 height = tb_height();
|
||||
struct tb_cell* buf = tb_cell_buffer();
|
||||
char c;
|
||||
char c_under;
|
||||
bool changes = false;
|
||||
|
||||
for (int i = height - 2; i >= 0; --i)
|
||||
{
|
||||
for (int k = 0; k < width; ++k)
|
||||
{
|
||||
c = buf[i * width + k].ch;
|
||||
|
||||
if (isspace(c))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c_under = buf[(i + 1) * width + k].ch;
|
||||
|
||||
if (!isspace(c_under))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!changes)
|
||||
{
|
||||
changes = true;
|
||||
}
|
||||
|
||||
// omg this is not cryptographically secure
|
||||
if (((rand() % 10)) > 7)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
buf[(i + 1) * width + k] = buf[i * width + k];
|
||||
buf[i * width + k].ch = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (!changes)
|
||||
{
|
||||
sleep(7);
|
||||
config.auth_fails = 0;
|
||||
config.min_refresh_delta = config.old_min_refresh_delta;
|
||||
config.force_update = config.old_force_update;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
#ifndef H_DRAW
|
||||
#define H_DRAW
|
||||
|
||||
#include "widgets.h"
|
||||
#include "cylgom.h"
|
||||
|
||||
struct box
|
||||
{
|
||||
u32 left_up;
|
||||
u32 left_down;
|
||||
u32 right_up;
|
||||
u32 right_down;
|
||||
u32 top;
|
||||
u32 bot;
|
||||
u32 left;
|
||||
u32 right;
|
||||
};
|
||||
|
||||
void draw_init();
|
||||
void draw_box();
|
||||
void draw_labels();
|
||||
void draw_f_commands();
|
||||
void draw_lock_state();
|
||||
void draw_desktop(struct desktop* target);
|
||||
void draw_input(struct input* input);
|
||||
void draw_input_mask(struct input* input);
|
||||
void position_input(struct desktop* desktop, struct input* login, struct input* password);
|
||||
void animate();
|
||||
void cascade();
|
||||
|
||||
#endif
|
@ -0,0 +1,66 @@
|
||||
#include "inputs.h"
|
||||
#include "termbox.h"
|
||||
#include "widgets.h"
|
||||
#include "cylgom.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void handle_desktop(void* input_struct, struct tb_event* event)
|
||||
{
|
||||
struct desktop* target = (struct desktop*) input_struct;
|
||||
|
||||
if ((event != NULL) && (event->type == TB_EVENT_KEY))
|
||||
{
|
||||
if (event->key == TB_KEY_ARROW_LEFT)
|
||||
{
|
||||
widget_desktop_move_cur(target, LEFT);
|
||||
}
|
||||
else if (event->key == TB_KEY_ARROW_RIGHT)
|
||||
{
|
||||
widget_desktop_move_cur(target, RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
tb_set_cursor(target->x + 2, target->y);
|
||||
}
|
||||
|
||||
void handle_text(void* input_struct, struct tb_event* event)
|
||||
{
|
||||
struct input* target = (struct input*) input_struct;
|
||||
|
||||
if ((event != NULL) && (event->type == TB_EVENT_KEY))
|
||||
{
|
||||
if (event->key == TB_KEY_ARROW_LEFT)
|
||||
{
|
||||
widget_input_move_cur(target, LEFT);
|
||||
}
|
||||
else if (event->key == TB_KEY_ARROW_RIGHT)
|
||||
{
|
||||
widget_input_move_cur(target, RIGHT);
|
||||
}
|
||||
else if (event->key == TB_KEY_DELETE)
|
||||
{
|
||||
widget_input_delete(target);
|
||||
}
|
||||
else if ((event->key == TB_KEY_BACKSPACE) || (event->key == TB_KEY_BACKSPACE2))
|
||||
{
|
||||
widget_input_backspace(target);
|
||||
}
|
||||
else if (((event->ch > 31) && (event->ch < 127)) || (event->key == TB_KEY_SPACE))
|
||||
{
|
||||
char buf[7] = {0};
|
||||
|
||||
if (event->key == TB_KEY_SPACE)
|
||||
{
|
||||
buf[0] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
utf8_unicode_to_char(buf, event->ch);
|
||||
}
|
||||
|
||||
widget_input_write(target, buf[0]);
|
||||
}
|
||||
}
|
||||
|
||||
tb_set_cursor(target->x + (target->cur - target->visible_start), target->y);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#ifndef H_INPUTS
|
||||
#define H_INPUTS
|
||||
|
||||
#include "termbox.h"
|
||||
|
||||
void handle_text(void* input_struct, struct tb_event* event);
|
||||
void handle_desktop(void* input_struct, struct tb_event* event);
|
||||
|
||||
#endif
|
@ -0,0 +1,456 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#define _DEFAULT_SOURCE
|
||||
|
||||
#include "config.h"
|
||||
#include "login.h"
|
||||
#include "widgets.h"
|
||||
#include "desktop.h"
|
||||
#include "termbox.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_misc.h>
|
||||
|
||||
#ifdef LY_SYSTEMD
|
||||
#define PAM_SYSTEMD
|
||||
#endif
|
||||
|
||||
#include <security/pam_modules.h>
|
||||
#include <security/pam_modutil.h>
|
||||
|
||||
int login_conv(int num_msg, const struct pam_message** msg,
|
||||
struct pam_response** resp, void* appdata_ptr)
|
||||
{
|
||||
int i;
|
||||
int result = PAM_SUCCESS;
|
||||
|
||||
if(!(*resp = calloc(num_msg, sizeof(struct pam_response))))
|
||||
{
|
||||
return PAM_BUF_ERR;
|
||||
}
|
||||
|
||||
for(i = 0; i < num_msg; i++)
|
||||
{
|
||||
char* username, *password;
|
||||
|
||||
switch(msg[i]->msg_style)
|
||||
{
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
username = ((char**) appdata_ptr)[0];
|
||||
(*resp)[i].resp = strdup(username);
|
||||
break;
|
||||
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
password = ((char**) appdata_ptr)[1];
|
||||
(*resp)[i].resp = strdup(password);
|
||||
break;
|
||||
|
||||
case PAM_ERROR_MSG:
|
||||
fprintf(stderr, "%s\n", msg[i]->msg);
|
||||
result = PAM_CONV_ERR;
|
||||
break;
|
||||
|
||||
case PAM_TEXT_INFO:
|
||||
printf("%s\n", msg[i]->msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if(result != PAM_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(result != PAM_SUCCESS)
|
||||
{
|
||||
free(*resp);
|
||||
*resp = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int get_free_display()
|
||||
{
|
||||
int i;
|
||||
char xlock[256];
|
||||
|
||||
for(i = 0; i < 200; ++i)
|
||||
{
|
||||
snprintf(xlock, sizeof(xlock), "/tmp/.X%d-lock", i);
|
||||
|
||||
if(access(xlock, F_OK) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
enum err init_env(pam_handle_t* handle, struct passwd* pw)
|
||||
{
|
||||
u16 i;
|
||||
u16 len;
|
||||
char tmp[256];
|
||||
char** env;
|
||||
char* termenv;
|
||||
|
||||
termenv = getenv("TERM");
|
||||
setenv("HOME", pw->pw_dir, 0);
|
||||
setenv("USER", pw->pw_name, 1);
|
||||
setenv("SHELL", pw->pw_shell, 1);
|
||||
setenv("LOGNAME", pw->pw_name, 1);
|
||||
|
||||
|
||||
if (termenv)
|
||||
{
|
||||
setenv("TERM", termenv, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setenv("TERM", "linux", 1);
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", pw->pw_dir, config.xauthority);
|
||||
setenv("XAUTHORITY", tmp, 0);
|
||||
len = snprintf(tmp, sizeof(tmp), "%s/%s", _PATH_MAILDIR, pw->pw_name);
|
||||
|
||||
if ((len > 0) && ((size_t) len < sizeof(tmp)))
|
||||
{
|
||||
setenv("MAIL", tmp, 0);
|
||||
}
|
||||
|
||||
if (setenv("PATH", config.path, 1))
|
||||
{
|
||||
return ERR;
|
||||
}
|
||||
|
||||
env = pam_getenvlist(handle);
|
||||
|
||||
for (i = 0; env && env[i]; i++)
|
||||
{
|
||||
putenv(env[i]);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void init_xdg(const char* tty_id, const char* display_name,
|
||||
enum display_server display_server)
|
||||
{
|
||||
setenv("XDG_SESSION_CLASS", "user", 0);
|
||||
setenv("XDG_SEAT", "seat0", 0);
|
||||
setenv("XDG_VTNR", tty_id, 0);
|
||||
setenv("DISPLAY", display_name, 1);
|
||||
|
||||
switch(display_server)
|
||||
{
|
||||
case DS_SHELL:
|
||||
setenv("XDG_SESSION_TYPE", "tty", 0);
|
||||
break;
|
||||
case DS_WAYLAND:
|
||||
setenv("XDG_SESSION_TYPE", "wayland", 0);
|
||||
break;
|
||||
case DS_XINITRC:
|
||||
case DS_XORG:
|
||||
setenv("XDG_SESSION_TYPE", "x11", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reset_terminal(struct passwd* pwd)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
char cmd[256];
|
||||
|
||||
pid = fork();
|
||||
strncpy(cmd, "exec tput reset", sizeof(cmd));
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
execl(pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
}
|
||||
|
||||
void launch_wayland(struct passwd* pwd, pam_handle_t* pam_handle,
|
||||
const char* de_command)
|
||||
{
|
||||
char cmd[32];
|
||||
snprintf(cmd, 32, "exec %s", de_command);
|
||||
reset_terminal(pwd);
|
||||
execl(pwd->pw_shell, pwd->pw_shell, "-l", "-c", cmd, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void launch_shell(struct passwd* pwd, pam_handle_t* pam_handle)
|
||||
{
|
||||
char* pos;
|
||||
char args[256 + 2]; // arbitrary
|
||||
args[0] = '-';
|
||||
strncpy(args + 1, ((pos = strrchr(pwd->pw_shell,
|
||||
'/')) ? pos + 1 : pwd->pw_shell), sizeof(args) - 1);
|
||||
reset_terminal(pwd);
|
||||
execl(pwd->pw_shell, args, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void launch_xorg(struct passwd* pwd, pam_handle_t* pam_handle,
|
||||
const char* de_command, const char* display_name, const char* vt,
|
||||
int xinitrc)
|
||||
{
|
||||
FILE* file;
|
||||
pid_t child;
|
||||
int status;
|
||||
char cmd[256];
|
||||
|
||||
// updates cookie
|
||||
snprintf(cmd,
|
||||
sizeof(cmd),
|
||||
"exec xauth add %s . `%s`",
|
||||
display_name,
|
||||
config.mcookie_cmd);
|
||||
|
||||
file = fopen(getenv("XAUTHORITY"), "ab+");
|
||||
fclose(file);
|
||||
|
||||
// generates the cookie
|
||||
child = fork();
|
||||
|
||||
if(child == 0)
|
||||
{
|
||||
execl(pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
// starts x
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"exec xinit %s %s%s -- %s %s %s %s %s %s -auth %s",
|
||||
config.x_cmd_setup,
|
||||
xinitrc ? "" : "/usr/bin/",
|
||||
de_command, config.x_cmd,
|
||||
config.hide_x ? "-keeptty >" : "",
|
||||
config.hide_x ? config.hide_x_save_log : "",
|
||||
config.hide_x ? "2>&1" : "",
|
||||
display_name, vt, getenv("XAUTHORITY"));
|
||||
reset_terminal(pwd);
|
||||
execl(pwd->pw_shell, pwd->pw_shell, "-l", "-c", cmd, NULL);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
enum err login_desktop(struct desktop* desktop,
|
||||
struct input* login,
|
||||
struct input* password)
|
||||
{
|
||||
int display_id;
|
||||
char display_name[3];
|
||||
pid_t display_pid;
|
||||
int display_status;
|
||||
|
||||
const char* creds[2] = {login->text, password->text};
|
||||
struct pam_conv conv = {login_conv, creds};
|
||||
struct passwd* pwd = NULL;
|
||||
pam_handle_t* handle;
|
||||
int pam_result;
|
||||
|
||||
enum display_server display_server = desktop->display_server[desktop->cur];
|
||||
char tty_id [3];
|
||||
char vt[5];
|
||||
|
||||
display_id = get_free_display();
|
||||
snprintf(display_name, sizeof(display_name), ":%d", display_id);
|
||||
snprintf(tty_id, sizeof(tty_id), "%d", config.tty_id);
|
||||
snprintf(vt, sizeof(vt), "vt%d", config.tty_id);
|
||||
|
||||
// starting pam transations
|
||||
pam_result = pam_start(config.service_name, login->text, &conv, &handle);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
pam_result = pam_authenticate(handle, 0);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
pam_result = pam_acct_mgmt(handle, 0);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
// initializes user groups
|
||||
struct passwd* pw = getpwnam(login->text);
|
||||
|
||||
if (!pw)
|
||||
{
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
int grp_result = initgroups(login->text, pw->pw_gid);
|
||||
|
||||
if (grp_result == -1)
|
||||
{
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
// back to pam transactions
|
||||
pam_result = pam_setcred(handle, PAM_ESTABLISH_CRED);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
pam_result = pam_open_session(handle, 0);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
// login error
|
||||
if (handle == NULL)
|
||||
{
|
||||
return ERR;
|
||||
}
|
||||
|
||||
pwd = getpwnam(login->text);
|
||||
|
||||
// clears the password in memory
|
||||
widget_input_free(password);
|
||||
widget_input(password, config.max_password_len);
|
||||
|
||||
// launches the DE
|
||||
display_pid = fork();
|
||||
|
||||
if (display_pid == 0)
|
||||
{
|
||||
// restores regular terminal mode
|
||||
// doing this here to enable post-return cleanup
|
||||
tb_clear();
|
||||
tb_present();
|
||||
tb_shutdown();
|
||||
|
||||
// initialization
|
||||
clearenv();
|
||||
init_xdg(tty_id, display_name, display_server);
|
||||
|
||||
// downgrades group permissions
|
||||
if ((pwd == NULL) || (setgid(pwd->pw_gid) < 0))
|
||||
{
|
||||
set_error(ERR_PERM_GROUP);
|
||||
pam_end(handle, pam_result);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
init_env(handle, pwd);
|
||||
|
||||
// downgrades user permissions
|
||||
if (setuid(pwd->pw_uid) < 0)
|
||||
{
|
||||
set_error(ERR_PERM_USER);
|
||||
pam_end(handle, pam_result);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (chdir(pwd->pw_dir) < 0)
|
||||
{
|
||||
set_error(ERR_PERM_DIR);
|
||||
pam_end(handle, pam_result);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
switch (display_server)
|
||||
{
|
||||
case DS_SHELL:
|
||||
launch_shell(pwd, handle);
|
||||
break;
|
||||
case DS_WAYLAND:
|
||||
launch_wayland(pwd, handle, desktop->cmd[desktop->cur]);
|
||||
break;
|
||||
case DS_XORG:
|
||||
launch_xorg(pwd, handle, desktop->cmd[desktop->cur],
|
||||
display_name, vt, 0);
|
||||
break;
|
||||
case DS_XINITRC:
|
||||
launch_xorg(pwd, handle, desktop->cmd[desktop->cur],
|
||||
display_name, vt, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// waits for the de/shell to exit
|
||||
waitpid(display_pid, &display_status, 0);
|
||||
|
||||
tb_init();
|
||||
tb_select_output_mode(TB_OUTPUT_TRUECOLOR);
|
||||
|
||||
// reloads the desktop environment list on logout
|
||||
widget_desktop_free(desktop);
|
||||
widget_desktop(desktop);
|
||||
desktop_load(desktop);
|
||||
|
||||
info_line = lang.logout;
|
||||
pam_result = pam_close_session(handle, 0);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
pam_result = pam_setcred(handle, PAM_DELETE_CRED);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
pam_result = pam_end(handle, pam_result);
|
||||
|
||||
if (pam_result != PAM_SUCCESS)
|
||||
{
|
||||
pam_diagnose(pam_result);
|
||||
pam_end(handle, pam_result);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#ifndef H_LOGIN
|
||||
#define H_LOGIN
|
||||
|
||||
#include "config.h"
|
||||
#include "widgets.h"
|
||||
|
||||
enum err login_desktop(struct desktop* desktop, struct input* login, struct input* password);
|
||||
|
||||
#endif
|
@ -0,0 +1,179 @@
|
||||
#include "cylgom.h"
|
||||
#include "termbox.h"
|
||||
#include "draw.h"
|
||||
#include "desktop.h"
|
||||
#include "config.h"
|
||||
#include "inputs.h"
|
||||
#include "login.h"
|
||||
#include "util.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
enum active_input {INPUT_DESKTOP, INPUT_LOGIN, INPUT_PASSWORD};
|
||||
enum shutdown {SHUTDOWN_NO, SHUTDOWN_YES, SHUTDOWN_REBOOT};
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
struct desktop desktop;
|
||||
struct input login;
|
||||
struct input password;
|
||||
struct tb_event event;
|
||||
enum shutdown shutdown = SHUTDOWN_NO;
|
||||
enum active_input active_input;
|
||||
enum err error = OK;
|
||||
enum err status;
|
||||
|
||||
void* input_structs[3] =
|
||||
{
|
||||
(void*) &desktop,
|
||||
(void*) &login,
|
||||
(void*) &password
|
||||
};
|
||||
|
||||
void (*input_handles[3]) (void*, struct tb_event*) =
|
||||
{
|
||||
handle_desktop,
|
||||
handle_text,
|
||||
handle_text
|
||||
};
|
||||
|
||||
active_input = INPUT_PASSWORD;
|
||||
config_load("/etc/ly/config.ini");
|
||||
|
||||
widget_desktop(&desktop);
|
||||
widget_input(&login, config.max_login_len);
|
||||
widget_input(&password, config.max_password_len);
|
||||
|
||||
desktop_load(&desktop);
|
||||
|
||||
tb_init();
|
||||
tb_select_output_mode(TB_OUTPUT_TRUECOLOR);
|
||||
tb_clear();
|
||||
|
||||
draw_init();
|
||||
draw_box();
|
||||
draw_labels();
|
||||
draw_f_commands();
|
||||
draw_lock_state();
|
||||
|
||||
position_input(&desktop, &login, &password);
|
||||
load(&desktop, &login);
|
||||
draw_desktop(&desktop);
|
||||
draw_input(&login);
|
||||
draw_input_mask(&password);
|
||||
|
||||
(*input_handles[active_input])(input_structs[active_input], NULL);
|
||||
|
||||
tb_present();
|
||||
|
||||
switch_tty();
|
||||
|
||||
bool run = true;
|
||||
|
||||
while (run)
|
||||
{
|
||||
error = tb_peek_event(&event, config.min_refresh_delta);
|
||||
|
||||
if (error < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (event.type == TB_EVENT_KEY)
|
||||
{
|
||||
if (event.key == TB_KEY_F1)
|
||||
{
|
||||
shutdown = SHUTDOWN_YES;
|
||||
break;
|
||||
}
|
||||
else if (event.key == TB_KEY_F2)
|
||||
{
|
||||
shutdown = SHUTDOWN_REBOOT;
|
||||
break;
|
||||
}
|
||||
else if (event.key == TB_KEY_CTRL_C)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if ((event.key == TB_KEY_ARROW_UP) && (active_input > 0))
|
||||
{
|
||||
--active_input;
|
||||
}
|
||||
else if (((event.key == TB_KEY_ARROW_DOWN) || (event.key == TB_KEY_ENTER))
|
||||
&& (active_input < 2))
|
||||
{
|
||||
++active_input;
|
||||
}
|
||||
else if (event.key == TB_KEY_ENTER)
|
||||
{
|
||||
save(&desktop, &login);
|
||||
status = login_desktop(&desktop, &login, &password);
|
||||
load(&desktop, &login);
|
||||
error = 1; // triggers cursor and screen update
|
||||
|
||||
if (status != OK)
|
||||
{
|
||||
++config.auth_fails;
|
||||
config.old_min_refresh_delta = config.min_refresh_delta;
|
||||
config.old_force_update = config.force_update;
|
||||
config.min_refresh_delta = 10;
|
||||
config.force_update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error > 0)
|
||||
{
|
||||
// calls the apropriate function depending on the active input
|
||||
(*input_handles[active_input])(input_structs[active_input], &event);
|
||||
}
|
||||
|
||||
if (config.force_update || (error > 0))
|
||||
{
|
||||
if (config.auth_fails < 10)
|
||||
{
|
||||
tb_clear();
|
||||
|
||||
draw_init();
|
||||
animate();
|
||||
draw_box();
|
||||
draw_labels();
|
||||
draw_f_commands();
|
||||
draw_lock_state();
|
||||
|
||||
position_input(&desktop, &login, &password);
|
||||
draw_desktop(&desktop);
|
||||
draw_input(&login);
|
||||
draw_input_mask(&password);
|
||||
}
|
||||
else
|
||||
{
|
||||
cascade();
|
||||
}
|
||||
}
|
||||
|
||||
tb_present();
|
||||
}
|
||||
|
||||
// TODO error
|
||||
tb_shutdown();
|
||||
|
||||
widget_desktop_free(&desktop);
|
||||
widget_input_free(&login);
|
||||
widget_input_free(&password);
|
||||
config_lang_free();
|
||||
free_hostname();
|
||||
|
||||
if (shutdown == SHUTDOWN_YES)
|
||||
{
|
||||
execl(config.shutdown_cmd, config.shutdown_cmd, "-h", "now", NULL);
|
||||
}
|
||||
if (shutdown == SHUTDOWN_REBOOT)
|
||||
{
|
||||
execl(config.shutdown_cmd, config.shutdown_cmd, "-r", "now", NULL);
|
||||
}
|
||||
|
||||
config_config_free();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
#include "widgets.h"
|
||||
#include "cylgom.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// hostname
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/vt.h>
|
||||
|
||||
char* hostname_backup;
|
||||
|
||||
void hostname(char** out)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo* info;
|
||||
char hostname[HOST_NAME_MAX + 1];
|
||||
char* dot;
|
||||
int result;
|
||||
|
||||
hostname[HOST_NAME_MAX] = '\0';
|
||||
gethostname(hostname, HOST_NAME_MAX);
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
result = getaddrinfo(hostname, "http", &hints, &info);
|
||||
|
||||
if ((result == 0) && (info != NULL))
|
||||
{
|
||||
dot = strchr(info->ai_canonname, '.');
|
||||
*out = strndup(info->ai_canonname, dot - info->ai_canonname);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = strdup("");
|
||||
}
|
||||
|
||||
hostname_backup = *out;
|
||||
freeaddrinfo(info);
|
||||
}
|
||||
|
||||
void free_hostname()
|
||||
{
|
||||
free(hostname_backup);
|
||||
}
|
||||
|
||||
void switch_tty()
|
||||
{
|
||||
FILE* console = fopen(config.console_dev, "w");
|
||||
|
||||
if (console == NULL)
|
||||
{
|
||||
info_line = lang.err_console_dev;
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = fileno(console);
|
||||
|
||||
ioctl(fd, VT_ACTIVATE, config.tty);
|
||||
ioctl(fd, VT_WAITACTIVE, config.tty);
|
||||
|
||||
fclose(console);
|
||||
}
|
||||
|
||||
void save(struct desktop* desktop, struct input* login)
|
||||
{
|
||||
if (config.save)
|
||||
{
|
||||
FILE* file = fopen(config.save_file, "wb+");
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
fprintf(file, "%s\n%d", login->text, desktop->cur);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load(struct desktop* desktop, struct input* login)
|
||||
{
|
||||
if (config.load == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* file = fopen(config.save_file, "rb");
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char* line = malloc((config.max_login_len * (sizeof (char))) + 1);
|
||||
|
||||
if (line == NULL)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgets(line, (config.max_login_len * (sizeof (char))) + 1, file))
|
||||
{
|
||||
strncpy(login->text, line, login->len);
|
||||
|
||||
int len = strlen(line);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
login->end = login->text;
|
||||
}
|
||||
else
|
||||
{
|
||||
login->end = login->text + len - 1;
|
||||
login->text[len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(file);
|
||||
free(line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgets(line, (config.max_login_len * (sizeof (char))) + 1, file))
|
||||
{
|
||||
int saved_cur = abs(atoi(line));
|
||||
|
||||
if (saved_cur < desktop->len)
|
||||
{
|
||||
desktop->cur = saved_cur;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
free(line);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
#ifndef H_UTIL
|
||||
#define H_UTIL
|
||||
|
||||
#include "widgets.h"
|
||||
|
||||
void hostname(char** out);
|
||||
void free_hostname();
|
||||
void switch_tty();
|
||||
void save(struct desktop* desktop, struct input* login);
|
||||
void load(struct desktop* desktop, struct input* login);
|
||||
|
||||
#endif
|
@ -0,0 +1,184 @@
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include "widgets.h"
|
||||
#include "cylgom.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
enum err widget_desktop(struct desktop* target)
|
||||
{
|
||||
enum err error = OK;
|
||||
|
||||
// one default slot for the shell
|
||||
target->list = NULL;
|
||||
target->cmd = NULL;
|
||||
target->display_server = NULL;
|
||||
target->cur = 0;
|
||||
target->len = 0;
|
||||
|
||||
error |= widget_desktop_add(target, strdup(lang.shell), strdup(""), DS_SHELL);
|
||||
error |= widget_desktop_add(target, strdup(lang.xinitrc), strdup(""), DS_XINITRC);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
enum err widget_input(struct input* target, u64 len)
|
||||
{
|
||||
enum err error = OK;
|
||||
int ret;
|
||||
|
||||
target->text = malloc(len + 1);
|
||||
|
||||
if (target->text == NULL)
|
||||
{
|
||||
error = ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// lock inputs memory so it won't swap and leak the password
|
||||
// probably not relevant as most software is insecure as hell,
|
||||
// but hey are we trying to write good code or not?
|
||||
ret = mlock(target->text, len + 1);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
error = SECURE_RAM;
|
||||
}
|
||||
|
||||
memset(target->text, 0, len + 1);
|
||||
}
|
||||
|
||||
target->cur = target->text;
|
||||
target->end = target->text;
|
||||
target->visible_start = target->text;
|
||||
target->len = len;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void widget_desktop_free(struct desktop* target)
|
||||
{
|
||||
if (target != NULL)
|
||||
{
|
||||
for (u16 i = 0; i < target->len; ++i)
|
||||
{
|
||||
if (target->list[i] != NULL)
|
||||
{
|
||||
free(target->list[i]);
|
||||
}
|
||||
if (target->cmd[i] != NULL)
|
||||
{
|
||||
free(target->cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(target->list);
|
||||
free(target->cmd);
|
||||
free(target->display_server);
|
||||
}
|
||||
}
|
||||
|
||||
void widget_input_free(struct input* target)
|
||||
{
|
||||
// wipes the passord from memory and
|
||||
// restores the buffer's address as swappable
|
||||
memset(target->text, 0, target->len);
|
||||
munlock(target->text, target->len + 1);
|
||||
free(target->text);
|
||||
}
|
||||
|
||||
void widget_desktop_move_cur(struct desktop* target, enum direction dest)
|
||||
{
|
||||
if ((dest == RIGHT) && (target->cur < (target->len - 1)))
|
||||
{
|
||||
++(target->cur);
|
||||
}
|
||||
|
||||
if ((dest == LEFT) && (target->cur > 0))
|
||||
{
|
||||
--(target->cur);
|
||||
}
|
||||
}
|
||||
|
||||
enum err widget_desktop_add(struct desktop* target, char* name, char* cmd, enum display_server display_server)
|
||||
{
|
||||
++(target->len);
|
||||
target->list = realloc(target->list, target->len * (sizeof (char*)));
|
||||
target->cmd = realloc(target->cmd, target->len * (sizeof (char*)));
|
||||
target->display_server = realloc(target->display_server, target->len * (sizeof (enum display_server)));
|
||||
target->cur = target->len - 1;
|
||||
|
||||
if ((target->list == NULL)
|
||||
|| (target->cmd == NULL)
|
||||
|| (target->display_server == NULL))
|
||||
{
|
||||
return ERR;
|
||||
}
|
||||
|
||||
target->list[target->cur] = name;
|
||||
target->cmd[target->cur] = cmd;
|
||||
target->display_server[target->cur] = display_server;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void widget_input_move_cur(struct input* target, enum direction dest)
|
||||
{
|
||||
if ((dest == RIGHT) && (target->cur < target->end))
|
||||
{
|
||||
++(target->cur);
|
||||
|
||||
if ((target->cur - target->visible_start) > target->visible_len)
|
||||
{
|
||||
++(target->visible_start);
|
||||
}
|
||||
}
|
||||
|
||||
if ((dest == LEFT) && (target->cur > target->text))
|
||||
{
|
||||
--(target->cur);
|
||||
|
||||
if ((target->cur - target->visible_start) < 0)
|
||||
{
|
||||
--(target->visible_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void widget_input_write(struct input* target, char ascii)
|
||||
{
|
||||
if (ascii <= 0)
|
||||
{
|
||||
return; // unices do not support usernames and passwords other than ascii
|
||||
}
|
||||
|
||||
if ((target->end - target->text + 1) < target->len)
|
||||
{
|
||||
// moves the text on the right to add space for the new ascii char
|
||||
memcpy(target->cur + 1, target->cur, target->end - target->cur);
|
||||
++(target->end);
|
||||
// adds the new char and moves the cursor to the right
|
||||
*(target->cur) = ascii;
|
||||
widget_input_move_cur(target, RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
void widget_input_delete(struct input* target)
|
||||
{
|
||||
if (target->cur < target->end)
|
||||
{
|
||||
// moves the text on the right to overwrite the currently pointed char
|
||||
memcpy(target->cur, target->cur + 1, target->end - target->cur + 1);
|
||||
--(target->end);
|
||||
}
|
||||
}
|
||||
|
||||
void widget_input_backspace(struct input* target)
|
||||
{
|
||||
if (target->cur > target->text)
|
||||
{
|
||||
widget_input_move_cur(target, LEFT);
|
||||
widget_input_delete(target);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
#ifndef H_WIDGETS
|
||||
#define H_WIDGETS
|
||||
|
||||
#include "cylgom.h"
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
enum direction {LEFT, RIGHT};
|
||||
|
||||
struct input
|
||||
{
|
||||
char* text;
|
||||
char* end;
|
||||
u64 len;
|
||||
|
||||
char* cur;
|
||||
char* visible_start;
|
||||
u16 visible_len;
|
||||
|
||||
u16 x;
|
||||
u16 y;
|
||||
};
|
||||
|
||||
struct desktop
|
||||
{
|
||||
char** list;
|
||||
char** cmd;
|
||||
enum display_server* display_server;
|
||||
|
||||
u16 cur;
|
||||
u16 len;
|
||||
u16 visible_len;
|
||||
|
||||
u16 x;
|
||||
u16 y;
|
||||
};
|
||||
|
||||
enum err widget_desktop(struct desktop* target);
|
||||
enum err widget_input(struct input* target, u64 len);
|
||||
void widget_desktop_free(struct desktop* target);
|
||||
void widget_input_free(struct input* target);
|
||||
void widget_desktop_move_cur(struct desktop* target, enum direction dest);
|
||||
enum err widget_desktop_add(struct desktop* target, char* name, char* cmd, enum display_server display_server);
|
||||
void widget_input_move_cur(struct input* target, enum direction dest);
|
||||
void widget_input_write(struct input* target, char ascii);
|
||||
void widget_input_delete(struct input* target);
|
||||
void widget_input_backspace(struct input* target);
|
||||
|
||||
#endif
|
@ -0,0 +1 @@
|
||||
Subproject commit 0ee2bf26abccc63ee0a5a416ed9cdf4d113d8c25
|
@ -0,0 +1 @@
|
||||
Subproject commit 467501d0fc3c4bd6889af54a62d2ff7580325444
|
Loading…
Reference in New Issue