anastasis-gtk

Demonstrator GUI for Anastasis
Log | Files | Refs | README | LICENSE

anastasis-gtk_handle-auth-edit-provider-clicked.c (16708B)


      1 /*
      2      This file is part of anastasis-gtk.
      3      Copyright (C) 2021 Anastasis SARL
      4 
      5      Anastasis is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      Anastasis 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      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with Anastasis; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19 */
     20 
     21 /**
     22  * @file src/anastasis/anastasis-gtk_backup.c
     23  * @brief Main function of anastasis-gtk
     24  * @author Christian Grothoff
     25  * @author Dennis Neufeld
     26  */
     27 #include <gnunet/gnunet_util_lib.h>
     28 #include "anastasis_gtk_util.h"
     29 #include "anastasis-gtk_action.h"
     30 #include "anastasis-gtk_helper.h"
     31 #include "anastasis-gtk_handle-main-window-forward-clicked.h"
     32 #include <sys/types.h>
     33 #include <sys/wait.h>
     34 #include <jansson.h>
     35 #include <microhttpd.h>
     36 
     37 
     38 /**
     39  * Context for menu callbacks.
     40  */
     41 struct MenuContext
     42 {
     43   /**
     44    * Base URL of the selected provider.
     45    */
     46   char *url;
     47 
     48 };
     49 
     50 
     51 /**
     52  * An item was selected from the context menu; destroy the menu shell.
     53  *
     54  * @param menushell menu to destroy
     55  * @param user_data the 'struct MenuContext' of the menu
     56  */
     57 static void
     58 context_popup_selection_done (GtkMenuShell *menushell,
     59                               gpointer user_data)
     60 {
     61   struct MenuContext *ctx = user_data;
     62 
     63   gtk_widget_destroy (GTK_WIDGET (menushell));
     64   GNUNET_free (ctx->url);
     65   GNUNET_free (ctx);
     66 }
     67 
     68 
     69 /**
     70  * Open @a url in a browser.
     71  *
     72  * @param url the URL to open
     73  */
     74 static void
     75 xdg_open (const char *url)
     76 {
     77   pid_t chld;
     78   int status;
     79 
     80   chld = fork ();
     81   if (-1 == chld)
     82   {
     83     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
     84                          "fork");
     85     return;
     86   }
     87   if (0 == chld)
     88   {
     89     pid_t c2;
     90 
     91     c2 = fork ();
     92     if (-1 == c2)
     93       _exit (EXIT_FAILURE);
     94     if (0 != c2)
     95       _exit (EXIT_SUCCESS);
     96     execlp ("xdg-open",
     97             "xdg-open",
     98             url,
     99             NULL);
    100     execlp ("open",
    101             "open",
    102             url,
    103             NULL);
    104     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    105                               "exec",
    106                               "open");
    107     _exit (EXIT_FAILURE);
    108   }
    109   waitpid (chld, &status, 0);
    110 }
    111 
    112 
    113 /**
    114  * The user selected the 'view pp' menu.
    115  *
    116  * @param menuitem the selected menu
    117  * @param user_data a `struct MenuContext`
    118  */
    119 static void
    120 view_terms_of_service (GtkMenuItem *menuitem,
    121                        gpointer user_data)
    122 {
    123   struct MenuContext *ctx = user_data;
    124   char *tos;
    125 
    126   GNUNET_asprintf (&tos,
    127                    "%sterms",
    128                    ctx->url);
    129   xdg_open (tos);
    130   GNUNET_free (tos);
    131 }
    132 
    133 
    134 /**
    135  * The user selected the 'view tos' menu.
    136  *
    137  * @param menuitem the selected menu
    138  * @param user_data a `struct MenuContext`
    139  */
    140 static void
    141 view_privacy_policy (GtkMenuItem *menuitem,
    142                      gpointer user_data)
    143 {
    144   struct MenuContext *ctx = user_data;
    145   char *pp;
    146 
    147   GNUNET_asprintf (&pp,
    148                    "%sprivacy",
    149                    ctx->url);
    150   xdg_open (pp);
    151   GNUNET_free (pp);
    152 }
    153 
    154 
    155 void
    156 provider_toggle_callback (GtkCellRendererToggle *cell,
    157                           gchar *path_str,
    158                           gpointer user_data)
    159 {
    160   GtkBuilder *builder = GTK_BUILDER (user_data);
    161   GtkTreeIter iter;
    162   GtkTreePath *path;
    163   gboolean enabled;
    164   GtkTreeModel *tm;
    165 
    166   tm = GTK_TREE_MODEL (gtk_builder_get_object (builder,
    167                                                "provider_liststore"));
    168   if (NULL == tm)
    169   {
    170     GNUNET_break (0);
    171     return;
    172   }
    173   path = gtk_tree_path_new_from_string (path_str);
    174   if (! gtk_tree_model_get_iter (tm,
    175                                  &iter,
    176                                  path))
    177   {
    178     GNUNET_break (0);
    179     return;
    180   }
    181   gtk_tree_model_get (tm,
    182                       &iter,
    183                       AG_PMC_PROVIDER_ENABLED, &enabled,
    184                       -1);
    185   enabled = ! enabled;
    186   gtk_list_store_set (GTK_LIST_STORE (tm),
    187                       &iter,
    188                       AG_PMC_PROVIDER_ENABLED, enabled,
    189                       -1);
    190   gtk_tree_path_free (path);
    191 }
    192 
    193 
    194 /**
    195  * User clicked on the tree view. If it was a right-click, show
    196  * context menu to allow user to view PP or TOS.
    197  *
    198  * @param widget the tree view
    199  * @param event the event
    200  * @param user_data the builder
    201  */
    202 gboolean
    203 provider_tree_view_button_press_event_cb (GtkWidget *widget,
    204                                           GdkEvent *event,
    205                                           gpointer user_data)
    206 {
    207   GtkBuilder *builder = GTK_BUILDER (user_data);
    208   GdkEventButton *event_button = (GdkEventButton *) event;
    209   GtkTreeView *tv;
    210   GtkTreeModel *tm;
    211   GtkTreePath *path;
    212   GtkTreeIter iter;
    213   struct MenuContext *ctx;
    214   GtkMenu *menu;
    215 
    216   if ((GDK_BUTTON_PRESS != event->type) ||
    217       (3 != event_button->button))
    218     return FALSE; /* not a right-click */
    219   tm = GTK_TREE_MODEL (gtk_builder_get_object (builder,
    220                                                "provider_liststore"));
    221   if (NULL == tm)
    222   {
    223     GNUNET_break (0);
    224     return FALSE;
    225   }
    226   tv = GTK_TREE_VIEW (gtk_builder_get_object (builder,
    227                                               "provider_tree_view"));
    228   if (! gtk_tree_view_get_path_at_pos (tv,
    229                                        event_button->x,
    230                                        event_button->y,
    231                                        &path,
    232                                        NULL,
    233                                        NULL,
    234                                        NULL))
    235   {
    236     /* nothing selected */
    237     return FALSE;
    238   }
    239   if (! gtk_tree_model_get_iter (tm,
    240                                  &iter,
    241                                  path))
    242   {
    243     /* not sure how we got a path but no iter... */
    244     GNUNET_break (0);
    245     return FALSE;
    246   }
    247   gtk_tree_path_free (path);
    248   ctx = GNUNET_new (struct MenuContext);
    249   gtk_tree_model_get (tm,
    250                       &iter,
    251                       AG_PMC_PROVIDER_URL, &ctx->url,
    252                       -1);
    253   menu = GTK_MENU (gtk_menu_new ());
    254   {
    255     GtkWidget *child;
    256 
    257     child = gtk_menu_item_new_with_label (_ ("View _privacy policy..."));
    258     g_signal_connect (child,
    259                       "activate",
    260                       G_CALLBACK (&view_privacy_policy),
    261                       ctx);
    262     gtk_label_set_use_underline (GTK_LABEL (
    263                                    gtk_bin_get_child (GTK_BIN (child))),
    264                                  TRUE);
    265     gtk_widget_show (child);
    266     gtk_menu_shell_append (GTK_MENU_SHELL (menu),
    267                            child);
    268   }
    269   {
    270     GtkWidget *child;
    271 
    272     child = gtk_menu_item_new_with_label (_ ("View _terms of service..."));
    273     g_signal_connect (child,
    274                       "activate",
    275                       G_CALLBACK (&view_terms_of_service),
    276                       ctx);
    277     gtk_label_set_use_underline (GTK_LABEL (
    278                                    gtk_bin_get_child (GTK_BIN (child))),
    279                                  TRUE);
    280     gtk_widget_show (child);
    281     gtk_menu_shell_append (GTK_MENU_SHELL (menu),
    282                            child);
    283   }
    284 
    285   g_signal_connect (menu,
    286                     "selection-done",
    287                     G_CALLBACK (&context_popup_selection_done),
    288                     ctx);
    289 
    290   gtk_menu_popup_at_pointer (menu,
    291                              event);
    292 
    293   return FALSE;
    294 }
    295 
    296 
    297 /**
    298  * The user clicked the "add" button to add a new provider to the list.
    299  *
    300  * @param button the button object
    301  * @param user_data the builder
    302  */
    303 void
    304 url_add_button_clicked_cb (GtkButton *button,
    305                            gpointer user_data)
    306 {
    307   GtkBuilder *builder = GTK_BUILDER (user_data);
    308   GtkListStore *ls;
    309   GtkEntry *entry;
    310   const char *url;
    311 
    312   ls = GTK_LIST_STORE (gtk_builder_get_object (builder,
    313                                                "provider_liststore"));
    314   GNUNET_assert (NULL != ls);
    315   entry = GTK_ENTRY (gtk_builder_get_object (builder,
    316                                              "url_entry"));
    317   url = gtk_entry_get_text (entry);
    318   gtk_list_store_insert_with_values (ls,
    319                                      NULL,
    320                                      -1,
    321                                      AG_PMC_PROVIDER_URL, url,
    322                                      AG_PMC_PROVIDER_STATUS, _ ("new"),
    323                                      AG_PMC_PROVIDER_STATUS_COLOR, "blue",
    324                                      AG_PMC_PROVIDER_ENABLED, true,
    325                                      AG_PMC_PROVIDER_SENSITIVE, false,
    326                                      AG_PMC_PROVIDER_NOT_SENSITIVE, true,
    327                                      AG_PMC_PROVIDER_NAME, url,
    328                                      -1);
    329   gtk_entry_set_text (entry,
    330                       "");
    331 }
    332 
    333 
    334 /**
    335  * The user changed the URL of a provider to be possibly added.
    336  * Validate the syntax and if it is a valid URL, enable the button.
    337  *
    338  * @param entry the edited widget
    339  * @param user_data the dialog builder
    340  */
    341 void
    342 url_entry_changed_cb (GtkEntry *entry,
    343                       gpointer user_data)
    344 {
    345   GtkBuilder *builder = GTK_BUILDER (user_data);
    346   GtkWidget *button;
    347   const char *url;
    348 
    349   button = GTK_WIDGET (gtk_builder_get_object (builder,
    350                                                "add_button"));
    351   url = gtk_entry_get_text (entry);
    352   gtk_widget_set_sensitive (button,
    353                             (0 == strncasecmp (url,
    354                                                "http://",
    355                                                strlen ("http://"))) ||
    356                             (0 == strncasecmp (url,
    357                                                "https://",
    358                                                strlen ("https://"))));
    359 }
    360 
    361 
    362 /**
    363  * Function called from the edit-provider dialog upon completion.
    364  *
    365  * @param dialog the pseudonym selection dialog
    366  * @param response_id response code from the dialog
    367  * @param user_data the builder of the dialog
    368  */
    369 void
    370 edit_provider_dialog_response_cb (GtkDialog *dialog,
    371                                   gint response_id,
    372                                   gpointer user_data)
    373 {
    374   GtkBuilder *builder = GTK_BUILDER (user_data);
    375   GtkTreeModel *tm;
    376   GtkTreeIter iter;
    377   json_t *args;
    378 
    379   if (GTK_RESPONSE_APPLY != response_id)
    380   {
    381     gtk_widget_destroy (GTK_WIDGET (dialog));
    382     g_object_unref (G_OBJECT (builder));
    383     return;
    384   }
    385   tm = GTK_TREE_MODEL (gtk_builder_get_object (builder,
    386                                                "provider_liststore"));
    387   if (NULL == tm)
    388   {
    389     GNUNET_break (0);
    390     return;
    391   }
    392   args = json_object ();
    393   if (gtk_tree_model_get_iter_first (tm,
    394                                      &iter))
    395     do {
    396       gchar *url;
    397       gboolean enabled;
    398 
    399       gtk_tree_model_get (tm,
    400                           &iter,
    401                           AG_PMC_PROVIDER_URL, &url,
    402                           AG_PMC_PROVIDER_ENABLED, &enabled,
    403                           -1);
    404       GNUNET_assert (0 ==
    405                      json_object_set_new (
    406                        args,
    407                        url,
    408                        GNUNET_JSON_PACK (
    409                          GNUNET_JSON_pack_string ("status",
    410                                                   enabled
    411                                                   ? "not-contacted"
    412                                                   : "disabled"))));
    413       g_free (url);
    414     }
    415     while (gtk_tree_model_iter_next (tm,
    416                                      &iter));
    417   gtk_widget_destroy (GTK_WIDGET (dialog));
    418   g_object_unref (G_OBJECT (builder));
    419   AG_freeze ();
    420   AG_ra = ANASTASIS_redux_action (AG_redux_state,
    421                                   "add_provider",
    422                                   args,
    423                                   &AG_action_cb,
    424                                   NULL);
    425   json_decref (args);
    426 }
    427 
    428 
    429 /**
    430  * Callback invoked if the the "Edit"-provider list button is clicked.
    431  *
    432  * @param object
    433  * @param user_data unused
    434  */
    435 void
    436 anastasis_gtk_edit_provider_list_clicked_cb (GtkButton *object,
    437                                              gpointer user_data)
    438 {
    439   GtkWidget *ad;
    440   GtkBuilder *builder;
    441   GtkListStore *ls;
    442   json_t *providers;
    443 
    444   builder = ANASTASIS_GTK_get_new_builder (
    445     ANASTASIS_GTK_project_data (),
    446     "anastasis_gtk_edit_providers.glade",
    447     NULL);
    448   if (NULL == builder)
    449   {
    450     GNUNET_break (0);
    451     return;
    452   }
    453   ls = GTK_LIST_STORE (gtk_builder_get_object (builder,
    454                                                "provider_liststore"));
    455   providers = json_object_get (AG_redux_state,
    456                                "authentication_providers");
    457   {
    458     const char *url;
    459     const json_t *provider;
    460     json_object_foreach (providers, url, provider)
    461     {
    462       uint32_t http_code = 0;
    463       uint32_t ec = TALER_EC_NONE;
    464       struct TALER_Amount ll;
    465       const char *status;
    466       const char *name = NULL;
    467       struct GNUNET_JSON_Specification spec[] = {
    468         GNUNET_JSON_spec_string ("status",
    469                                  &status),
    470         GNUNET_JSON_spec_mark_optional (
    471           GNUNET_JSON_spec_uint32 ("http_status",
    472                                    &http_code),
    473           NULL),
    474         GNUNET_JSON_spec_mark_optional (
    475           GNUNET_JSON_spec_string ("business_name",
    476                                    &name),
    477           NULL),
    478         GNUNET_JSON_spec_mark_optional (
    479           TALER_JSON_spec_amount_any ("liability_limit",
    480                                       &ll),
    481           NULL),
    482         GNUNET_JSON_spec_mark_optional (
    483           GNUNET_JSON_spec_uint32 ("error_code",
    484                                    &ec),
    485           NULL),
    486         GNUNET_JSON_spec_end ()
    487       };
    488       char *status_str;
    489       const char *color;
    490       bool sensitive = false;
    491       const char *ll_s = NULL;
    492 
    493       memset (&ll,
    494               0,
    495               sizeof (ll));
    496       if (GNUNET_OK !=
    497           GNUNET_JSON_parse (provider,
    498                              spec,
    499                              NULL, NULL))
    500       {
    501         GNUNET_break (0);
    502         json_dumpf (provider,
    503                     stderr,
    504                     JSON_INDENT (2));
    505         continue;
    506       }
    507       if ( (MHD_HTTP_OK == http_code) &&
    508            (0 != strcmp (status,
    509                          "disabled")) )
    510       {
    511         status_str = GNUNET_strdup (_ ("available"));
    512         color = "green";
    513         sensitive = true;
    514         if (GNUNET_OK ==
    515             TALER_amount_is_valid (&ll))
    516           ll_s = TALER_amount2s (&ll);
    517         else
    518           GNUNET_break (0);
    519       }
    520       else if ( (0 == http_code) &&
    521                 (0 != strcmp (status,
    522                               "disabled")) )
    523       {
    524         GNUNET_asprintf (&status_str,
    525                          _ ("Network failure: %s (#%u)"),
    526                          TALER_ErrorCode_get_hint (ec),
    527                          (unsigned int) ec);
    528         color = "red";
    529       }
    530       else if (0 == strcmp (status,
    531                             "disabled"))
    532       {
    533         GNUNET_asprintf (&status_str,
    534                          _ ("disabled"));
    535         color = "blue";
    536         sensitive = true;
    537       }
    538       else
    539       {
    540         GNUNET_asprintf (&status_str,
    541                          _ ("HTTP %s (%u): %s (#%u)"),
    542                          MHD_get_reason_phrase_for (http_code),
    543                          (unsigned int) http_code,
    544                          TALER_ErrorCode_get_hint (ec),
    545                          (unsigned int) ec);
    546         color = "red";
    547       }
    548       if (NULL == name)
    549         name = url;
    550       gtk_list_store_insert_with_values (
    551         ls,
    552         NULL,
    553         -1,
    554         AG_PMC_PROVIDER_URL, url,
    555         AG_PMC_PROVIDER_STATUS, status_str,
    556         AG_PMC_PROVIDER_STATUS_COLOR, color,
    557         AG_PMC_PROVIDER_LIABILITY_LIMIT, ll_s,
    558         AG_PMC_PROVIDER_ENABLED, (0 != strcmp (status,
    559                                                "disabled")),
    560         AG_PMC_PROVIDER_SENSITIVE, sensitive,
    561         AG_PMC_PROVIDER_NOT_SENSITIVE, ! sensitive,
    562         AG_PMC_PROVIDER_NAME, name,
    563         -1);
    564       GNUNET_free (status_str);
    565     }
    566   }
    567   ad = GTK_WIDGET (gtk_builder_get_object (builder,
    568                                            "edit_provider_dialog"));
    569   {
    570     GtkWidget *toplevel;
    571 
    572     toplevel = gtk_widget_get_toplevel (GTK_WIDGET (object));
    573     gtk_window_set_transient_for (GTK_WINDOW (ad),
    574                                   GTK_WINDOW (toplevel));
    575     gtk_window_present (GTK_WINDOW (ad));
    576   }
    577 }