accounts.c (7314B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2022--2026 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 <gnunet/gnunet_chat_lib.h> 28 29 #include "account_entry.h" 30 31 #include "../account.h" 32 #include "../application.h" 33 #include "../secret.h" 34 #include "../ui.h" 35 36 static void 37 handle_close_button_click(UNUSED GtkButton *button, 38 gpointer user_data) 39 { 40 g_assert(user_data); 41 42 GtkDialog *dialog = GTK_DIALOG(user_data); 43 gtk_window_close(GTK_WINDOW(dialog)); 44 } 45 46 static gboolean 47 _open_new_account_dialog(gpointer user_data) 48 { 49 g_assert(user_data); 50 51 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 52 53 ui_new_account_dialog_init(app, &(app->ui.new_account)); 54 55 gtk_widget_show(GTK_WIDGET(app->ui.new_account.dialog)); 56 return FALSE; 57 } 58 59 static void 60 _account_secret_lookup(MESSENGER_Application *app, 61 const char *secret, 62 uint32_t secret_len, 63 gboolean success, 64 gboolean error, 65 gpointer user_data) 66 { 67 g_assert((app) && (user_data)); 68 69 struct GNUNET_CHAT_Account *account = user_data; 70 71 if (error) 72 { 73 fprintf(stderr, "ERROR: Looking up secret failed\n"); 74 } 75 else if ((success) && (secret) && (secret_len > 0)) 76 { 77 application_chat_lock(app); 78 GNUNET_CHAT_connect(app->chat.messenger.handle, account, secret, secret_len); 79 application_chat_unlock(app); 80 } 81 else 82 { 83 const char *name; 84 85 application_chat_lock(app); 86 name = GNUNET_CHAT_account_get_name(account); 87 application_chat_unlock(app); 88 89 secret_operation_generate(app, name, &_account_secret_lookup, account); 90 } 91 } 92 93 static void 94 handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, 95 GtkListBoxRow* row, 96 gpointer user_data) 97 { 98 g_assert((row) && (user_data)); 99 100 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 101 102 // Drop activations of rows which do not contain accounts 103 if (!gtk_list_box_row_get_selectable(row)) 104 { 105 app->ui.accounts.show_queued = util_idle_add( 106 G_SOURCE_FUNC(_open_new_account_dialog), app 107 ); 108 109 goto close_dialog; 110 } 111 112 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( 113 g_object_get_qdata(G_OBJECT(row), app->quarks.data) 114 ); 115 116 if (!account) 117 goto close_dialog; 118 119 app->ui.state = MESSENGER_STATE_MAIN_WINDOW; 120 121 gtk_list_box_unselect_all(app->ui.messenger.accounts_listbox); 122 gtk_widget_set_sensitive(GTK_WIDGET(app->ui.accounts.dialog), FALSE); 123 124 const char *name; 125 126 application_chat_lock(app); 127 name = GNUNET_CHAT_account_get_name(account); 128 application_chat_unlock(app); 129 130 secret_operation_lookup(app, name, &_account_secret_lookup, account); 131 132 close_dialog: 133 gtk_window_close(GTK_WINDOW(app->ui.accounts.dialog)); 134 } 135 136 static void 137 handle_dialog_destroy(UNUSED GtkWidget *window, 138 gpointer user_data) 139 { 140 g_assert(user_data); 141 142 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 143 144 ui_accounts_dialog_cleanup(&(app->ui.accounts), app); 145 146 if ((app->ui.accounts.show_queued) || 147 (MESSENGER_STATE_MAIN_WINDOW == app->ui.state)) 148 return; 149 150 gtk_widget_destroy(GTK_WIDGET(app->ui.messenger.main_window)); 151 } 152 153 static int 154 _iterate_accounts(void *cls, 155 UNUSED struct GNUNET_CHAT_Handle *handle, 156 struct GNUNET_CHAT_Account *account) 157 { 158 g_assert((cls) && (account)); 159 160 MESSENGER_Application *app = (MESSENGER_Application*) cls; 161 162 UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app); 163 164 ui_account_entry_set_account(entry, account); 165 166 gtk_list_box_prepend(app->ui.accounts.accounts_listbox, entry->entry_box); 167 168 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 169 gtk_widget_get_parent(entry->entry_box) 170 ); 171 172 g_object_set_qdata(G_OBJECT(row), app->quarks.data, account); 173 174 g_object_set_qdata( 175 G_OBJECT(row), 176 app->quarks.ui, 177 entry 178 ); 179 180 return GNUNET_YES; 181 } 182 183 void 184 ui_accounts_dialog_init(MESSENGER_Application *app, 185 UI_ACCOUNTS_Handle *handle) 186 { 187 g_assert((app) && (handle)); 188 189 handle->show_queued = 0; 190 191 handle->builder = ui_builder_from_resource( 192 application_get_resource_path(app, "ui/accounts.ui") 193 ); 194 195 handle->dialog = GTK_DIALOG( 196 gtk_builder_get_object(handle->builder, "accounts_dialog") 197 ); 198 199 gtk_window_set_transient_for( 200 GTK_WINDOW(handle->dialog), 201 GTK_WINDOW(app->ui.messenger.main_window) 202 ); 203 204 handle->accounts_listbox = GTK_LIST_BOX( 205 gtk_builder_get_object(handle->builder, "accounts_listbox") 206 ); 207 208 g_signal_connect( 209 handle->accounts_listbox, 210 "row-activated", 211 G_CALLBACK(handle_accounts_listbox_row_activated), 212 app 213 ); 214 215 handle->close_button = GTK_BUTTON( 216 gtk_builder_get_object(handle->builder, "close_button") 217 ); 218 219 g_signal_connect( 220 handle->close_button, 221 "clicked", 222 G_CALLBACK(handle_close_button_click), 223 handle->dialog 224 ); 225 226 g_signal_connect( 227 handle->dialog, 228 "destroy", 229 G_CALLBACK(handle_dialog_destroy), 230 app 231 ); 232 } 233 234 static void 235 _ui_accounts_cleanup_listbox(UI_ACCOUNTS_Handle *handle, 236 MESSENGER_Application *app) 237 { 238 g_assert(handle); 239 240 GList *list = gtk_container_get_children( 241 GTK_CONTAINER(handle->accounts_listbox) 242 ); 243 244 GList *item = list; 245 while (item) 246 { 247 GtkListBoxRow *row = GTK_LIST_BOX_ROW(item->data); 248 249 if ((!row) || (!gtk_list_box_row_get_selectable(row))) 250 goto skip_row; 251 252 UI_ACCOUNT_ENTRY_Handle *entry = g_object_get_qdata( 253 G_OBJECT(row), 254 app->quarks.ui 255 ); 256 257 gtk_container_remove( 258 GTK_CONTAINER(handle->accounts_listbox), 259 GTK_WIDGET(row) 260 ); 261 262 ui_account_entry_delete(entry); 263 264 skip_row: 265 item = item->next; 266 } 267 268 if (list) 269 g_list_free(list); 270 } 271 272 void 273 ui_accounts_dialog_refresh(MESSENGER_Application *app, 274 UI_ACCOUNTS_Handle *handle) 275 { 276 g_assert((app) && (handle)); 277 278 if (!(handle->accounts_listbox)) 279 return; 280 281 _ui_accounts_cleanup_listbox(handle, app); 282 283 application_chat_lock(app); 284 285 GNUNET_CHAT_iterate_accounts( 286 app->chat.messenger.handle, 287 _iterate_accounts, 288 app 289 ); 290 291 application_chat_unlock(app); 292 } 293 294 void 295 ui_accounts_dialog_cleanup(UI_ACCOUNTS_Handle *handle, 296 MESSENGER_Application *app) 297 { 298 g_assert((handle) && (app)); 299 300 _ui_accounts_cleanup_listbox(handle, app); 301 302 g_object_unref(handle->builder); 303 304 guint show = handle->show_queued; 305 memset(handle, 0, sizeof(*handle)); 306 handle->show_queued = show; 307 }