messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

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 }