diff options
38 files changed, 3520 insertions, 63 deletions
@@ -1,10 +1,32 @@ | |||
1 | .version | ||
2 | |||
3 | aclocal.m4 | ||
4 | autom4te.cache/ | ||
5 | build-aux/ | ||
6 | |||
7 | config.log | ||
8 | config.status | ||
9 | configure | ||
10 | configure~ | ||
11 | |||
12 | libtool | ||
13 | m4/ | ||
14 | |||
15 | Makefile.in | ||
16 | Makefile | ||
17 | |||
1 | # IDE specific files: | 18 | # IDE specific files: |
2 | .cproject | 19 | .cproject |
3 | .project | 20 | .project |
4 | .settings/ | 21 | .settings/ |
22 | .cache/ | ||
23 | .vscode/ | ||
5 | 24 | ||
6 | # Binary files: | 25 | # Binary files: |
7 | *.o | 26 | *.o |
8 | 27 | ||
9 | # Application file: | 28 | # Application file: |
10 | messenger-cli | 29 | messenger-cli |
30 | |||
31 | # Tar files | ||
32 | messenger-cli-*.tar.gz | ||
@@ -1 +1,2 @@ | |||
1 | Tobias Frisch <thejackimonster@gmail.com> | 1 | Tobias Frisch <thejackimonster@gmail.com> |
2 | Marcos Marado <mindboosternoori@gmail.com> | ||
diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..ef9fb5e --- /dev/null +++ b/ChangeLog | |||
@@ -0,0 +1,10 @@ | |||
1 | ## Version 0.1.1 | ||
2 | * Replaces build system finally with Meson increasing platform support | ||
3 | * Fixes issues regarding changes in header usage from GNUnet 0.19.0 | ||
4 | |||
5 | ## Version 0.1.0 | ||
6 | * It is possible to create direct chats and group chats via lobbies, shared keys or invitations | ||
7 | * Members of a chats can be observed | ||
8 | * Chats allow sending text messages or files | ||
9 | * Messages can be deleted in any chat locally | ||
10 | * Switching between different accounts can be done during runtime | ||
diff --git a/Makefile b/Makefile deleted file mode 100644 index 364c1fc..0000000 --- a/Makefile +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | |||
2 | SOURCE_DIR = src/ | ||
3 | INSTALL_DIR = /usr/local/ | ||
4 | |||
5 | BINARY = messenger-cli | ||
6 | SOURCES = messenger_cli.c | ||
7 | HEADERS = | ||
8 | |||
9 | LIBRARIES = gnunetchat | ||
10 | |||
11 | CC = gcc | ||
12 | LD = gcc | ||
13 | RM = rm | ||
14 | |||
15 | CFLAGS = -pedantic -Wall -Wextra -march=native -ggdb3 | ||
16 | LDFLAGS = | ||
17 | |||
18 | DEBUGFLAGS = -O0 -D _DEBUG | ||
19 | RELEASEFLAGS = -O2 -D NDEBUG -fwhole-program | ||
20 | |||
21 | SOURCE_FILES = $(addprefix $(SOURCE_DIR), $(SOURCES)) | ||
22 | OBJECT_FILES = $(SOURCE_FILES:%.c=%.o) | ||
23 | HEADER_FILES = $(addprefix $(SOURCE_DIR), $(HEADERS)) | ||
24 | LIBRARY_FLAGS = $(addprefix -l, $(LIBRARIES)) | ||
25 | |||
26 | all: $(BINARY) | ||
27 | |||
28 | debug: CFLAGS += $(DEBUGFLAGS) | ||
29 | debug: $(BINARY) | ||
30 | |||
31 | release: CFLAGS += $(RELEASEFLAGS) | ||
32 | release: $(BINARY) | ||
33 | |||
34 | %.o: %.c | ||
35 | $(CC) $(CFLAGS) -c $< -o $@ $(LIBRARY_FLAGS) | ||
36 | |||
37 | $(BINARY): $(OBJECT_FILES) | ||
38 | $(LD) $(LDFLAGS) $^ -o $@ $(LIBRARY_FLAGS) | ||
39 | |||
40 | .PHONY: install | ||
41 | |||
42 | install: | ||
43 | install -m 755 $(BINARY) $(addprefix $(INSTALL_DIR), bin/) | ||
44 | |||
45 | .PHONY: uninstall | ||
46 | |||
47 | uninstall: | ||
48 | $(RM) -f $(addsuffix $(BINARY), $(addprefix $(INSTALL_DIR), bin/)) | ||
49 | |||
50 | .PHONY: clean | ||
51 | |||
52 | clean: | ||
53 | $(RM) -f $(BINARY) | ||
54 | $(RM) -f $(OBJECT_FILES) \ No newline at end of file | ||
@@ -2,8 +2,51 @@ | |||
2 | 2 | ||
3 | A CLI for the Messenger service of GNUnet. | 3 | A CLI for the Messenger service of GNUnet. |
4 | 4 | ||
5 | ## (Planned) Dependencies | 5 | ``` |
6 | |||
7 | o o | ||
8 | ooo oo | ||
9 | ooooo ooooo | ||
10 | oo ooo | ||
11 | oo ooo | ||
12 | ooooooo | ||
13 | oooooo | ||
14 | oooo | ||
15 | |||
16 | |||
17 | ``` | ||
18 | |||
19 | ## Build & Installation | ||
20 | |||
21 | The following dependencies are required and need to be installed to build the application: | ||
22 | |||
23 | - [gnunet](https://git.gnunet.org/gnunet.git/): For using general GNUnet datatypes | ||
24 | - [libgnunetchat](https://git.gnunet.org/libgnunetchat.git/): For chatting via GNUnet messenger | ||
25 | - [ncurses](https://www.gnu.org/software/ncurses/): For the general UI visualization | ||
26 | |||
27 | Then you can simply use [Meson](https://mesonbuild.com/) as follows: | ||
28 | ``` | ||
29 | meson build # Configure the build files for your system | ||
30 | ninja -C build # Build the application using those build files | ||
31 | ninja -C build install # Install the application | ||
32 | ``` | ||
33 | |||
34 | Here is a list of some useful build commands using Meson and [Ninja](https://ninja-build.org/): | ||
35 | |||
36 | - `meson compile -C build` to just compile everything with configured parameters | ||
37 | - `rm -r build` to cleanup build files in case you want to recompile | ||
38 | - `meson install -C build` to install the compiled files (you might need sudo permissions to install) | ||
39 | - `meson dist -C build` to create a tar file for distribution | ||
40 | |||
41 | If you want to change the installation location, use the `--prefix=` parameter in the initial meson command. Also you can enable optimized release builds by adding `--buildtype=release` as parameter. | ||
42 | |||
43 | ## Contribution | ||
44 | |||
45 | If you want to contribute to this project as well, the following options are available: | ||
46 | |||
47 | - Contribute directly to the [source code](https://git.gnunet.org/messenger-cli.git/) with patches to fix issues, implement new features or improve the usability. | ||
48 | - Open issues in the [bug tracker](https://bugs.gnunet.org/bug_report_page.php) to report bugs, issues or missing features. | ||
49 | - Contact the authors of the software if you need any help to contribute (testing is always an option). | ||
50 | |||
51 | The list of all previous authors can be viewed in the provided [file](AUTHORS). | ||
6 | 52 | ||
7 | - [gnunet](https://git.gnunet.org/gnunet.git/) | ||
8 | - [libgnunetchat](https://git.gnunet.org/libgnunetchat.git/) | ||
9 | - [ncurses](https://www.gnu.org/software/ncurses/) | ||
diff --git a/contrib/distribute_version.sh b/contrib/distribute_version.sh new file mode 100644 index 0000000..110d311 --- /dev/null +++ b/contrib/distribute_version.sh | |||
@@ -0,0 +1,4 @@ | |||
1 | #!/bin/sh | ||
2 | VERSION=$1 | ||
3 | cd "${MESON_DIST_ROOT}" | ||
4 | echo $VERSION > .version \ No newline at end of file | ||
diff --git a/contrib/get_version.sh b/contrib/get_version.sh new file mode 100644 index 0000000..2a41ed4 --- /dev/null +++ b/contrib/get_version.sh | |||
@@ -0,0 +1,18 @@ | |||
1 | #!/bin/sh | ||
2 | # Gets the version number from git, or from the contents of .version | ||
3 | VERSION= | ||
4 | if test -f ".version" | ||
5 | then | ||
6 | VERSION=$(cat .version) | ||
7 | fi | ||
8 | if test -d "./.git" | ||
9 | then | ||
10 | VERSION=$(git describe --tags) | ||
11 | VERSION=${VERSION#v} | ||
12 | echo $VERSION > .version | ||
13 | fi | ||
14 | if test "x$VERSION" = "x" | ||
15 | then | ||
16 | VERSION="unknown" | ||
17 | fi | ||
18 | echo "$VERSION" | ||
diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..d46f2f9 --- /dev/null +++ b/meson.build | |||
@@ -0,0 +1,52 @@ | |||
1 | # | ||
2 | # This file is part of GNUnet. | ||
3 | # Copyright (C) 2023--2024 GNUnet e.V. | ||
4 | # | ||
5 | # GNUnet is free software: you can redistribute it and/or modify it | ||
6 | # under the terms of the GNU Affero General Public License as published | ||
7 | # by the Free Software Foundation, either version 3 of the License, | ||
8 | # or (at your option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # Affero General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU Affero General Public License | ||
16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | # | ||
18 | # SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | # | ||
20 | |||
21 | project( | ||
22 | 'messenger-cli', | ||
23 | 'c', | ||
24 | license: 'AGPL3.0-or-later', | ||
25 | version: run_command('contrib/get_version.sh').stdout().strip(), | ||
26 | ) | ||
27 | |||
28 | meson.add_dist_script('contrib/distribute_version.sh', meson.project_version()) | ||
29 | |||
30 | src_directory = include_directories('src') | ||
31 | |||
32 | messenger_cli_deps = [ | ||
33 | dependency('gnunetchat'), | ||
34 | dependency('gnunetutil'), | ||
35 | dependency('ncurses'), | ||
36 | ] | ||
37 | |||
38 | messenger_cli_args = [ | ||
39 | '-DMESSENGER_CLI_BINARY="@0@"'.format(meson.project_name()), | ||
40 | '-DMESSENGER_CLI_VERSION="@0@"'.format(meson.project_version()), | ||
41 | ] | ||
42 | |||
43 | subdir('src') | ||
44 | |||
45 | messenger_cli_exec = executable( | ||
46 | 'messenger-cli', | ||
47 | messenger_cli_sources, | ||
48 | c_args: messenger_cli_args, | ||
49 | install: true, | ||
50 | dependencies: messenger_cli_deps, | ||
51 | include_directories: src_directory, | ||
52 | ) | ||
diff --git a/resources/logo.asc b/resources/logo.asc new file mode 100644 index 0000000..ddc43ad --- /dev/null +++ b/resources/logo.asc | |||
@@ -0,0 +1,10 @@ | |||
1 | |||
2 | o o | ||
3 | ooo oo | ||
4 | ooooo ooooo | ||
5 | oo ooo | ||
6 | oo ooo | ||
7 | ooooooo | ||
8 | oooooo | ||
9 | oooo | ||
10 | |||
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..937a67b --- /dev/null +++ b/src/.gitignore | |||
@@ -0,0 +1,14 @@ | |||
1 | .deps/ | ||
2 | .libs/ | ||
3 | |||
4 | Makefile.in | ||
5 | Makefile | ||
6 | |||
7 | stamp-h1 | ||
8 | |||
9 | messenger_cli_config.h | ||
10 | messenger_cli_config.h.in | ||
11 | messenger_cli_config.h.in~ | ||
12 | |||
13 | *.o | ||
14 | *.a | ||
diff --git a/src/application.c b/src/application.c new file mode 100644 index 0000000..1b2bdbd --- /dev/null +++ b/src/application.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2024 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file application.c | ||
23 | */ | ||
24 | |||
25 | #include "application.h" | ||
26 | |||
27 | #include "util.h" | ||
28 | |||
29 | #ifndef MESSENGER_CLI_BINARY | ||
30 | #define MESSENGER_CLI_BINARY "messenger_cli" | ||
31 | #endif | ||
32 | |||
33 | #ifndef MESSENGER_CLI_VERSION | ||
34 | #define MESSENGER_CLI_VERSION "unknown" | ||
35 | #endif | ||
36 | |||
37 | #ifndef MESSENGER_CLI_DESC | ||
38 | #define MESSENGER_CLI_DESC "A CLI for the Messenger service of GNUnet." | ||
39 | #endif | ||
40 | |||
41 | void | ||
42 | application_clear(MESSENGER_Application *app) | ||
43 | { | ||
44 | app->accounts.window = NULL; | ||
45 | app->chats.window = NULL; | ||
46 | app->current.members.window = NULL; | ||
47 | app->current.messages.window = NULL; | ||
48 | } | ||
49 | |||
50 | void | ||
51 | application_init(MESSENGER_Application *app, | ||
52 | int argc, | ||
53 | char **argv) | ||
54 | { | ||
55 | const struct GNUNET_GETOPT_CommandLineOption options [] = { | ||
56 | GNUNET_GETOPT_option_version(MESSENGER_CLI_VERSION), | ||
57 | GNUNET_GETOPT_option_help(MESSENGER_CLI_DESC), | ||
58 | GNUNET_GETOPT_OPTION_END | ||
59 | }; | ||
60 | |||
61 | memset(app, 0, sizeof(*app)); | ||
62 | |||
63 | app->argc = argc; | ||
64 | app->argv = argv; | ||
65 | |||
66 | const int parsing = GNUNET_GETOPT_run( | ||
67 | MESSENGER_CLI_BINARY, | ||
68 | options, | ||
69 | app->argc, | ||
70 | app->argv | ||
71 | ); | ||
72 | |||
73 | if (parsing <= 0) | ||
74 | { | ||
75 | app->window = NULL; | ||
76 | app->status = GNUNET_SYSERR == parsing? GNUNET_SYSERR : GNUNET_OK; | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | app->window = initscr(); | ||
81 | |||
82 | if (!(app->window)) | ||
83 | { | ||
84 | app->status = GNUNET_SYSERR; | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | application_refresh(app); | ||
89 | |||
90 | noecho(); | ||
91 | |||
92 | keypad(app->window, TRUE); | ||
93 | wtimeout(app->window, 10); | ||
94 | } | ||
95 | |||
96 | void | ||
97 | application_refresh(MESSENGER_Application *app) | ||
98 | { | ||
99 | if (app->ui.logo) delwin(app->ui.logo); | ||
100 | if (app->ui.main) delwin(app->ui.main); | ||
101 | if (app->ui.left) delwin(app->ui.left); | ||
102 | if (app->ui.right) delwin(app->ui.right); | ||
103 | if (app->ui.input) delwin(app->ui.input); | ||
104 | |||
105 | memset(&(app->ui), 0, sizeof(app->ui)); | ||
106 | |||
107 | curs_set(0); | ||
108 | } | ||
109 | |||
110 | static void | ||
111 | run (void *cls, | ||
112 | UNUSED char* const* args, | ||
113 | UNUSED const char *cfgfile, | ||
114 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
115 | { | ||
116 | MESSENGER_Application *app = cls; | ||
117 | |||
118 | if (!(app->window)) | ||
119 | return; | ||
120 | |||
121 | chat_start(&(app->chat), app, cfg); | ||
122 | } | ||
123 | |||
124 | void | ||
125 | application_run(MESSENGER_Application *app) | ||
126 | { | ||
127 | const struct GNUNET_GETOPT_CommandLineOption options [] = { | ||
128 | GNUNET_GETOPT_OPTION_END | ||
129 | }; | ||
130 | |||
131 | app->status = GNUNET_PROGRAM_run( | ||
132 | 1, | ||
133 | app->argv, | ||
134 | MESSENGER_CLI_BINARY, | ||
135 | gettext_noop(MESSENGER_CLI_DESC), | ||
136 | options, | ||
137 | &run, | ||
138 | app | ||
139 | ); | ||
140 | |||
141 | members_clear(&(app->current.members)); | ||
142 | messages_clear(&(app->current.messages)); | ||
143 | |||
144 | application_clear(app); | ||
145 | |||
146 | if (app->window) | ||
147 | delwin(app->window); | ||
148 | |||
149 | if (ERR == endwin()) | ||
150 | { | ||
151 | app->status = GNUNET_SYSERR; | ||
152 | return; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | int | ||
157 | application_status(MESSENGER_Application *app) | ||
158 | { | ||
159 | if (app->status != GNUNET_OK) | ||
160 | return EXIT_FAILURE; | ||
161 | else | ||
162 | return EXIT_SUCCESS; | ||
163 | } | ||
diff --git a/src/application.h b/src/application.h new file mode 100644 index 0000000..2ed9ea4 --- /dev/null +++ b/src/application.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file application.h | ||
23 | */ | ||
24 | |||
25 | #ifndef APPLICATION_H_ | ||
26 | #define APPLICATION_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | #include "chat.h" | ||
32 | |||
33 | #include "ui/accounts.h" | ||
34 | #include "ui/chat.h" | ||
35 | #include "ui/chats.h" | ||
36 | |||
37 | /** | ||
38 | * @struct MESSENGER_Application | ||
39 | */ | ||
40 | typedef struct MESSENGER_Application | ||
41 | { | ||
42 | char **argv; | ||
43 | int argc; | ||
44 | |||
45 | int status; | ||
46 | WINDOW *window; | ||
47 | |||
48 | struct { | ||
49 | WINDOW *logo; | ||
50 | WINDOW *main; | ||
51 | WINDOW *left; | ||
52 | WINDOW *right; | ||
53 | WINDOW *input; | ||
54 | } ui; | ||
55 | |||
56 | MESSENGER_Chat chat; | ||
57 | |||
58 | UI_ACCOUNTS_Handle accounts; | ||
59 | UI_CHATS_Handle chats; | ||
60 | UI_CHAT_Handle current; | ||
61 | } MESSENGER_Application; | ||
62 | |||
63 | /** | ||
64 | * Clears the application handle to reset all views | ||
65 | * which might have been in use. | ||
66 | * | ||
67 | * @param[out] app Application handle | ||
68 | */ | ||
69 | void | ||
70 | application_clear(MESSENGER_Application *app); | ||
71 | |||
72 | /** | ||
73 | * Initializes the application handle with the program | ||
74 | * arguments provided from the main function. | ||
75 | * | ||
76 | * @param[out] app Application handle | ||
77 | * @param[in] argc Argument count | ||
78 | * @param[in] argv Argument array | ||
79 | */ | ||
80 | void | ||
81 | application_init(MESSENGER_Application *app, | ||
82 | int argc, | ||
83 | char **argv); | ||
84 | |||
85 | /** | ||
86 | * Refreshes the application handle freeing all temporary | ||
87 | * WINDOW handles to manage the different views which | ||
88 | * were used. | ||
89 | * | ||
90 | * @param[out] app Application handle | ||
91 | */ | ||
92 | void | ||
93 | application_refresh(MESSENGER_Application *app); | ||
94 | |||
95 | /** | ||
96 | * Starts the main loop of the application which will | ||
97 | * be processed via GNUnet and its callback management. | ||
98 | * | ||
99 | * @param[in,out] app Application handle | ||
100 | */ | ||
101 | void | ||
102 | application_run(MESSENGER_Application *app); | ||
103 | |||
104 | /** | ||
105 | * Returns the status code by the given application | ||
106 | * at current state. | ||
107 | * | ||
108 | * @param[in] app Application handle | ||
109 | * @return #EXIT_FAILURE on failure, otherwise #EXIT_SUCCESS | ||
110 | */ | ||
111 | int | ||
112 | application_status(MESSENGER_Application *app); | ||
113 | |||
114 | #endif /* APPLICATION_H_ */ | ||
diff --git a/src/chat.c b/src/chat.c new file mode 100644 index 0000000..792f8eb --- /dev/null +++ b/src/chat.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2024 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file chat.c | ||
23 | */ | ||
24 | |||
25 | #include "chat.h" | ||
26 | |||
27 | #include "application.h" | ||
28 | #include "util.h" | ||
29 | #include <curses.h> | ||
30 | #include <gnunet/gnunet_chat_lib.h> | ||
31 | |||
32 | #ifndef MESSENGER_CLI_BINARY | ||
33 | #define MESSENGER_CLI_BINARY "messenger_cli" | ||
34 | #endif | ||
35 | |||
36 | #ifndef MESSENGER_CLI_VERSION | ||
37 | #define MESSENGER_CLI_VERSION "unknown" | ||
38 | #endif | ||
39 | |||
40 | static void | ||
41 | _chat_refresh(MESSENGER_Application *app) | ||
42 | { | ||
43 | application_clear(app); | ||
44 | chat_update_layout(&(app->chat), app); | ||
45 | |||
46 | accounts_print(&(app->accounts), app); | ||
47 | chats_print(&(app->chats), app); | ||
48 | members_print(&(app->current.members)); | ||
49 | messages_print(&(app->current.messages)); | ||
50 | |||
51 | if (!app->ui.logo) | ||
52 | return; | ||
53 | |||
54 | werase(app->ui.logo); | ||
55 | wmove(app->ui.logo, 0, 0); | ||
56 | |||
57 | util_print_logo(app->ui.logo); | ||
58 | |||
59 | int x = getcurx(app->ui.logo); | ||
60 | int y = getcury(app->ui.logo); | ||
61 | |||
62 | util_print_info(app->ui.logo, MESSENGER_CLI_VERSION); | ||
63 | |||
64 | wmove(app->ui.logo, --y, x); | ||
65 | util_print_info(app->ui.logo, MESSENGER_CLI_BINARY); | ||
66 | } | ||
67 | |||
68 | static bool | ||
69 | _chat_event(MESSENGER_Application *app, | ||
70 | int key) | ||
71 | { | ||
72 | if (key < 0) | ||
73 | goto refresh; | ||
74 | |||
75 | const struct GNUNET_CHAT_Account *account = GNUNET_CHAT_get_connected( | ||
76 | app->chat.handle | ||
77 | ); | ||
78 | |||
79 | if (!account) | ||
80 | accounts_event(&(app->accounts), app, key); | ||
81 | else if (app->chat.context) | ||
82 | { | ||
83 | if (app->chat.show_members) | ||
84 | members_event(&(app->current.members), app, key); | ||
85 | else | ||
86 | messages_event(&(app->current.messages), app, key); | ||
87 | } | ||
88 | else | ||
89 | chats_event(&(app->chats), app, key); | ||
90 | |||
91 | if (app->chat.quit) | ||
92 | return TRUE; | ||
93 | |||
94 | refresh: | ||
95 | _chat_refresh(app); | ||
96 | return FALSE; | ||
97 | } | ||
98 | |||
99 | static int | ||
100 | _chat_message(void *cls, | ||
101 | struct GNUNET_CHAT_Context *context, | ||
102 | const struct GNUNET_CHAT_Message *message) | ||
103 | { | ||
104 | MESSENGER_Application *app = cls; | ||
105 | |||
106 | chat_process_message(&(app->chat), context, message); | ||
107 | |||
108 | _chat_event(app, KEY_RESIZE); | ||
109 | return GNUNET_YES; | ||
110 | } | ||
111 | |||
112 | static void | ||
113 | _chat_idle(void *cls) | ||
114 | { | ||
115 | MESSENGER_Application *app = cls; | ||
116 | app->chat.idle = NULL; | ||
117 | |||
118 | if (app->chat.quit) | ||
119 | return; | ||
120 | |||
121 | if (_chat_event(app, wgetch(app->window))) | ||
122 | { | ||
123 | chat_stop(&(app->chat)); | ||
124 | return; | ||
125 | } | ||
126 | |||
127 | app->chat.idle = GNUNET_SCHEDULER_add_delayed_with_priority( | ||
128 | GNUNET_TIME_relative_multiply( | ||
129 | GNUNET_TIME_relative_get_millisecond_(), | ||
130 | wgetdelay(app->window) | ||
131 | ), | ||
132 | GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
133 | &_chat_idle, | ||
134 | app | ||
135 | ); | ||
136 | } | ||
137 | |||
138 | void | ||
139 | chat_start(MESSENGER_Chat *chat, | ||
140 | struct MESSENGER_Application *app, | ||
141 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
142 | { | ||
143 | chat->handle = GNUNET_CHAT_start( | ||
144 | cfg, | ||
145 | &_chat_message, | ||
146 | app | ||
147 | ); | ||
148 | |||
149 | chat->context = NULL; | ||
150 | |||
151 | chat->idle = GNUNET_SCHEDULER_add_now( | ||
152 | &_chat_idle, | ||
153 | app | ||
154 | ); | ||
155 | |||
156 | chat->quit = FALSE; | ||
157 | } | ||
158 | |||
159 | void | ||
160 | chat_stop(MESSENGER_Chat *chat) | ||
161 | { | ||
162 | if (chat->idle) | ||
163 | { | ||
164 | GNUNET_SCHEDULER_cancel(chat->idle); | ||
165 | chat->idle = NULL; | ||
166 | } | ||
167 | |||
168 | GNUNET_CHAT_stop(chat->handle); | ||
169 | chat->handle = NULL; | ||
170 | |||
171 | chat->quit = TRUE; | ||
172 | } | ||
173 | |||
174 | void | ||
175 | _chat_update_layout_accounts(struct MESSENGER_Application *app) | ||
176 | { | ||
177 | int rows, cols; | ||
178 | getmaxyx(app->window, rows, cols); | ||
179 | |||
180 | if (rows >= UTIL_LOGO_ROWS + UI_ACCOUNTS_ROWS_MIN) | ||
181 | { | ||
182 | const int offset = UTIL_LOGO_ROWS + 1; | ||
183 | |||
184 | app->ui.logo = subwin(app->window, UTIL_LOGO_ROWS, cols, 0, 0); | ||
185 | app->ui.main = subwin(app->window, rows - offset, cols, offset, 0); | ||
186 | |||
187 | wmove(app->window, UTIL_LOGO_ROWS, 0); | ||
188 | whline(app->window, ACS_HLINE, cols); | ||
189 | } | ||
190 | else | ||
191 | app->ui.main = subwin(app->window, rows, cols, 0, 0); | ||
192 | |||
193 | app->accounts.window = app->ui.main; | ||
194 | } | ||
195 | |||
196 | void | ||
197 | _chat_update_layout_chats(struct MESSENGER_Application *app) | ||
198 | { | ||
199 | int rows, cols; | ||
200 | getmaxyx(app->window, rows, cols); | ||
201 | |||
202 | int min_rows = UI_CHATS_ROWS_MIN; | ||
203 | int offset_x = 0; | ||
204 | int offset_y = 0; | ||
205 | |||
206 | if (cols >= UI_ACCOUNTS_COLS_MIN + UI_CHATS_COLS_MIN) | ||
207 | { | ||
208 | offset_x = UI_ACCOUNTS_COLS_MIN + 1; | ||
209 | |||
210 | if (UI_ACCOUNTS_ROWS_MIN > min_rows) min_rows = UI_ACCOUNTS_ROWS_MIN; | ||
211 | } | ||
212 | |||
213 | if (rows >= UTIL_LOGO_ROWS + min_rows) | ||
214 | { | ||
215 | offset_y = UTIL_LOGO_ROWS + 1; | ||
216 | |||
217 | app->ui.logo = subwin(app->window, UTIL_LOGO_ROWS, cols, 0, 0); | ||
218 | |||
219 | wmove(app->window, UTIL_LOGO_ROWS, 0); | ||
220 | whline(app->window, ACS_HLINE, cols); | ||
221 | } | ||
222 | |||
223 | if (offset_x > 0) | ||
224 | { | ||
225 | app->ui.left = subwin( | ||
226 | app->window, | ||
227 | rows - offset_y, | ||
228 | UI_ACCOUNTS_COLS_MIN, | ||
229 | offset_y, | ||
230 | 0 | ||
231 | ); | ||
232 | |||
233 | wmove(app->window, offset_y > 0? offset_y : 0, UI_ACCOUNTS_COLS_MIN); | ||
234 | wvline(app->window, ACS_VLINE, rows - offset_y); | ||
235 | |||
236 | if (offset_y > 0) | ||
237 | { | ||
238 | wmove(app->window, offset_y - 1, UI_ACCOUNTS_COLS_MIN); | ||
239 | waddch(app->window, ACS_TTEE); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | app->ui.main = subwin( | ||
244 | app->window, | ||
245 | rows - offset_y, | ||
246 | cols - offset_x, | ||
247 | offset_y, | ||
248 | offset_x | ||
249 | ); | ||
250 | |||
251 | app->accounts.window = app->ui.left; | ||
252 | app->chats.window = app->ui.main; | ||
253 | } | ||
254 | |||
255 | void | ||
256 | _chat_update_layout_messages(struct MESSENGER_Application *app) | ||
257 | { | ||
258 | int rows, cols; | ||
259 | getmaxyx(app->window, rows, cols); | ||
260 | |||
261 | const int cols_min_left = (UTIL_LOGO_COLS > UI_CHATS_COLS_MIN? | ||
262 | UTIL_LOGO_COLS : UI_CHATS_COLS_MIN | ||
263 | ); | ||
264 | |||
265 | int offset_x, cut_x; | ||
266 | cut_x = 0; | ||
267 | |||
268 | if (cols >= cols_min_left + UI_MESSAGES_COLS_MIN) | ||
269 | offset_x = cols_min_left + 1; | ||
270 | else | ||
271 | { | ||
272 | offset_x = 0; | ||
273 | goto skip_left_split; | ||
274 | } | ||
275 | |||
276 | if (rows >= UTIL_LOGO_ROWS + UI_CHATS_ROWS_MIN) | ||
277 | { | ||
278 | const int offset = UTIL_LOGO_ROWS + 1; | ||
279 | |||
280 | app->ui.logo = subwin(app->window, UTIL_LOGO_ROWS, cols_min_left, 0, 0); | ||
281 | app->ui.left = subwin(app->window, rows - offset, cols_min_left, offset, 0); | ||
282 | |||
283 | wmove(app->window, UTIL_LOGO_ROWS, 0); | ||
284 | whline(app->window, ACS_HLINE, cols_min_left); | ||
285 | } | ||
286 | else | ||
287 | app->ui.left = subwin(app->window, rows, cols_min_left, 0, 0); | ||
288 | |||
289 | if (cols >= cols_min_left + UI_MESSAGES_COLS_MIN + UI_MEMBERS_COLS_MIN) | ||
290 | { | ||
291 | cut_x = UI_MEMBERS_COLS_MIN + 1; | ||
292 | |||
293 | app->ui.right = subwin( | ||
294 | app->window, | ||
295 | rows, | ||
296 | UI_MEMBERS_COLS_MIN, | ||
297 | 0, | ||
298 | cols - UI_MEMBERS_COLS_MIN | ||
299 | ); | ||
300 | |||
301 | wmove(app->window, 0, cols - cut_x); | ||
302 | wvline(app->window, ACS_VLINE, rows); | ||
303 | } | ||
304 | |||
305 | wmove(app->window, 0, cols_min_left); | ||
306 | wvline(app->window, ACS_VLINE, rows); | ||
307 | |||
308 | skip_left_split: | ||
309 | app->ui.main = subwin( | ||
310 | app->window, | ||
311 | rows, | ||
312 | cols - offset_x - cut_x, | ||
313 | 0, | ||
314 | offset_x | ||
315 | ); | ||
316 | |||
317 | app->chats.window = app->ui.left; | ||
318 | |||
319 | if (app->ui.right) | ||
320 | { | ||
321 | app->current.members.window = app->ui.right; | ||
322 | app->current.messages.window = app->ui.main; | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | if (app->chat.show_members) | ||
327 | app->current.members.window = app->ui.main; | ||
328 | else | ||
329 | app->current.messages.window = app->ui.main; | ||
330 | } | ||
331 | |||
332 | void | ||
333 | chat_update_layout(MESSENGER_Chat *chat, | ||
334 | struct MESSENGER_Application *app) | ||
335 | { | ||
336 | const struct GNUNET_CHAT_Account *account = GNUNET_CHAT_get_connected( | ||
337 | chat->handle | ||
338 | ); | ||
339 | |||
340 | application_refresh(app); | ||
341 | |||
342 | if (!account) | ||
343 | _chat_update_layout_accounts(app); | ||
344 | else if (app->chat.context) | ||
345 | _chat_update_layout_messages(app); | ||
346 | else | ||
347 | _chat_update_layout_chats(app); | ||
348 | } | ||
349 | |||
350 | void | ||
351 | chat_process_message(UNUSED MESSENGER_Chat *chat, | ||
352 | struct GNUNET_CHAT_Context *context, | ||
353 | const struct GNUNET_CHAT_Message *message) | ||
354 | { | ||
355 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); | ||
356 | |||
357 | struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); | ||
358 | |||
359 | UI_CHAT_Handle *current = (UI_CHAT_Handle*) ( | ||
360 | GNUNET_CHAT_context_get_user_pointer(context) | ||
361 | ); | ||
362 | |||
363 | if (!current) | ||
364 | return; | ||
365 | |||
366 | bool new_member = FALSE; | ||
367 | |||
368 | if (GNUNET_CHAT_KIND_LEAVE == kind) | ||
369 | members_remove(&(current->members), sender); | ||
370 | else if (GNUNET_CHAT_KIND_JOIN == kind) | ||
371 | new_member = members_add(&(current->members), sender); | ||
372 | |||
373 | if (GNUNET_CHAT_KIND_DELETION == kind) | ||
374 | messages_remove( | ||
375 | &(current->messages), | ||
376 | GNUNET_CHAT_message_get_target(message) | ||
377 | ); | ||
378 | else if (GNUNET_YES == GNUNET_CHAT_message_is_deleted(message)) | ||
379 | messages_remove(&(current->messages), message); | ||
380 | else if ((GNUNET_CHAT_KIND_JOIN != kind) || (new_member)) | ||
381 | messages_add(&(current->messages), message); | ||
382 | } | ||
diff --git a/src/chat.h b/src/chat.h new file mode 100644 index 0000000..00c01f1 --- /dev/null +++ b/src/chat.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file chat.h | ||
23 | */ | ||
24 | |||
25 | #ifndef CHAT_H_ | ||
26 | #define CHAT_H_ | ||
27 | |||
28 | #include <gnunet/gnunet_chat_lib.h> | ||
29 | #include <gnunet/gnunet_util_lib.h> | ||
30 | |||
31 | struct MESSENGER_Application; | ||
32 | |||
33 | /** | ||
34 | * @struct MESSENGER_Chat | ||
35 | */ | ||
36 | typedef struct MESSENGER_Chat | ||
37 | { | ||
38 | struct GNUNET_CHAT_Handle *handle; | ||
39 | struct GNUNET_CHAT_Context *context; | ||
40 | |||
41 | struct GNUNET_SCHEDULER_Task *idle; | ||
42 | |||
43 | bool show_members; | ||
44 | bool quit; | ||
45 | } MESSENGER_Chat; | ||
46 | |||
47 | /** | ||
48 | * Starts the processing of the given applications | ||
49 | * chat handle. | ||
50 | * | ||
51 | * @param[out] chat Application chat handle | ||
52 | * @param[in,out] app Application handle | ||
53 | * @param[in] cfg Configuration | ||
54 | */ | ||
55 | void | ||
56 | chat_start(MESSENGER_Chat *chat, | ||
57 | struct MESSENGER_Application *app, | ||
58 | const struct GNUNET_CONFIGURATION_Handle *cfg); | ||
59 | |||
60 | /** | ||
61 | * Stops the processing of the given applications | ||
62 | * chat handle. | ||
63 | * | ||
64 | * @param[in,out] chat Application chat handle | ||
65 | */ | ||
66 | void | ||
67 | chat_stop(MESSENGER_Chat *chat); | ||
68 | |||
69 | /** | ||
70 | * Updates the layout of the applications views depending | ||
71 | * on the main windows resolution and the current state | ||
72 | * of the applications chat handle. | ||
73 | * | ||
74 | * @param[in] chat Application chat handle | ||
75 | * @param[out] app Application handle | ||
76 | */ | ||
77 | void | ||
78 | chat_update_layout(MESSENGER_Chat *chat, | ||
79 | struct MESSENGER_Application *app); | ||
80 | |||
81 | /** | ||
82 | * Processes a chat message to update the list of | ||
83 | * required resources to handle visual representation | ||
84 | * of current members in a chat or the messages. | ||
85 | * | ||
86 | * @param[in,out] chat Application chat handle | ||
87 | * @param[in] context Chat context of the message | ||
88 | * @param[in] message Chat message | ||
89 | */ | ||
90 | void | ||
91 | chat_process_message(MESSENGER_Chat *chat, | ||
92 | struct GNUNET_CHAT_Context *context, | ||
93 | const struct GNUNET_CHAT_Message *message); | ||
94 | |||
95 | #endif /* CHAT_H_ */ | ||
diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..1d98bea --- /dev/null +++ b/src/meson.build | |||
@@ -0,0 +1,28 @@ | |||
1 | # | ||
2 | # This file is part of GNUnet. | ||
3 | # Copyright (C) 2023 GNUnet e.V. | ||
4 | # | ||
5 | # GNUnet is free software: you can redistribute it and/or modify it | ||
6 | # under the terms of the GNU Affero General Public License as published | ||
7 | # by the Free Software Foundation, either version 3 of the License, | ||
8 | # or (at your option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # Affero General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU Affero General Public License | ||
16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | # | ||
18 | # SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | # | ||
20 | |||
21 | subdir('ui') | ||
22 | |||
23 | messenger_cli_sources = files([ | ||
24 | 'application.c', 'application.h', | ||
25 | 'chat.c', 'chat.h', | ||
26 | 'util.c', 'util.h', | ||
27 | 'messenger_cli.c', | ||
28 | ]) + messenger_cli_ui_sources | ||
diff --git a/src/messenger_cli.c b/src/messenger_cli.c index cee3020..7127514 100644 --- a/src/messenger_cli.c +++ b/src/messenger_cli.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2021 GNUnet e.V. | 3 | Copyright (C) 2021--2022 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -22,9 +22,18 @@ | |||
22 | * @file messenger_cli.c | 22 | * @file messenger_cli.c |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <gnunet/gnunet_chat_lib.h> | 25 | #include "application.h" |
26 | 26 | ||
27 | int main(int argc, const char** argv) { | 27 | int |
28 | GNUNET_CHAT_test("Hello world"); | 28 | main (int argc, char** argv) |
29 | return 0; | 29 | { |
30 | MESSENGER_Application app; | ||
31 | |||
32 | application_init(&app, argc, argv); | ||
33 | application_run(&app); | ||
34 | |||
35 | const int status = application_status(&app); | ||
36 | |||
37 | exit_curses(status); | ||
38 | return status; | ||
30 | } | 39 | } |
diff --git a/src/ui/account_create_dialog.c b/src/ui/account_create_dialog.c new file mode 100644 index 0000000..6845a1d --- /dev/null +++ b/src/ui/account_create_dialog.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/account_create_dialog.c | ||
23 | */ | ||
24 | |||
25 | #include "account_create_dialog.h" | ||
26 | |||
27 | #include <gnunet/gnunet_chat_lib.h> | ||
28 | #include <gnunet/gnunet_util_lib.h> | ||
29 | |||
30 | #include "text_input.h" | ||
31 | #include "../application.h" | ||
32 | |||
33 | void | ||
34 | account_create_dialog_event(UI_ACCOUNT_CREATE_DIALOG_Handle *create_dialog, | ||
35 | struct MESSENGER_Application *app, | ||
36 | int key) | ||
37 | { | ||
38 | switch (key) | ||
39 | { | ||
40 | case 27: | ||
41 | case KEY_EXIT: | ||
42 | create_dialog->window = NULL; | ||
43 | break; | ||
44 | case '\n': | ||
45 | case KEY_ENTER: | ||
46 | if (create_dialog->name_len > 0) | ||
47 | GNUNET_CHAT_account_create(app->chat.handle, create_dialog->name); | ||
48 | |||
49 | create_dialog->name_len = 0; | ||
50 | create_dialog->window = NULL; | ||
51 | break; | ||
52 | default: | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | text_input_event(create_dialog->name, key); | ||
57 | } | ||
58 | |||
59 | void | ||
60 | account_create_dialog_print(UI_ACCOUNT_CREATE_DIALOG_Handle *create_dialog) | ||
61 | { | ||
62 | if (!(create_dialog->window)) | ||
63 | return; | ||
64 | |||
65 | WINDOW *window = *(create_dialog->window); | ||
66 | |||
67 | werase(window); | ||
68 | wmove(window, 0, 0); | ||
69 | |||
70 | wprintw(window, "%s", create_dialog->name); | ||
71 | wmove(window, 0, create_dialog->name_pos); | ||
72 | |||
73 | wcursyncup(window); | ||
74 | curs_set(1); | ||
75 | } | ||
diff --git a/src/ui/account_create_dialog.h b/src/ui/account_create_dialog.h new file mode 100644 index 0000000..93c8318 --- /dev/null +++ b/src/ui/account_create_dialog.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/account_create_dialog.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_ACCOUNT_CREATE_DIALOG_H_ | ||
26 | #define UI_ACCOUNT_CREATE_DIALOG_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | struct MESSENGER_Application; | ||
32 | |||
33 | /** | ||
34 | * @struct UI_ACCOUNT_CREATE_DIALOG_Handle | ||
35 | */ | ||
36 | typedef struct UI_ACCOUNT_CREATE_DIALOG_Handle | ||
37 | { | ||
38 | WINDOW **window; | ||
39 | |||
40 | char name [256]; | ||
41 | int name_len; | ||
42 | int name_pos; | ||
43 | } UI_ACCOUNT_CREATE_DIALOG_Handle; | ||
44 | |||
45 | /** | ||
46 | * Processes the current key event by the dialog | ||
47 | * to create a new account. | ||
48 | * | ||
49 | * @param[in,out] create_dialog Account creation dialog | ||
50 | * @param[in,out] app Application handle | ||
51 | * @param[in] key Key | ||
52 | */ | ||
53 | void | ||
54 | account_create_dialog_event(UI_ACCOUNT_CREATE_DIALOG_Handle *create_dialog, | ||
55 | struct MESSENGER_Application *app, | ||
56 | int key); | ||
57 | |||
58 | /** | ||
59 | * Prints the content of the dialog to create a new | ||
60 | * account to its selected window view. | ||
61 | * | ||
62 | * @param[in] create_dialog Account creation dialog | ||
63 | */ | ||
64 | void | ||
65 | account_create_dialog_print(UI_ACCOUNT_CREATE_DIALOG_Handle *create_dialog); | ||
66 | |||
67 | #endif /* UI_ACCOUNT_CREATE_DIALOG_H_ */ | ||
diff --git a/src/ui/accounts.c b/src/ui/accounts.c new file mode 100644 index 0000000..bdc5086 --- /dev/null +++ b/src/ui/accounts.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/accounts.c | ||
23 | */ | ||
24 | |||
25 | #include "accounts.h" | ||
26 | |||
27 | #include "list_input.h" | ||
28 | #include "../application.h" | ||
29 | #include "../util.h" | ||
30 | |||
31 | int | ||
32 | _accounts_iterate(void *cls, | ||
33 | UNUSED const struct GNUNET_CHAT_Handle *handle, | ||
34 | struct GNUNET_CHAT_Account *account) | ||
35 | { | ||
36 | UI_ACCOUNTS_Handle *accounts = cls; | ||
37 | list_input_select(accounts, 1, account); | ||
38 | return GNUNET_YES; | ||
39 | } | ||
40 | |||
41 | void | ||
42 | accounts_event(UI_ACCOUNTS_Handle *accounts, | ||
43 | MESSENGER_Application *app, | ||
44 | int key) | ||
45 | { | ||
46 | if (accounts->create_dialog.window) | ||
47 | { | ||
48 | account_create_dialog_event(&(accounts->create_dialog), app, key); | ||
49 | return; | ||
50 | } | ||
51 | |||
52 | list_input_reset(accounts); | ||
53 | |||
54 | GNUNET_CHAT_iterate_accounts( | ||
55 | app->chat.handle, | ||
56 | &_accounts_iterate, | ||
57 | accounts | ||
58 | ); | ||
59 | |||
60 | list_input_select(accounts, 1, NULL); | ||
61 | |||
62 | switch (key) | ||
63 | { | ||
64 | case 27: | ||
65 | case KEY_EXIT: | ||
66 | app->chat.quit = TRUE; | ||
67 | break; | ||
68 | case '\n': | ||
69 | case KEY_ENTER: | ||
70 | if (accounts->selected) | ||
71 | GNUNET_CHAT_connect(app->chat.handle, accounts->selected); | ||
72 | else | ||
73 | accounts->create_dialog.window = &(accounts->window); | ||
74 | break; | ||
75 | default: | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | list_input_event(accounts, key); | ||
80 | } | ||
81 | |||
82 | static int | ||
83 | _accounts_print_entry(UI_ACCOUNTS_Handle *accounts, | ||
84 | char type, | ||
85 | const char *text) | ||
86 | { | ||
87 | list_input_print_gnunet(accounts, 1); | ||
88 | |||
89 | const int attrs_select = A_BOLD; | ||
90 | |||
91 | if (selected) wattron(accounts->window, attrs_select); | ||
92 | |||
93 | wmove(accounts->window, y, 0); | ||
94 | wprintw(accounts->window, "[%c] %s", selected? type : ' ', text); | ||
95 | |||
96 | if (selected) wattroff(accounts->window, attrs_select); | ||
97 | |||
98 | return GNUNET_YES; | ||
99 | } | ||
100 | |||
101 | int | ||
102 | _accounts_iterate_print(void *cls, | ||
103 | UNUSED const struct GNUNET_CHAT_Handle *handle, | ||
104 | struct GNUNET_CHAT_Account *account) | ||
105 | { | ||
106 | UI_ACCOUNTS_Handle *accounts = cls; | ||
107 | const char *name = GNUNET_CHAT_account_get_name(account); | ||
108 | return _accounts_print_entry(accounts, 'x', name); | ||
109 | } | ||
110 | |||
111 | void | ||
112 | accounts_print(UI_ACCOUNTS_Handle *accounts, | ||
113 | MESSENGER_Application *app) | ||
114 | { | ||
115 | if (accounts->create_dialog.window) | ||
116 | { | ||
117 | account_create_dialog_print(&(accounts->create_dialog)); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | if (!(accounts->window)) | ||
122 | return; | ||
123 | |||
124 | list_input_reset(accounts); | ||
125 | werase(accounts->window); | ||
126 | |||
127 | GNUNET_CHAT_iterate_accounts( | ||
128 | app->chat.handle, | ||
129 | &_accounts_iterate_print, | ||
130 | accounts | ||
131 | ); | ||
132 | |||
133 | _accounts_print_entry(accounts, '+', "Add account"); | ||
134 | } | ||
diff --git a/src/ui/accounts.h b/src/ui/accounts.h new file mode 100644 index 0000000..392f476 --- /dev/null +++ b/src/ui/accounts.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/accounts.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_ACCOUNTS_H_ | ||
26 | #define UI_ACCOUNTS_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | #include <gnunet/gnunet_chat_lib.h> | ||
32 | #include <gnunet/gnunet_util_lib.h> | ||
33 | |||
34 | #include "account_create_dialog.h" | ||
35 | |||
36 | struct MESSENGER_Application; | ||
37 | |||
38 | /** | ||
39 | * @struct UI_ACCOUNTS_Handle | ||
40 | */ | ||
41 | typedef struct UI_ACCOUNTS_Handle | ||
42 | { | ||
43 | WINDOW *window; | ||
44 | |||
45 | int line_prev; | ||
46 | int line_next; | ||
47 | |||
48 | int line_index; | ||
49 | int line_offset; | ||
50 | int line_selected; | ||
51 | |||
52 | struct GNUNET_CHAT_Account *selected; | ||
53 | |||
54 | UI_ACCOUNT_CREATE_DIALOG_Handle create_dialog; | ||
55 | } UI_ACCOUNTS_Handle; | ||
56 | |||
57 | #define UI_ACCOUNTS_ROWS_MIN 5 | ||
58 | #define UI_ACCOUNTS_COLS_MIN 30 | ||
59 | |||
60 | /** | ||
61 | * Processes the current key event by the view | ||
62 | * to show the list of chat accounts. | ||
63 | * | ||
64 | * @param[in,out] accounts Chat accounts view | ||
65 | * @param[in,out] app Application handle | ||
66 | * @param[in] key Key | ||
67 | */ | ||
68 | void | ||
69 | accounts_event(UI_ACCOUNTS_Handle *accounts, | ||
70 | struct MESSENGER_Application *app, | ||
71 | int key); | ||
72 | |||
73 | /** | ||
74 | * Prints the content of the view to show | ||
75 | * the list of chat accounts to its selected | ||
76 | * window view on screen. | ||
77 | * | ||
78 | * @param[in,out] accounts Chat accounts view | ||
79 | * @param[in] app Application handle | ||
80 | */ | ||
81 | void | ||
82 | accounts_print(UI_ACCOUNTS_Handle *accounts, | ||
83 | struct MESSENGER_Application *app); | ||
84 | |||
85 | #endif /* UI_ACCOUNTS_H_ */ | ||
diff --git a/src/ui/chat.h b/src/ui/chat.h new file mode 100644 index 0000000..582ba66 --- /dev/null +++ b/src/ui/chat.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chat.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_CHAT_H_ | ||
26 | #define UI_CHAT_H_ | ||
27 | |||
28 | #include "members.h" | ||
29 | #include "messages.h" | ||
30 | |||
31 | /** | ||
32 | * @struct UI_CHAT_Handle | ||
33 | */ | ||
34 | typedef struct UI_CHAT_Handle | ||
35 | { | ||
36 | UI_MEMBERS_Handle members; | ||
37 | UI_MESSAGES_Handle messages; | ||
38 | } UI_CHAT_Handle; | ||
39 | |||
40 | #endif /* UI_CHAT_H_ */ | ||
diff --git a/src/ui/chat_open_dialog.c b/src/ui/chat_open_dialog.c new file mode 100644 index 0000000..1ea5863 --- /dev/null +++ b/src/ui/chat_open_dialog.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chat_open_dialog.c | ||
23 | */ | ||
24 | |||
25 | #include "chat_open_dialog.h" | ||
26 | |||
27 | #include <gnunet/gnunet_chat_lib.h> | ||
28 | #include <gnunet/gnunet_util_lib.h> | ||
29 | |||
30 | #include "text_input.h" | ||
31 | #include "../application.h" | ||
32 | |||
33 | void | ||
34 | chat_open_dialog_event(UI_CHAT_OPEN_DIALOG_Handle *open_dialog, | ||
35 | struct MESSENGER_Application *app, | ||
36 | int key) | ||
37 | { | ||
38 | switch (key) | ||
39 | { | ||
40 | case 27: | ||
41 | case KEY_EXIT: | ||
42 | open_dialog->window = NULL; | ||
43 | break; | ||
44 | case '\n': | ||
45 | case KEY_ENTER: | ||
46 | if (open_dialog->topic_len > 0) | ||
47 | GNUNET_CHAT_group_create(app->chat.handle, open_dialog->topic); | ||
48 | |||
49 | open_dialog->topic_len = 0; | ||
50 | open_dialog->window = NULL; | ||
51 | break; | ||
52 | default: | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | text_input_event(open_dialog->topic, key); | ||
57 | } | ||
58 | |||
59 | void | ||
60 | chat_open_dialog_print(UI_CHAT_OPEN_DIALOG_Handle *open_dialog) | ||
61 | { | ||
62 | if (!(open_dialog->window)) | ||
63 | return; | ||
64 | |||
65 | WINDOW *window = *(open_dialog->window); | ||
66 | |||
67 | werase(window); | ||
68 | wmove(window, 0, 0); | ||
69 | |||
70 | wprintw(window, "%s", open_dialog->topic); | ||
71 | wmove(window, 0, open_dialog->topic_pos); | ||
72 | |||
73 | wcursyncup(window); | ||
74 | curs_set(1); | ||
75 | } | ||
diff --git a/src/ui/chat_open_dialog.h b/src/ui/chat_open_dialog.h new file mode 100644 index 0000000..413d15e --- /dev/null +++ b/src/ui/chat_open_dialog.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chat_open_dialog.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_CHAT_OPEN_DIALOG_H_ | ||
26 | #define UI_CHAT_OPEN_DIALOG_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | struct MESSENGER_Application; | ||
32 | |||
33 | /** | ||
34 | * @struct UI_CHAT_OPEN_DIALOG_Handle | ||
35 | */ | ||
36 | typedef struct UI_CHAT_OPEN_DIALOG_Handle | ||
37 | { | ||
38 | WINDOW **window; | ||
39 | |||
40 | char topic [256]; | ||
41 | int topic_len; | ||
42 | int topic_pos; | ||
43 | } UI_CHAT_OPEN_DIALOG_Handle; | ||
44 | |||
45 | /** | ||
46 | * Processes the current key event by the dialog | ||
47 | * to open a chat. | ||
48 | * | ||
49 | * @param[in,out] open_dialog Chat opening dialog | ||
50 | * @param[in,out] app Application handle | ||
51 | * @param[in] key Key | ||
52 | */ | ||
53 | void | ||
54 | chat_open_dialog_event(UI_CHAT_OPEN_DIALOG_Handle *open_dialog, | ||
55 | struct MESSENGER_Application *app, | ||
56 | int key); | ||
57 | |||
58 | /** | ||
59 | * Prints the content of the dialog to open a | ||
60 | * chat to its selected window view. | ||
61 | * | ||
62 | * @param[in] open_dialog Chat opening dialog | ||
63 | */ | ||
64 | void | ||
65 | chat_open_dialog_print(UI_CHAT_OPEN_DIALOG_Handle *open_dialog); | ||
66 | |||
67 | #endif /* UI_CHAT_OPEN_DIALOG_H_ */ | ||
diff --git a/src/ui/chats.c b/src/ui/chats.c new file mode 100644 index 0000000..5889dd4 --- /dev/null +++ b/src/ui/chats.c | |||
@@ -0,0 +1,239 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2024 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chats.c | ||
23 | */ | ||
24 | |||
25 | #include "chats.h" | ||
26 | |||
27 | #include "list_input.h" | ||
28 | #include "../application.h" | ||
29 | #include "../util.h" | ||
30 | #include <gnunet/gnunet_chat_lib.h> | ||
31 | #include <gnunet/gnunet_common.h> | ||
32 | |||
33 | static enum GNUNET_GenericReturnValue | ||
34 | _chats_iterate_group(void *cls, | ||
35 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
36 | struct GNUNET_CHAT_Group *group) | ||
37 | { | ||
38 | UI_CHATS_Handle *chats = cls; | ||
39 | list_input_select(chats, 1, GNUNET_CHAT_group_get_context(group)); | ||
40 | return GNUNET_YES; | ||
41 | } | ||
42 | |||
43 | static enum GNUNET_GenericReturnValue | ||
44 | _chats_iterate_contact(void *cls, | ||
45 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
46 | struct GNUNET_CHAT_Contact *contact) | ||
47 | { | ||
48 | UI_CHATS_Handle *chats = cls; | ||
49 | |||
50 | if (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact)) | ||
51 | return GNUNET_YES; | ||
52 | |||
53 | list_input_select(chats, 1, GNUNET_CHAT_contact_get_context(contact)); | ||
54 | return GNUNET_YES; | ||
55 | } | ||
56 | |||
57 | static enum GNUNET_GenericReturnValue | ||
58 | _chats_iterate_messages(void *cls, | ||
59 | struct GNUNET_CHAT_Context *context, | ||
60 | const struct GNUNET_CHAT_Message *message) | ||
61 | { | ||
62 | MESSENGER_Chat *chat = cls; | ||
63 | chat_process_message(chat, context, message); | ||
64 | return GNUNET_YES; | ||
65 | } | ||
66 | |||
67 | void | ||
68 | chats_event(UI_CHATS_Handle *chats, | ||
69 | MESSENGER_Application *app, | ||
70 | int key) | ||
71 | { | ||
72 | if (chats->open_dialog.window) | ||
73 | { | ||
74 | chat_open_dialog_event(&(chats->open_dialog), app, key); | ||
75 | return; | ||
76 | } | ||
77 | else if (chats->create_dialog.win) | ||
78 | { | ||
79 | lobby_create_dialog_event(&(chats->create_dialog), app, key); | ||
80 | return; | ||
81 | } | ||
82 | else if (chats->enter_dialog.window) | ||
83 | { | ||
84 | lobby_enter_dialog_event(&(chats->enter_dialog), app, key); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | list_input_reset(chats); | ||
89 | |||
90 | GNUNET_CHAT_iterate_groups( | ||
91 | app->chat.handle, | ||
92 | &_chats_iterate_group, | ||
93 | chats | ||
94 | ); | ||
95 | |||
96 | GNUNET_CHAT_iterate_contacts( | ||
97 | app->chat.handle, | ||
98 | &_chats_iterate_contact, | ||
99 | chats | ||
100 | ); | ||
101 | |||
102 | list_input_select(chats, 1, NULL); | ||
103 | list_input_select(chats, 1, NULL); | ||
104 | list_input_select(chats, 1, NULL); | ||
105 | |||
106 | const int count = chats->line_index; | ||
107 | |||
108 | switch (key) | ||
109 | { | ||
110 | case 27: | ||
111 | case KEY_EXIT: | ||
112 | GNUNET_CHAT_disconnect(app->chat.handle); | ||
113 | break; | ||
114 | case '\n': | ||
115 | case KEY_ENTER: | ||
116 | if (chats->selected) | ||
117 | { | ||
118 | GNUNET_CHAT_context_request(chats->selected); | ||
119 | |||
120 | members_clear(&(app->current.members)); | ||
121 | messages_clear(&(app->current.messages)); | ||
122 | |||
123 | GNUNET_CHAT_context_set_user_pointer( | ||
124 | chats->selected, | ||
125 | &(app->current) | ||
126 | ); | ||
127 | |||
128 | GNUNET_CHAT_context_iterate_messages( | ||
129 | chats->selected, | ||
130 | &_chats_iterate_messages, | ||
131 | &(app->chat) | ||
132 | ); | ||
133 | |||
134 | app->chat.context = chats->selected; | ||
135 | } | ||
136 | else if (chats->line_selected == count - 3) | ||
137 | chats->open_dialog.window = &(chats->window); | ||
138 | else if (chats->line_selected == count - 2) | ||
139 | chats->create_dialog.win = &(chats->window); | ||
140 | else if (chats->line_selected == count - 1) | ||
141 | chats->enter_dialog.window = &(chats->window); | ||
142 | break; | ||
143 | default: | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | list_input_event(chats, key); | ||
148 | } | ||
149 | |||
150 | static int | ||
151 | _chats_print_entry(UI_CHATS_Handle *chats, | ||
152 | char type, | ||
153 | char chat_type, | ||
154 | const char *text) | ||
155 | { | ||
156 | list_input_print_gnunet(chats, 1); | ||
157 | |||
158 | const int attrs_select = A_BOLD; | ||
159 | |||
160 | if (selected) wattron(chats->window, attrs_select); | ||
161 | |||
162 | wmove(chats->window, y, 0); | ||
163 | |||
164 | if (chat_type) | ||
165 | wprintw(chats->window, "[%c][%c] %s", type, chat_type, text); | ||
166 | else | ||
167 | wprintw(chats->window, "[%c] %s", type, text); | ||
168 | |||
169 | if (selected) wattroff(chats->window, attrs_select); | ||
170 | |||
171 | return GNUNET_YES; | ||
172 | } | ||
173 | |||
174 | enum GNUNET_GenericReturnValue | ||
175 | _chats_iterate_print_group(void *cls, | ||
176 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
177 | struct GNUNET_CHAT_Group *group) | ||
178 | { | ||
179 | UI_CHATS_Handle *chats = cls; | ||
180 | const char *name = GNUNET_CHAT_group_get_name(group); | ||
181 | return _chats_print_entry(chats, 'x', 'G', name); | ||
182 | } | ||
183 | |||
184 | enum GNUNET_GenericReturnValue | ||
185 | _chats_iterate_print_contact(void *cls, | ||
186 | UNUSED struct GNUNET_CHAT_Handle *handle, | ||
187 | struct GNUNET_CHAT_Contact *contact) | ||
188 | { | ||
189 | UI_CHATS_Handle *chats = cls; | ||
190 | |||
191 | if (GNUNET_YES == GNUNET_CHAT_contact_is_owned(contact)) | ||
192 | return GNUNET_YES; | ||
193 | |||
194 | const char *name = GNUNET_CHAT_contact_get_name(contact); | ||
195 | return _chats_print_entry(chats, 'x', 'C', name); | ||
196 | } | ||
197 | |||
198 | void | ||
199 | chats_print(UI_CHATS_Handle *chats, | ||
200 | MESSENGER_Application *app) | ||
201 | { | ||
202 | if (chats->open_dialog.window) | ||
203 | { | ||
204 | chat_open_dialog_print(&(chats->open_dialog)); | ||
205 | return; | ||
206 | } | ||
207 | else if (chats->create_dialog.win) | ||
208 | { | ||
209 | lobby_create_dialog_print(&(chats->create_dialog)); | ||
210 | return; | ||
211 | } | ||
212 | else if (chats->enter_dialog.window) | ||
213 | { | ||
214 | lobby_enter_dialog_print(&(chats->enter_dialog)); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | if (!(chats->window)) | ||
219 | return; | ||
220 | |||
221 | list_input_reset(chats); | ||
222 | werase(chats->window); | ||
223 | |||
224 | GNUNET_CHAT_iterate_groups( | ||
225 | app->chat.handle, | ||
226 | &_chats_iterate_print_group, | ||
227 | chats | ||
228 | ); | ||
229 | |||
230 | GNUNET_CHAT_iterate_contacts( | ||
231 | app->chat.handle, | ||
232 | &_chats_iterate_print_contact, | ||
233 | chats | ||
234 | ); | ||
235 | |||
236 | _chats_print_entry(chats, '+', '\0', "Add chat"); | ||
237 | _chats_print_entry(chats, '+', '\0', "Open lobby"); | ||
238 | _chats_print_entry(chats, '+', '\0', "Enter lobby"); | ||
239 | } | ||
diff --git a/src/ui/chats.h b/src/ui/chats.h new file mode 100644 index 0000000..eb0ba99 --- /dev/null +++ b/src/ui/chats.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/chats.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_CHATS_H_ | ||
26 | #define UI_CHATS_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | #include <gnunet/gnunet_chat_lib.h> | ||
32 | #include <gnunet/gnunet_util_lib.h> | ||
33 | |||
34 | #include "chat_open_dialog.h" | ||
35 | #include "lobby_create_dialog.h" | ||
36 | #include "lobby_enter_dialog.h" | ||
37 | |||
38 | struct MESSENGER_Application; | ||
39 | |||
40 | /** | ||
41 | * @struct UI_CHATS_Handle | ||
42 | */ | ||
43 | typedef struct UI_CHATS_Handle | ||
44 | { | ||
45 | WINDOW *window; | ||
46 | |||
47 | int line_prev; | ||
48 | int line_next; | ||
49 | |||
50 | int line_index; | ||
51 | int line_offset; | ||
52 | int line_selected; | ||
53 | |||
54 | struct GNUNET_CHAT_Context *selected; | ||
55 | |||
56 | UI_CHAT_OPEN_DIALOG_Handle open_dialog; | ||
57 | UI_LOBBY_CREATE_DIALOG_Handle create_dialog; | ||
58 | UI_LOBBY_ENTER_DIALOG_Handle enter_dialog; | ||
59 | } UI_CHATS_Handle; | ||
60 | |||
61 | #define UI_CHATS_ROWS_MIN 8 | ||
62 | #define UI_CHATS_COLS_MIN 30 | ||
63 | |||
64 | /** | ||
65 | * Processes the current key event by the view | ||
66 | * to show the list of available chats. | ||
67 | * | ||
68 | * @param[in,out] chats Chats view | ||
69 | * @param[in,out] app Application handle | ||
70 | * @param[in] key Key | ||
71 | */ | ||
72 | void | ||
73 | chats_event(UI_CHATS_Handle *chats, | ||
74 | struct MESSENGER_Application *app, | ||
75 | int key); | ||
76 | |||
77 | /** | ||
78 | * Prints the content of the view to show | ||
79 | * the list of available chats to its selected | ||
80 | * window view on screen. | ||
81 | * | ||
82 | * @param[in,out] chats Chats view | ||
83 | * @param[in] app Application handle | ||
84 | */ | ||
85 | void | ||
86 | chats_print(UI_CHATS_Handle *chats, | ||
87 | struct MESSENGER_Application *app); | ||
88 | |||
89 | #endif /* UI_CHATS_H_ */ | ||
diff --git a/src/ui/list_input.h b/src/ui/list_input.h new file mode 100644 index 0000000..4fea1f4 --- /dev/null +++ b/src/ui/list_input.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/list_input.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_LIST_INPUT_H_ | ||
26 | #define UI_LIST_INPUT_H_ | ||
27 | |||
28 | #include <stdbool.h> | ||
29 | #include <stdlib.h> | ||
30 | |||
31 | /** | ||
32 | * Resets the list controls. | ||
33 | */ | ||
34 | #define list_input_reset(list) { \ | ||
35 | (list)->line_prev = 0; \ | ||
36 | (list)->line_next = 0; \ | ||
37 | (list)->line_index = 0; \ | ||
38 | (list)->selected = 0; \ | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * Handles the list controls selection and | ||
43 | * indices to move the selection via events. | ||
44 | */ | ||
45 | #define list_input_select(list, line_width, item) { \ | ||
46 | const bool selected = ( \ | ||
47 | ((list)->line_selected >= (list)->line_index) && \ | ||
48 | ((list)->line_selected < (list)->line_index + (line_width)) \ | ||
49 | ); \ | ||
50 | \ | ||
51 | if ((!selected) && ((list)->line_selected > (list)->line_index)) \ | ||
52 | (list)->line_prev = (list)->line_index; \ | ||
53 | \ | ||
54 | (list)->line_index += (line_width); \ | ||
55 | \ | ||
56 | if (selected) { \ | ||
57 | (list)->line_next = (list)->line_index; \ | ||
58 | (list)->selected = item; \ | ||
59 | } \ | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * Handles the key event to move the selection | ||
64 | * of list controls and adjust its view area. | ||
65 | */ | ||
66 | #define list_input_event(list, key) { \ | ||
67 | int count = (list)->line_index; \ | ||
68 | \ | ||
69 | switch (key) \ | ||
70 | { \ | ||
71 | case KEY_UP: \ | ||
72 | { \ | ||
73 | (list)->line_selected = (list)->line_prev; \ | ||
74 | break; \ | ||
75 | } \ | ||
76 | case KEY_DOWN: \ | ||
77 | { \ | ||
78 | (list)->line_selected = (list)->line_next; \ | ||
79 | break; \ | ||
80 | } \ | ||
81 | default: \ | ||
82 | break; \ | ||
83 | } \ | ||
84 | \ | ||
85 | if ((list)->line_selected < 0) \ | ||
86 | (list)->line_selected = 0; \ | ||
87 | else if ((list)->line_selected >= count) \ | ||
88 | (list)->line_selected = count - 1; \ | ||
89 | \ | ||
90 | if ((list)->window) \ | ||
91 | { \ | ||
92 | const int height = getmaxy((list)->window); \ | ||
93 | const int y = (list)->line_selected - (list)->line_offset; \ | ||
94 | \ | ||
95 | if (y < 0) \ | ||
96 | (list)->line_offset += y; \ | ||
97 | else if (y + 1 >= height) \ | ||
98 | (list)->line_offset += y + 1 - height; \ | ||
99 | \ | ||
100 | if ((list)->line_offset < 0) \ | ||
101 | (list)->line_offset = 0; \ | ||
102 | else if ((list)->line_offset >= count) \ | ||
103 | (list)->line_offset = count - 1; \ | ||
104 | } \ | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Prepares for printing an item in list controls | ||
109 | * as well as providing its selection and its | ||
110 | * y location in the current view. | ||
111 | */ | ||
112 | #define list_input_print_(list, line_width, yes_res, no_res) \ | ||
113 | const bool selected = ( \ | ||
114 | ((list)->line_selected >= (list)->line_index) && \ | ||
115 | ((list)->line_selected < (list)->line_index + (line_width)) \ | ||
116 | ); \ | ||
117 | \ | ||
118 | const int y = (list)->line_index - (list)->line_offset; { \ | ||
119 | \ | ||
120 | (list)->line_index += (line_width); \ | ||
121 | \ | ||
122 | if (y + (line_width) < 1) \ | ||
123 | return yes_res; \ | ||
124 | \ | ||
125 | const int height = getmaxy((list)->window); \ | ||
126 | \ | ||
127 | if (y >= height) \ | ||
128 | return no_res; \ | ||
129 | } | ||
130 | |||
131 | #define list_input_print_gnunet(list, line_width) \ | ||
132 | list_input_print_(list, line_width, GNUNET_YES, GNUNET_NO) | ||
133 | |||
134 | #define list_input_print(list, line_width) \ | ||
135 | list_input_print_(list, line_width, , ) | ||
136 | |||
137 | #endif /* UI_LIST_INPUT_H_ */ | ||
diff --git a/src/ui/lobby_create_dialog.c b/src/ui/lobby_create_dialog.c new file mode 100644 index 0000000..61c1a4c --- /dev/null +++ b/src/ui/lobby_create_dialog.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/lobby_create_dialog.c | ||
23 | */ | ||
24 | |||
25 | #include "lobby_create_dialog.h" | ||
26 | |||
27 | #include "list_input.h" | ||
28 | #include "../application.h" | ||
29 | #include "../util.h" | ||
30 | |||
31 | void | ||
32 | _lobby_open_with_uri(void *cls, | ||
33 | const struct GNUNET_CHAT_Uri *uri) | ||
34 | { | ||
35 | UI_LOBBY_CREATE_DIALOG_Handle *create_dialog = cls; | ||
36 | |||
37 | if (create_dialog->uri) | ||
38 | GNUNET_free(create_dialog->uri); | ||
39 | |||
40 | create_dialog->uri = GNUNET_CHAT_uri_to_string(uri); | ||
41 | } | ||
42 | |||
43 | void | ||
44 | lobby_create_dialog_event(UI_LOBBY_CREATE_DIALOG_Handle *create_dialog, | ||
45 | UNUSED struct MESSENGER_Application *app, | ||
46 | int key) | ||
47 | { | ||
48 | create_dialog->window = *(create_dialog->win); | ||
49 | |||
50 | list_input_reset(create_dialog); | ||
51 | |||
52 | if (create_dialog->uri) | ||
53 | list_input_select(create_dialog, 1, 0) | ||
54 | else | ||
55 | { | ||
56 | list_input_select(create_dialog, 1, 30); | ||
57 | list_input_select(create_dialog, 1, 5 * 60); | ||
58 | list_input_select(create_dialog, 1, 60 * 60); | ||
59 | list_input_select(create_dialog, 1, 8 * 60 * 60); | ||
60 | list_input_select(create_dialog, 1, 24 * 60 * 60); | ||
61 | list_input_select(create_dialog, 1, 7 * 24 * 60 * 60); | ||
62 | list_input_select(create_dialog, 1, 4 * 7 * 60 * 60); | ||
63 | list_input_select(create_dialog, 1, 0); | ||
64 | } | ||
65 | |||
66 | switch (key) | ||
67 | { | ||
68 | case 27: | ||
69 | case KEY_EXIT: | ||
70 | if (create_dialog->lobby) | ||
71 | GNUNET_CHAT_lobby_close(create_dialog->lobby); | ||
72 | |||
73 | create_dialog->lobby = NULL; | ||
74 | create_dialog->win = NULL; | ||
75 | break; | ||
76 | case '\n': | ||
77 | case KEY_ENTER: | ||
78 | if (create_dialog->uri) | ||
79 | { | ||
80 | GNUNET_free(create_dialog->uri); | ||
81 | |||
82 | create_dialog->lobby = NULL; | ||
83 | create_dialog->win = NULL; | ||
84 | } | ||
85 | else if (!(create_dialog->lobby)) | ||
86 | create_dialog->lobby = GNUNET_CHAT_lobby_open( | ||
87 | app->chat.handle, | ||
88 | GNUNET_TIME_relative_multiply( | ||
89 | GNUNET_TIME_relative_get_second_(), | ||
90 | create_dialog->selected | ||
91 | ), | ||
92 | _lobby_open_with_uri, | ||
93 | create_dialog | ||
94 | ); | ||
95 | |||
96 | break; | ||
97 | default: | ||
98 | break; | ||
99 | } | ||
100 | |||
101 | if (!(create_dialog->lobby)) | ||
102 | list_input_event(create_dialog, key) | ||
103 | else | ||
104 | list_input_event(create_dialog, KEY_RESIZE); | ||
105 | } | ||
106 | |||
107 | static void | ||
108 | _lobby_iterate_print(UI_LOBBY_CREATE_DIALOG_Handle *create_dialog, | ||
109 | const char *label) | ||
110 | { | ||
111 | list_input_print(create_dialog, 1); | ||
112 | |||
113 | const int attrs_select = A_BOLD; | ||
114 | |||
115 | if (selected) wattron(create_dialog->window, attrs_select); | ||
116 | |||
117 | wmove(create_dialog->window, y, 0); | ||
118 | wprintw(create_dialog->window, "%s", label); | ||
119 | |||
120 | if (selected) wattroff(create_dialog->window, attrs_select); | ||
121 | } | ||
122 | |||
123 | void | ||
124 | lobby_create_dialog_print(UI_LOBBY_CREATE_DIALOG_Handle *create_dialog) | ||
125 | { | ||
126 | if (!(create_dialog->win)) | ||
127 | return; | ||
128 | |||
129 | create_dialog->window = *(create_dialog->win); | ||
130 | |||
131 | list_input_reset(create_dialog); | ||
132 | werase(create_dialog->window); | ||
133 | |||
134 | if (create_dialog->uri) | ||
135 | _lobby_iterate_print(create_dialog, create_dialog->uri); | ||
136 | else | ||
137 | { | ||
138 | _lobby_iterate_print(create_dialog, "30 seconds"); | ||
139 | _lobby_iterate_print(create_dialog, "5 minutes"); | ||
140 | _lobby_iterate_print(create_dialog, "1 hour"); | ||
141 | _lobby_iterate_print(create_dialog, "8 hours"); | ||
142 | _lobby_iterate_print(create_dialog, "1 day"); | ||
143 | _lobby_iterate_print(create_dialog, "1 week"); | ||
144 | _lobby_iterate_print(create_dialog, "4 weeks"); | ||
145 | _lobby_iterate_print(create_dialog, "Off"); | ||
146 | } | ||
147 | } | ||
diff --git a/src/ui/lobby_create_dialog.h b/src/ui/lobby_create_dialog.h new file mode 100644 index 0000000..4ec5501 --- /dev/null +++ b/src/ui/lobby_create_dialog.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/lobby_create_dialog.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_LOBBY_CREATE_DIALOG_H_ | ||
26 | #define UI_LOBBY_CREATE_DIALOG_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | #include <gnunet/gnunet_chat_lib.h> | ||
32 | #include <gnunet/gnunet_util_lib.h> | ||
33 | |||
34 | struct MESSENGER_Application; | ||
35 | |||
36 | /** | ||
37 | * @struct UI_LOBBY_CREATE_DIALOG_Handle | ||
38 | */ | ||
39 | typedef struct UI_LOBBY_CREATE_DIALOG_Handle | ||
40 | { | ||
41 | WINDOW *window; | ||
42 | WINDOW **win; | ||
43 | |||
44 | int line_prev; | ||
45 | int line_next; | ||
46 | |||
47 | int line_index; | ||
48 | int line_offset; | ||
49 | int line_selected; | ||
50 | |||
51 | uint64_t selected; | ||
52 | |||
53 | struct GNUNET_CHAT_Lobby *lobby; | ||
54 | char *uri; | ||
55 | } UI_LOBBY_CREATE_DIALOG_Handle; | ||
56 | |||
57 | /** | ||
58 | * Processes the current key event by the dialog | ||
59 | * to create a lobby. | ||
60 | * | ||
61 | * @param[in,out] create_dialog Lobby creation dialog | ||
62 | * @param[in,out] app Application handle | ||
63 | * @param[in] key Key | ||
64 | */ | ||
65 | void | ||
66 | lobby_create_dialog_event(UI_LOBBY_CREATE_DIALOG_Handle *create_dialog, | ||
67 | struct MESSENGER_Application *app, | ||
68 | int key); | ||
69 | |||
70 | /** | ||
71 | * Prints the content of the dialog to create a | ||
72 | * lobby to its selected window view. | ||
73 | * | ||
74 | * @param[in] create_dialog Lobby creation dialog | ||
75 | */ | ||
76 | void | ||
77 | lobby_create_dialog_print(UI_LOBBY_CREATE_DIALOG_Handle *create_dialog); | ||
78 | |||
79 | #endif /* UI_LOBBY_CREATE_DIALOG_H_ */ | ||
diff --git a/src/ui/lobby_enter_dialog.c b/src/ui/lobby_enter_dialog.c new file mode 100644 index 0000000..a3ef356 --- /dev/null +++ b/src/ui/lobby_enter_dialog.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/lobby_enter_dialog.c | ||
23 | */ | ||
24 | |||
25 | #include "lobby_enter_dialog.h" | ||
26 | |||
27 | #include <gnunet/gnunet_chat_lib.h> | ||
28 | #include <gnunet/gnunet_util_lib.h> | ||
29 | |||
30 | #include "text_input.h" | ||
31 | #include "../application.h" | ||
32 | |||
33 | void | ||
34 | lobby_enter_dialog_event(UI_LOBBY_ENTER_DIALOG_Handle *enter_dialog, | ||
35 | struct MESSENGER_Application *app, | ||
36 | int key) | ||
37 | { | ||
38 | struct GNUNET_CHAT_Uri *uri; | ||
39 | |||
40 | switch (key) | ||
41 | { | ||
42 | case 27: | ||
43 | case KEY_EXIT: | ||
44 | if (enter_dialog->error) | ||
45 | GNUNET_free(enter_dialog->error); | ||
46 | |||
47 | enter_dialog->error = NULL; | ||
48 | enter_dialog->window = NULL; | ||
49 | break; | ||
50 | case '\n': | ||
51 | case KEY_ENTER: | ||
52 | if (enter_dialog->uri_len > 0) | ||
53 | { | ||
54 | if (enter_dialog->error) | ||
55 | GNUNET_free(enter_dialog->error); | ||
56 | |||
57 | enter_dialog->error = NULL; | ||
58 | uri = GNUNET_CHAT_uri_parse(enter_dialog->uri, &(enter_dialog->error)); | ||
59 | |||
60 | if (uri) | ||
61 | { | ||
62 | GNUNET_CHAT_lobby_join(app->chat.handle, uri); | ||
63 | GNUNET_CHAT_uri_destroy(uri); | ||
64 | |||
65 | enter_dialog->uri_len = 0; | ||
66 | enter_dialog->window = NULL; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | break; | ||
71 | default: | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | text_input_event(enter_dialog->uri, key); | ||
76 | } | ||
77 | |||
78 | void | ||
79 | lobby_enter_dialog_print(UI_LOBBY_ENTER_DIALOG_Handle *enter_dialog) | ||
80 | { | ||
81 | if (!(enter_dialog->window)) | ||
82 | return; | ||
83 | |||
84 | WINDOW *window = *(enter_dialog->window); | ||
85 | |||
86 | werase(window); | ||
87 | wmove(window, 0, 0); | ||
88 | |||
89 | wprintw(window, "%s", enter_dialog->uri); | ||
90 | |||
91 | if (enter_dialog->error) | ||
92 | { | ||
93 | wmove(window, 1, 0); | ||
94 | wprintw(window, "ERROR: %s", enter_dialog->error); | ||
95 | } | ||
96 | |||
97 | wmove(window, 0, enter_dialog->uri_pos); | ||
98 | |||
99 | wcursyncup(window); | ||
100 | curs_set(1); | ||
101 | } | ||
diff --git a/src/ui/lobby_enter_dialog.h b/src/ui/lobby_enter_dialog.h new file mode 100644 index 0000000..8e7cc05 --- /dev/null +++ b/src/ui/lobby_enter_dialog.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/lobby_enter_dialog.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_LOBBY_ENTER_DIALOG_H_ | ||
26 | #define UI_LOBBY_ENTER_DIALOG_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <curses.h> | ||
30 | |||
31 | struct MESSENGER_Application; | ||
32 | |||
33 | /** | ||
34 | * @struct UI_LOBBY_ENTER_DIALOG_Handle | ||
35 | */ | ||
36 | typedef struct UI_LOBBY_ENTER_DIALOG_Handle | ||
37 | { | ||
38 | WINDOW **window; | ||
39 | |||
40 | char *error; | ||
41 | |||
42 | char uri [2048]; | ||
43 | int uri_len; | ||
44 | int uri_pos; | ||
45 | } UI_LOBBY_ENTER_DIALOG_Handle; | ||
46 | |||
47 | /** | ||
48 | * Processes the current key event by the dialog | ||
49 | * to enter a lobby. | ||
50 | * | ||
51 | * @param[in,out] enter_dialog Lobby entry dialog | ||
52 | * @param[in,out] app Application handle | ||
53 | * @param[in] key Key | ||
54 | */ | ||
55 | void | ||
56 | lobby_enter_dialog_event(UI_LOBBY_ENTER_DIALOG_Handle *enter_dialog, | ||
57 | struct MESSENGER_Application *app, | ||
58 | int key); | ||
59 | |||
60 | /** | ||
61 | * Prints the content of the dialog to enter a | ||
62 | * lobby to its selected window view. | ||
63 | * | ||
64 | * @param[in] enter_dialog Lobby entry dialog | ||
65 | */ | ||
66 | void | ||
67 | lobby_enter_dialog_print(UI_LOBBY_ENTER_DIALOG_Handle *enter_dialog); | ||
68 | |||
69 | #endif /* UI_LOBBY_ENTER_DIALOG_H_ */ | ||
diff --git a/src/ui/members.c b/src/ui/members.c new file mode 100644 index 0000000..7e3239f --- /dev/null +++ b/src/ui/members.c | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/members.c | ||
23 | */ | ||
24 | |||
25 | #include "members.h" | ||
26 | |||
27 | #include "list_input.h" | ||
28 | #include "../application.h" | ||
29 | #include "../util.h" | ||
30 | |||
31 | void | ||
32 | members_event(UI_MEMBERS_Handle *members, | ||
33 | struct MESSENGER_Application *app, | ||
34 | int key) | ||
35 | { | ||
36 | list_input_reset(members); | ||
37 | |||
38 | UI_MEMBERS_List *element = members->head; | ||
39 | while (element) | ||
40 | { | ||
41 | list_input_select(members, 1, element->contact); | ||
42 | element = element->next; | ||
43 | } | ||
44 | |||
45 | switch (key) | ||
46 | { | ||
47 | case 27: | ||
48 | case KEY_EXIT: | ||
49 | case '\t': | ||
50 | app->chat.show_members = FALSE; | ||
51 | break; | ||
52 | case '\n': | ||
53 | case KEY_ENTER: { | ||
54 | struct GNUNET_CHAT_Context *context; | ||
55 | |||
56 | if (!(members->selected)) | ||
57 | break; | ||
58 | |||
59 | context = GNUNET_CHAT_contact_get_context(members->selected); | ||
60 | GNUNET_CHAT_context_request(context); | ||
61 | |||
62 | app->chat.show_members = FALSE; | ||
63 | app->chat.context = context; | ||
64 | break; | ||
65 | } | ||
66 | default: | ||
67 | break; | ||
68 | } | ||
69 | |||
70 | list_input_event(members, key); | ||
71 | } | ||
72 | |||
73 | static void | ||
74 | _members_iterate_print(UI_MEMBERS_Handle *members, | ||
75 | const struct GNUNET_CHAT_Contact *contact) | ||
76 | { | ||
77 | list_input_print(members, 1); | ||
78 | |||
79 | const int attrs_select = A_BOLD; | ||
80 | |||
81 | if (selected) wattron(members->window, attrs_select); | ||
82 | |||
83 | wmove(members->window, y, 0); | ||
84 | |||
85 | const char *name = GNUNET_CHAT_contact_get_name(contact); | ||
86 | const char *key = GNUNET_CHAT_contact_get_key(contact); | ||
87 | |||
88 | size_t key_len = key? strlen(key) : 0; | ||
89 | |||
90 | if (key_len > 4) | ||
91 | wprintw(members->window, "[%s]: %s", key + (key_len - 4), name); | ||
92 | else | ||
93 | wprintw(members->window, "%s", name); | ||
94 | |||
95 | if (selected) wattroff(members->window, attrs_select); | ||
96 | } | ||
97 | |||
98 | void | ||
99 | members_print(UI_MEMBERS_Handle *members) | ||
100 | { | ||
101 | if (!(members->window)) | ||
102 | return; | ||
103 | |||
104 | list_input_reset(members); | ||
105 | werase(members->window); | ||
106 | |||
107 | UI_MEMBERS_List *element = members->head; | ||
108 | while (element) | ||
109 | { | ||
110 | _members_iterate_print(members, element->contact); | ||
111 | element = element->next; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | void | ||
116 | members_clear(UI_MEMBERS_Handle *members) | ||
117 | { | ||
118 | UI_MEMBERS_List *element; | ||
119 | while (members->head) | ||
120 | { | ||
121 | element = members->head; | ||
122 | |||
123 | GNUNET_CONTAINER_DLL_remove( | ||
124 | members->head, | ||
125 | members->tail, | ||
126 | element | ||
127 | ); | ||
128 | |||
129 | GNUNET_free(element); | ||
130 | } | ||
131 | |||
132 | members->line_selected = 0; | ||
133 | } | ||
134 | |||
135 | bool | ||
136 | members_add(UI_MEMBERS_Handle *members, | ||
137 | struct GNUNET_CHAT_Contact *contact) | ||
138 | { | ||
139 | UI_MEMBERS_List *element = members->head; | ||
140 | while (element) | ||
141 | { | ||
142 | if (element->contact == contact) | ||
143 | break; | ||
144 | |||
145 | element = element->next; | ||
146 | } | ||
147 | |||
148 | if (element) | ||
149 | return FALSE; | ||
150 | |||
151 | element = GNUNET_new(UI_MEMBERS_List); | ||
152 | element->contact = contact; | ||
153 | |||
154 | GNUNET_CONTAINER_DLL_insert_tail( | ||
155 | members->head, | ||
156 | members->tail, | ||
157 | element | ||
158 | ); | ||
159 | |||
160 | return TRUE; | ||
161 | } | ||
162 | |||
163 | void | ||
164 | members_remove(UI_MEMBERS_Handle *members, | ||
165 | const struct GNUNET_CHAT_Contact *contact) | ||
166 | { | ||
167 | UI_MEMBERS_List *element = members->head; | ||
168 | while (element) | ||
169 | { | ||
170 | if (element->contact == contact) | ||
171 | break; | ||
172 | |||
173 | element = element->next; | ||
174 | } | ||
175 | |||
176 | if (element) | ||
177 | GNUNET_CONTAINER_DLL_remove( | ||
178 | members->head, | ||
179 | members->tail, | ||
180 | element | ||
181 | ); | ||
182 | } | ||
diff --git a/src/ui/members.h b/src/ui/members.h new file mode 100644 index 0000000..9ff3078 --- /dev/null +++ b/src/ui/members.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/members.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_MEMBERS_H_ | ||
26 | #define UI_MEMBERS_H_ | ||
27 | |||
28 | #include <stdbool.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <curses.h> | ||
31 | |||
32 | #include <gnunet/gnunet_chat_lib.h> | ||
33 | #include <gnunet/gnunet_util_lib.h> | ||
34 | |||
35 | struct MESSENGER_Application; | ||
36 | |||
37 | /** | ||
38 | * @struct UI_MEMBERS_List | ||
39 | */ | ||
40 | typedef struct UI_MEMBERS_List | ||
41 | { | ||
42 | struct GNUNET_CHAT_Contact *contact; | ||
43 | |||
44 | struct UI_MEMBERS_List *prev; | ||
45 | struct UI_MEMBERS_List *next; | ||
46 | } UI_MEMBERS_List; | ||
47 | |||
48 | /** | ||
49 | * @struct UI_MEMBERS_Handle | ||
50 | */ | ||
51 | typedef struct UI_MEMBERS_Handle | ||
52 | { | ||
53 | WINDOW *window; | ||
54 | |||
55 | UI_MEMBERS_List *head; | ||
56 | UI_MEMBERS_List *tail; | ||
57 | |||
58 | int line_prev; | ||
59 | int line_next; | ||
60 | |||
61 | int line_index; | ||
62 | int line_offset; | ||
63 | int line_selected; | ||
64 | |||
65 | struct GNUNET_CHAT_Contact *selected; | ||
66 | } UI_MEMBERS_Handle; | ||
67 | |||
68 | #define UI_MEMBERS_COLS_MIN 30 | ||
69 | |||
70 | /** | ||
71 | * Processes the current key event by the view | ||
72 | * to show a chats list of members. | ||
73 | * | ||
74 | * @param[in,out] members Chat members view | ||
75 | * @param[in,out] app Application handle | ||
76 | * @param[in] key Key | ||
77 | */ | ||
78 | void | ||
79 | members_event(UI_MEMBERS_Handle *members, | ||
80 | struct MESSENGER_Application *app, | ||
81 | int key); | ||
82 | |||
83 | /** | ||
84 | * Prints the content of the view to show | ||
85 | * a chats list of members to its selected | ||
86 | * window view on screen. | ||
87 | * | ||
88 | * @param[in,out] members Chat members view | ||
89 | */ | ||
90 | void | ||
91 | members_print(UI_MEMBERS_Handle *members); | ||
92 | |||
93 | /** | ||
94 | * Clears the list of members the view | ||
95 | * would print to the screen. | ||
96 | * | ||
97 | * @param[out] members Chat members view | ||
98 | */ | ||
99 | void | ||
100 | members_clear(UI_MEMBERS_Handle *members); | ||
101 | |||
102 | /** | ||
103 | * Adds a new chat contact to the list of | ||
104 | * members the view will print to the | ||
105 | * screen. | ||
106 | * | ||
107 | * @param[in,out] members Chat members view | ||
108 | * @param[in] contact Chat contact | ||
109 | * @return #TRUE if the member is new, otherwise #FALSE | ||
110 | */ | ||
111 | bool | ||
112 | members_add(UI_MEMBERS_Handle *members, | ||
113 | struct GNUNET_CHAT_Contact *contact); | ||
114 | |||
115 | /** | ||
116 | * Removes a chat contact from the list of | ||
117 | * members the view would print to the | ||
118 | * screen. | ||
119 | * | ||
120 | * @param[in,out] members Chat members view | ||
121 | * @param[in] contact Chat contact | ||
122 | */ | ||
123 | void | ||
124 | members_remove(UI_MEMBERS_Handle *members, | ||
125 | const struct GNUNET_CHAT_Contact *contact); | ||
126 | |||
127 | #endif /* UI_MEMBERS_H_ */ | ||
diff --git a/src/ui/meson.build b/src/ui/meson.build new file mode 100644 index 0000000..a57c670 --- /dev/null +++ b/src/ui/meson.build | |||
@@ -0,0 +1,33 @@ | |||
1 | # | ||
2 | # This file is part of GNUnet. | ||
3 | # Copyright (C) 2023 GNUnet e.V. | ||
4 | # | ||
5 | # GNUnet is free software: you can redistribute it and/or modify it | ||
6 | # under the terms of the GNU Affero General Public License as published | ||
7 | # by the Free Software Foundation, either version 3 of the License, | ||
8 | # or (at your option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # Affero General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU Affero General Public License | ||
16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | # | ||
18 | # SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | # | ||
20 | |||
21 | messenger_cli_ui_sources = files([ | ||
22 | 'account_create_dialog.c', 'account_create_dialog.h', | ||
23 | 'accounts.c', 'accounts.h', | ||
24 | 'chat_open_dialog.c', 'chat_open_dialog.h', | ||
25 | 'chat.h', | ||
26 | 'chats.c', 'chats.h', | ||
27 | 'list_input.h', | ||
28 | 'lobby_create_dialog.c', 'lobby_create_dialog.h', | ||
29 | 'lobby_enter_dialog.c', 'lobby_enter_dialog.h', | ||
30 | 'members.c', 'members.h', | ||
31 | 'messages.c', 'messages.h', | ||
32 | 'text_input.h', | ||
33 | ]) | ||
diff --git a/src/ui/messages.c b/src/ui/messages.c new file mode 100644 index 0000000..1dea885 --- /dev/null +++ b/src/ui/messages.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2024 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/messages.c | ||
23 | */ | ||
24 | |||
25 | #include "messages.h" | ||
26 | |||
27 | #include "list_input.h" | ||
28 | #include "text_input.h" | ||
29 | #include "../application.h" | ||
30 | #include "../util.h" | ||
31 | #include <gnunet/gnunet_chat_lib.h> | ||
32 | #include <gnunet/gnunet_common.h> | ||
33 | |||
34 | struct tm* | ||
35 | _messages_new_day(time_t* current_time, | ||
36 | const time_t* timestamp) | ||
37 | { | ||
38 | struct tm* ts = localtime(timestamp); | ||
39 | |||
40 | ts->tm_sec = 0; | ||
41 | ts->tm_min = 0; | ||
42 | ts->tm_hour = 0; | ||
43 | |||
44 | const time_t date_time = timelocal(ts); | ||
45 | |||
46 | if (date_time <= *current_time) { | ||
47 | return NULL; | ||
48 | } | ||
49 | |||
50 | *current_time = date_time; | ||
51 | return ts; | ||
52 | } | ||
53 | |||
54 | void | ||
55 | _messages_handle_message(UI_MESSAGES_Handle *messages) | ||
56 | { | ||
57 | switch (GNUNET_CHAT_message_get_kind(messages->selected)) | ||
58 | { | ||
59 | case GNUNET_CHAT_KIND_INVITATION: | ||
60 | { | ||
61 | struct GNUNET_CHAT_Invitation *invitation = ( | ||
62 | GNUNET_CHAT_message_get_invitation(messages->selected) | ||
63 | ); | ||
64 | |||
65 | if (invitation) | ||
66 | GNUNET_CHAT_invitation_accept(invitation); | ||
67 | break; | ||
68 | } | ||
69 | case GNUNET_CHAT_KIND_FILE: | ||
70 | { | ||
71 | struct GNUNET_CHAT_File *file = GNUNET_CHAT_message_get_file( | ||
72 | messages->selected | ||
73 | ); | ||
74 | |||
75 | if ((file) && (GNUNET_YES != GNUNET_CHAT_file_is_downloading(file))) | ||
76 | GNUNET_CHAT_file_start_download(file, NULL, NULL); | ||
77 | break; | ||
78 | default: | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void | ||
85 | messages_event(UI_MESSAGES_Handle *messages, | ||
86 | MESSENGER_Application *app, | ||
87 | int key) | ||
88 | { | ||
89 | list_input_reset(messages); | ||
90 | messages->line_time = 0; | ||
91 | |||
92 | UI_MESSAGES_List *element = messages->head; | ||
93 | while (element) | ||
94 | { | ||
95 | struct tm *ts = _messages_new_day( | ||
96 | &(messages->line_time), | ||
97 | &(element->timestamp) | ||
98 | ); | ||
99 | |||
100 | list_input_select(messages, ts? 2 : 1, element->message); | ||
101 | element = element->next; | ||
102 | } | ||
103 | |||
104 | list_input_select(messages, 1, NULL); | ||
105 | |||
106 | switch (key) | ||
107 | { | ||
108 | case 27: | ||
109 | case KEY_EXIT: | ||
110 | app->chat.context = NULL; | ||
111 | break; | ||
112 | case '\t': | ||
113 | app->chat.show_members = TRUE; | ||
114 | break; | ||
115 | case '\n': | ||
116 | case KEY_ENTER: | ||
117 | if (messages->selected) | ||
118 | _messages_handle_message(messages); | ||
119 | else if (messages->text_len > 0) | ||
120 | { | ||
121 | if (0 != strncmp(messages->text, | ||
122 | UI_MESSAGES_FILE_PREFIX, | ||
123 | UI_MESSAGES_FILE_PREFIX_LEN)) | ||
124 | goto write_text; | ||
125 | |||
126 | const char* filename = messages->text + 5; | ||
127 | |||
128 | if (0 != access(filename, R_OK | F_OK)) | ||
129 | break; | ||
130 | |||
131 | GNUNET_CHAT_context_send_file( | ||
132 | app->chat.context, | ||
133 | filename, | ||
134 | NULL, | ||
135 | NULL | ||
136 | ); | ||
137 | |||
138 | goto drop_text; | ||
139 | |||
140 | write_text: | ||
141 | GNUNET_CHAT_context_send_text( | ||
142 | app->chat.context, | ||
143 | messages->text | ||
144 | ); | ||
145 | |||
146 | drop_text: | ||
147 | messages->text_len = 0; | ||
148 | } | ||
149 | break; | ||
150 | case KEY_BACKSPACE: | ||
151 | if (messages->selected) | ||
152 | GNUNET_CHAT_message_delete( | ||
153 | messages->selected, | ||
154 | GNUNET_TIME_relative_get_zero_() | ||
155 | ); | ||
156 | break; | ||
157 | default: | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | if (!(messages->selected)) | ||
162 | text_input_event(messages->text, key); | ||
163 | |||
164 | list_input_event(messages, key); | ||
165 | } | ||
166 | |||
167 | void | ||
168 | _messages_iterate_print(UI_MESSAGES_Handle *messages, | ||
169 | const time_t* timestamp, | ||
170 | const struct GNUNET_CHAT_Message *message) | ||
171 | { | ||
172 | static const char *you = "you"; | ||
173 | |||
174 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); | ||
175 | |||
176 | struct GNUNET_CHAT_Contact *sender = GNUNET_CHAT_message_get_sender(message); | ||
177 | struct GNUNET_CHAT_Contact *recipient = GNUNET_CHAT_message_get_recipient(message); | ||
178 | |||
179 | enum GNUNET_GenericReturnValue sent = GNUNET_CHAT_message_is_sent(message); | ||
180 | const char *msg_s = GNUNET_YES == sent? "" : "s"; | ||
181 | |||
182 | enum GNUNET_GenericReturnValue recv = recipient? | ||
183 | GNUNET_CHAT_contact_is_owned(recipient) : GNUNET_NO; | ||
184 | |||
185 | const char *name = GNUNET_YES == sent? you : ( | ||
186 | sender? GNUNET_CHAT_contact_get_name(sender) : NULL | ||
187 | ); | ||
188 | |||
189 | const char *rcp = GNUNET_YES == recv? you : ( | ||
190 | recipient? GNUNET_CHAT_contact_get_name(recipient) : you | ||
191 | ); | ||
192 | |||
193 | const char *text = GNUNET_CHAT_message_get_text(message); | ||
194 | |||
195 | const struct GNUNET_CHAT_File *file = GNUNET_CHAT_message_get_file(message); | ||
196 | |||
197 | struct tm* ts = localtime(timestamp); | ||
198 | char time_buf [255]; | ||
199 | |||
200 | strftime(time_buf, sizeof(time_buf), "%H:%M", ts); | ||
201 | |||
202 | ts = _messages_new_day(&(messages->line_time), timestamp); | ||
203 | |||
204 | list_input_print(messages, ts? 2 : 1); | ||
205 | wmove(messages->window, y, 0); | ||
206 | |||
207 | if (ts) { | ||
208 | char date_buf [255]; | ||
209 | |||
210 | strftime(date_buf, sizeof(date_buf), "%x", ts); | ||
211 | |||
212 | const int width = getmaxx(messages->window); | ||
213 | |||
214 | whline(messages->window, '-', width); | ||
215 | wmove(messages->window, y, 8); | ||
216 | |||
217 | wprintw(messages->window, " %s ", date_buf); | ||
218 | wmove(messages->window, y+1, 0); | ||
219 | } | ||
220 | |||
221 | const int attrs_select = A_BOLD; | ||
222 | |||
223 | if (selected) wattron(messages->window, attrs_select); | ||
224 | |||
225 | wprintw(messages->window, " %s | ", time_buf); | ||
226 | |||
227 | switch (kind) { | ||
228 | case GNUNET_CHAT_KIND_JOIN: | ||
229 | wprintw( | ||
230 | messages->window, | ||
231 | "%s join%s the room.", | ||
232 | name, | ||
233 | msg_s | ||
234 | ); | ||
235 | break; | ||
236 | case GNUNET_CHAT_KIND_LEAVE: | ||
237 | wprintw( | ||
238 | messages->window, | ||
239 | "%s leave%s the room.", | ||
240 | name, | ||
241 | msg_s | ||
242 | ); | ||
243 | break; | ||
244 | case GNUNET_CHAT_KIND_INVITATION: | ||
245 | wprintw( | ||
246 | messages->window, | ||
247 | "%s invite%s %s to a room.", | ||
248 | name, | ||
249 | msg_s, | ||
250 | rcp | ||
251 | ); | ||
252 | break; | ||
253 | case GNUNET_CHAT_KIND_TEXT: | ||
254 | wprintw( | ||
255 | messages->window, | ||
256 | "%s: %s", | ||
257 | name, | ||
258 | text | ||
259 | ); | ||
260 | break; | ||
261 | case GNUNET_CHAT_KIND_FILE: { | ||
262 | const char *filename = GNUNET_CHAT_file_get_name(file); | ||
263 | |||
264 | const uint64_t localsize = GNUNET_CHAT_file_get_local_size(file); | ||
265 | const uint64_t filesize = GNUNET_CHAT_file_get_size(file); | ||
266 | |||
267 | wprintw( | ||
268 | messages->window, | ||
269 | "%s share%s the file '%s' (%lu / %lu).", | ||
270 | name, | ||
271 | msg_s, | ||
272 | filename, | ||
273 | localsize, | ||
274 | filesize | ||
275 | ); | ||
276 | break; | ||
277 | } | ||
278 | default: | ||
279 | wprintw( | ||
280 | messages->window, | ||
281 | "[%d] %s: %s", | ||
282 | (int) kind, | ||
283 | name, | ||
284 | text | ||
285 | ); | ||
286 | break; | ||
287 | } | ||
288 | |||
289 | if (selected) wattroff(messages->window, attrs_select); | ||
290 | } | ||
291 | |||
292 | void | ||
293 | messages_print(UI_MESSAGES_Handle *messages) | ||
294 | { | ||
295 | if (!(messages->window)) | ||
296 | return; | ||
297 | |||
298 | list_input_reset(messages); | ||
299 | messages->line_time = 0; | ||
300 | |||
301 | werase(messages->window); | ||
302 | |||
303 | UI_MESSAGES_List *element = messages->head; | ||
304 | while (element) | ||
305 | { | ||
306 | _messages_iterate_print(messages, &(element->timestamp), element->message); | ||
307 | element = element->next; | ||
308 | } | ||
309 | |||
310 | const int count = messages->line_index; | ||
311 | const bool selected = (count == messages->line_selected); | ||
312 | |||
313 | const int width = getmaxx(messages->window); | ||
314 | const int height = getmaxy(messages->window); | ||
315 | const int line_height = height - 2; | ||
316 | |||
317 | wmove(messages->window, line_height, 0); | ||
318 | whline(messages->window, '-', width); | ||
319 | |||
320 | const bool is_file_text = (0 == strncmp( | ||
321 | messages->text, | ||
322 | UI_MESSAGES_FILE_PREFIX, | ||
323 | UI_MESSAGES_FILE_PREFIX_LEN | ||
324 | )); | ||
325 | |||
326 | const int attrs_select = A_BOLD | (is_file_text? A_ITALIC : A_NORMAL); | ||
327 | |||
328 | if (selected) wattron(messages->window, attrs_select); | ||
329 | |||
330 | wmove(messages->window, height - 1, 0); | ||
331 | wprintw(messages->window, "%s", messages->text); | ||
332 | |||
333 | if (selected) wattroff(messages->window, attrs_select); | ||
334 | |||
335 | wmove(messages->window, height - 1, messages->text_pos); | ||
336 | |||
337 | if (selected) | ||
338 | { | ||
339 | wcursyncup(messages->window); | ||
340 | curs_set(1); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | void | ||
345 | messages_clear(UI_MESSAGES_Handle *messages) | ||
346 | { | ||
347 | UI_MESSAGES_List *element; | ||
348 | while (messages->head) | ||
349 | { | ||
350 | element = messages->head; | ||
351 | |||
352 | GNUNET_CONTAINER_DLL_remove( | ||
353 | messages->head, | ||
354 | messages->tail, | ||
355 | element | ||
356 | ); | ||
357 | |||
358 | GNUNET_free(element); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | static int | ||
363 | _message_compare_timestamps(UNUSED void *cls, | ||
364 | UI_MESSAGES_List *list0, | ||
365 | UI_MESSAGES_List *list1) | ||
366 | { | ||
367 | if ((!list0) || (!list1)) | ||
368 | return 0; | ||
369 | |||
370 | if (list0->timestamp > list1->timestamp) | ||
371 | return -1; | ||
372 | else if (list0->timestamp < list1->timestamp) | ||
373 | return +1; | ||
374 | else | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | void | ||
379 | messages_add(UI_MESSAGES_Handle *messages, | ||
380 | const struct GNUNET_CHAT_Message *message) | ||
381 | { | ||
382 | enum GNUNET_CHAT_MessageKind kind = GNUNET_CHAT_message_get_kind(message); | ||
383 | |||
384 | switch (kind) { | ||
385 | case GNUNET_CHAT_KIND_UPDATE: | ||
386 | case GNUNET_CHAT_KIND_CONTACT: | ||
387 | case GNUNET_CHAT_KIND_DELETION: | ||
388 | return; | ||
389 | default: | ||
390 | break; | ||
391 | } | ||
392 | |||
393 | list_input_reset(messages); | ||
394 | messages->line_time = 0; | ||
395 | |||
396 | UI_MESSAGES_List *element = messages->head; | ||
397 | while (element) | ||
398 | { | ||
399 | struct tm *ts = _messages_new_day( | ||
400 | &(messages->line_time), | ||
401 | &(element->timestamp) | ||
402 | ); | ||
403 | |||
404 | list_input_select(messages, ts? 2 : 1, element->message); | ||
405 | element = element->next; | ||
406 | } | ||
407 | |||
408 | list_input_select(messages, 1, NULL); | ||
409 | |||
410 | const struct GNUNET_TIME_Absolute abs_time = ( | ||
411 | GNUNET_CHAT_message_get_timestamp(message) | ||
412 | ); | ||
413 | |||
414 | const struct GNUNET_TIME_Timestamp timestamp = ( | ||
415 | GNUNET_TIME_absolute_to_timestamp(abs_time) | ||
416 | ); | ||
417 | |||
418 | element = GNUNET_new(UI_MESSAGES_List); | ||
419 | element->timestamp = GNUNET_TIME_timestamp_to_s(timestamp); | ||
420 | element->message = message; | ||
421 | |||
422 | GNUNET_CONTAINER_DLL_insert_sorted( | ||
423 | UI_MESSAGES_List, | ||
424 | _message_compare_timestamps, | ||
425 | NULL, | ||
426 | messages->head, | ||
427 | messages->tail, | ||
428 | element | ||
429 | ); | ||
430 | |||
431 | list_input_select(messages, 1, NULL); | ||
432 | |||
433 | if (!(messages->selected)) | ||
434 | list_input_event(messages, KEY_DOWN); | ||
435 | } | ||
436 | |||
437 | void | ||
438 | messages_remove(UI_MESSAGES_Handle *messages, | ||
439 | const struct GNUNET_CHAT_Message *message) | ||
440 | { | ||
441 | UI_MESSAGES_List *element = messages->head; | ||
442 | while (element) | ||
443 | { | ||
444 | if (element->message == message) | ||
445 | break; | ||
446 | |||
447 | element = element->next; | ||
448 | } | ||
449 | |||
450 | if (element) | ||
451 | GNUNET_CONTAINER_DLL_remove( | ||
452 | messages->head, | ||
453 | messages->tail, | ||
454 | element | ||
455 | ); | ||
456 | } | ||
diff --git a/src/ui/messages.h b/src/ui/messages.h new file mode 100644 index 0000000..bcb2336 --- /dev/null +++ b/src/ui/messages.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2023 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/messages.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_MESSAGES_H_ | ||
26 | #define UI_MESSAGES_H_ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <time.h> | ||
30 | #include <unistd.h> | ||
31 | #include <curses.h> | ||
32 | |||
33 | #include <gnunet/gnunet_chat_lib.h> | ||
34 | #include <gnunet/gnunet_util_lib.h> | ||
35 | |||
36 | struct MESSENGER_Application; | ||
37 | |||
38 | /** | ||
39 | * @struct UI_MESSAGES_List | ||
40 | */ | ||
41 | typedef struct UI_MESSAGES_List | ||
42 | { | ||
43 | time_t timestamp; | ||
44 | |||
45 | const struct GNUNET_CHAT_Message *message; | ||
46 | |||
47 | struct UI_MESSAGES_List *prev; | ||
48 | struct UI_MESSAGES_List *next; | ||
49 | } UI_MESSAGES_List; | ||
50 | |||
51 | #define TEXT_LEN_MAX 1024 | ||
52 | |||
53 | /** | ||
54 | * @struct UI_MESSAGES_Handle | ||
55 | */ | ||
56 | typedef struct UI_MESSAGES_Handle | ||
57 | { | ||
58 | WINDOW *window; | ||
59 | |||
60 | UI_MESSAGES_List *head; | ||
61 | UI_MESSAGES_List *tail; | ||
62 | |||
63 | int line_prev; | ||
64 | int line_next; | ||
65 | |||
66 | int line_index; | ||
67 | int line_offset; | ||
68 | int line_selected; | ||
69 | time_t line_time; | ||
70 | |||
71 | const struct GNUNET_CHAT_Message *selected; | ||
72 | |||
73 | char text [1024]; | ||
74 | int text_len; | ||
75 | int text_pos; | ||
76 | } UI_MESSAGES_Handle; | ||
77 | |||
78 | #define UI_MESSAGES_COLS_MIN 50 | ||
79 | |||
80 | #define UI_MESSAGES_FILE_PREFIX "file:" | ||
81 | #define UI_MESSAGES_FILE_PREFIX_LEN 5 | ||
82 | |||
83 | /** | ||
84 | * Processes the current key event by the view | ||
85 | * to show a chats list of messages. | ||
86 | * | ||
87 | * @param[in,out] messages Chat messages view | ||
88 | * @param[in,out] app Application handle | ||
89 | * @param[in] key Key | ||
90 | */ | ||
91 | void | ||
92 | messages_event(UI_MESSAGES_Handle *messages, | ||
93 | struct MESSENGER_Application *app, | ||
94 | int key); | ||
95 | |||
96 | /** | ||
97 | * Prints the content of the view to show | ||
98 | * a chats list of messages to its selected | ||
99 | * window view on screen. | ||
100 | * | ||
101 | * @param[in,out] messages Chat messages view | ||
102 | */ | ||
103 | void | ||
104 | messages_print(UI_MESSAGES_Handle *messages); | ||
105 | |||
106 | /** | ||
107 | * Clears the list of messages the view | ||
108 | * would print to the screen. | ||
109 | * | ||
110 | * @param[out] messages Chat messages view | ||
111 | */ | ||
112 | void | ||
113 | messages_clear(UI_MESSAGES_Handle *messages); | ||
114 | |||
115 | /** | ||
116 | * Adds a new chat message to the list of | ||
117 | * messages the view will print to the | ||
118 | * screen. | ||
119 | * | ||
120 | * @param[in,out] messages Chat messages view | ||
121 | * @param[in] message Chat message | ||
122 | */ | ||
123 | void | ||
124 | messages_add(UI_MESSAGES_Handle *messages, | ||
125 | const struct GNUNET_CHAT_Message *message); | ||
126 | |||
127 | /** | ||
128 | * Removes a chat message from the list of | ||
129 | * messages the view would print to the | ||
130 | * screen. | ||
131 | * | ||
132 | * @param[in,out] messages Chat messages view | ||
133 | * @param[in] message Chat message | ||
134 | */ | ||
135 | void | ||
136 | messages_remove(UI_MESSAGES_Handle *messages, | ||
137 | const struct GNUNET_CHAT_Message *message); | ||
138 | |||
139 | #endif /* UI_MESSAGES_H_ */ | ||
diff --git a/src/ui/text_input.h b/src/ui/text_input.h new file mode 100644 index 0000000..ec04ed5 --- /dev/null +++ b/src/ui/text_input.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file ui/text_input.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UI_TEXT_INPUT_H_ | ||
26 | #define UI_TEXT_INPUT_H_ | ||
27 | |||
28 | #include <ctype.h> | ||
29 | |||
30 | /** | ||
31 | * Handles the key event to move the cursor | ||
32 | * and adjust the content of text controls. | ||
33 | */ | ||
34 | #define text_input_event(text, key) { \ | ||
35 | switch (key) \ | ||
36 | { \ | ||
37 | case KEY_LEFT: \ | ||
38 | { \ | ||
39 | text##_pos--; \ | ||
40 | break; \ | ||
41 | } \ | ||
42 | case KEY_RIGHT: \ | ||
43 | { \ | ||
44 | text##_pos++; \ | ||
45 | break; \ | ||
46 | } \ | ||
47 | case KEY_BACKSPACE: \ | ||
48 | { \ | ||
49 | if ((text##_pos < text##_len) && (text##_pos > 0)) \ | ||
50 | for (int i = text##_pos; i < text##_len; i++) \ | ||
51 | text[i - 1] = text[i]; \ | ||
52 | \ | ||
53 | if ((text##_pos > 0) && (text##_len > 0)) \ | ||
54 | { \ | ||
55 | text##_pos--; \ | ||
56 | text##_len--; \ | ||
57 | } \ | ||
58 | \ | ||
59 | break; \ | ||
60 | } \ | ||
61 | default: \ | ||
62 | { \ | ||
63 | if (!isprint(key)) \ | ||
64 | break; \ | ||
65 | \ | ||
66 | for (int i = text##_len - 1; i >= text##_pos; i--) \ | ||
67 | text[i + 1] = text[i]; \ | ||
68 | \ | ||
69 | text[text##_pos++] = (char) key; \ | ||
70 | text##_len++; \ | ||
71 | break; \ | ||
72 | } \ | ||
73 | } \ | ||
74 | \ | ||
75 | int max_len = (int) sizeof(text) - 1; \ | ||
76 | \ | ||
77 | if (text##_len > max_len) \ | ||
78 | text##_len = max_len; \ | ||
79 | \ | ||
80 | text[text##_len] = '\0'; \ | ||
81 | \ | ||
82 | if (text##_pos < 0) \ | ||
83 | text##_pos = 0; \ | ||
84 | \ | ||
85 | if (text##_pos > text##_len) \ | ||
86 | text##_pos = text##_len; \ | ||
87 | } | ||
88 | |||
89 | #endif /* UI_TEXT_INPUT_H_ */ | ||
diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..89155c8 --- /dev/null +++ b/src/util.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2024 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file util.c | ||
23 | */ | ||
24 | |||
25 | #include "util.h" | ||
26 | #include <string.h> | ||
27 | |||
28 | void | ||
29 | util_print_logo(WINDOW *window) | ||
30 | { | ||
31 | int x = getcurx(window); | ||
32 | int y = getcury(window); | ||
33 | |||
34 | wmove(window, y++, x); wprintw(window, " "); | ||
35 | wmove(window, y++, x); wprintw(window, " o/ \\o "); | ||
36 | wmove(window, y++, x); wprintw(window, " ooo oo "); | ||
37 | wmove(window, y++, x); wprintw(window, " \\oooo\\ /oooo/ "); | ||
38 | wmove(window, y++, x); wprintw(window, " oo ooo "); | ||
39 | wmove(window, y++, x); wprintw(window, " oo ooo "); | ||
40 | wmove(window, y++, x); wprintw(window, " ooooooo "); | ||
41 | wmove(window, y++, x); wprintw(window, " \\oooo/ "); | ||
42 | wmove(window, y++, x); wprintw(window, " oooo "); | ||
43 | wmove(window, y++, x); wprintw(window, " "); | ||
44 | } | ||
45 | |||
46 | void | ||
47 | util_print_info(WINDOW *window, | ||
48 | const char *info) | ||
49 | { | ||
50 | const int x = getmaxx(window) - strlen(info) - 1; | ||
51 | const int y = getcury(window); | ||
52 | |||
53 | if ((x + (y - 2) / 2 < UTIL_LOGO_COLS - 7) || | ||
54 | ((y < 4) && (x < UTIL_LOGO_COLS))) | ||
55 | return; | ||
56 | |||
57 | wmove(window, y, x); | ||
58 | wprintw(window, "%s", info); | ||
59 | } | ||
diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..d1126a9 --- /dev/null +++ b/src/util.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022--2024 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /* | ||
21 | * @author Tobias Frisch | ||
22 | * @file util.h | ||
23 | */ | ||
24 | |||
25 | #ifndef UTIL_H_ | ||
26 | #define UTIL_H_ | ||
27 | |||
28 | #include <stdbool.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <curses.h> | ||
31 | |||
32 | #define UNUSED __attribute__((unused)) | ||
33 | |||
34 | #define UTIL_LOGO_ROWS 10 | ||
35 | #define UTIL_LOGO_COLS 28 | ||
36 | |||
37 | /** | ||
38 | * Prints the main logo of the application | ||
39 | * onto a specified view. | ||
40 | * | ||
41 | * @param[in,out] window Window view | ||
42 | */ | ||
43 | void | ||
44 | util_print_logo(WINDOW *window); | ||
45 | |||
46 | /** | ||
47 | * Print information on the right side of | ||
48 | * the application besides the main logo. | ||
49 | * | ||
50 | * @param[in,out] window Window view | ||
51 | * @param[in] info Information | ||
52 | */ | ||
53 | void | ||
54 | util_print_info(WINDOW *window, | ||
55 | const char *info); | ||
56 | |||
57 | #endif /* UTIL_H_ */ | ||