anastasis-gtk_progress.c (8792B)
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 * @file src/anastasis/anastasis-gtk_progress.c 22 * @brief Functions dealing with the lists that show the user where we are in the process 23 * @author Christian Grothoff 24 */ 25 #include <gnunet/gnunet_util_lib.h> 26 #include "anastasis_gtk_util.h" 27 #include "anastasis-gtk_helper.h" 28 #include "anastasis-gtk_rows.h" 29 #include <gdk-pixbuf/gdk-pixbuf.h> 30 31 32 /** 33 * One step of one of the two processes we guide the user through. 34 */ 35 struct Step 36 { 37 /** 38 * Name of the step, as shown to the user. 39 */ 40 const char *description; 41 42 /** 43 * Regular expression matching the reducer states this step covers. 44 */ 45 const char *regex; 46 47 /** 48 * Long explanation of the step, shown as a tooltip. 49 */ 50 const char *tooltip; 51 }; 52 53 54 /** 55 * The steps of making a backup. 56 */ 57 static const struct Step backup_steps[] = { 58 { .description = N_ ("1. Location & currency"), 59 .regex = "^(CONTINENT|COUNTRY)_SELECTING$", 60 .tooltip = N_ ( 61 "Where you live will determine which personal information can be used to identify your backup.") }, 62 { .description = N_ ("2. Personal information"), 63 .regex = "^USER_ATTRIBUTES_COLLECTING$", 64 .tooltip = N_ ( 65 "Your personal information will not be shared with anyone. But you must provide the same information during recovery.\\") }, 66 { .description = N_ ("3. Authorization methods"), 67 .regex = "^AUTHENTICATIONS_EDITING$", 68 .tooltip = N_ ( 69 "Specify which methods could be used to authenticate you during recovery.") }, 70 { .description = N_ ("4. Recovery policies"), 71 .regex = "^POLICIES_REVIEWING$", 72 .tooltip = N_ ( 73 "These are possible ways how the secret could be recovered. Please review and possibly edit the policies.") }, 74 { .description = N_ ("5. Enter secret"), 75 .regex = "^SECRET_EDITING$", 76 .tooltip = N_ ("Please specify the secret to be backed up.") }, 77 { .description = N_ ("6. Payment (optional)"), 78 .regex = "^.*_PAYING$", 79 .tooltip = N_ ( 80 "Some Anastasis providers require payment for their service. Please pay.") }, 81 { .description = N_ ("7. Backup completed"), 82 .regex = "BACKUP_FINISHED", 83 .tooltip = N_ ( 84 "Your backup is complete. Please do test the recovery on occasion.") }, 85 { .description = NULL } 86 }; 87 88 89 /** 90 * The steps of a recovery. 91 */ 92 static const struct Step recovery_steps[] = { 93 { .description = N_ ("1. Location & currency"), 94 .regex = "^(CONTINENT|COUNTRY)_SELECTING$", 95 .tooltip = N_ ( 96 "Where you live will determine which personal information can be used to identify your backup.") }, 97 { .description = N_ ("2. Personal information"), 98 .regex = "^USER_ATTRIBUTES_COLLECTING$", 99 .tooltip = N_ ( 100 "Your personal information will not be shared with anyone. But you must provide the same information during recovery.") }, 101 { .description = N_ ("3. Select secret"), 102 .regex = "^SECRET_SELECTING$", 103 .tooltip = N_ ( 104 "Please select which secret to recover. You may switch to a different version or provider.") }, 105 { .description = N_ ("4. Solve challenges"), 106 /* paying for a challenge and answering it are both part of this step */ 107 .regex = "^CHALLENGE_(SELECTING|PAYING|SOLVING)$", 108 .tooltip = N_ ( 109 "Please select an authentication challenge to pass to recover the secret.") }, 110 { .description = N_ ("5. Secret recovered"), 111 .regex = "^RECOVERY_FINISHED$", 112 .tooltip = N_ ("Your secret was successfully recovered.") }, 113 { .description = NULL } 114 }; 115 116 117 /** 118 * Fill the list called @a name with the given @a steps. 119 * 120 * @param name name of the model in the UI file 121 * @param steps the steps to show 122 */ 123 static void 124 fill_progress (const char *name, 125 const struct Step *steps) 126 { 127 GListStore *list = AG_list (name); 128 129 if (NULL == list) 130 return; 131 for (unsigned int i = 0; NULL != steps[i].description; i++) 132 AG_list_append (list, 133 GNUNET_JSON_PACK ( 134 GNUNET_JSON_pack_string ("description", 135 _ (steps[i].description)), 136 GNUNET_JSON_pack_string ("regex", 137 steps[i].regex), 138 GNUNET_JSON_pack_string ("tooltip", 139 _ (steps[i].tooltip)))); 140 } 141 142 143 void 144 AG_progress_setup (void) 145 { 146 fill_progress ("anastasis_gtk_backup_progress_liststore", 147 backup_steps); 148 fill_progress ("anastasis_gtk_recovery_progress_liststore", 149 recovery_steps); 150 } 151 152 153 /** 154 * The progress lists only report where we are in the process; the user must 155 * not be able to change the selection by clicking. The gesture runs in the 156 * capture phase, so claiming the sequence here keeps the click from ever 157 * reaching the list. 158 * 159 * @param gesture the click gesture of the list 160 * @param n_press number of presses 161 * @param x horizontal position of the click 162 * @param y vertical position of the click 163 * @param user_data NULL 164 */ 165 void 166 anastasis_gtk_progress_treeview_pressed_cb (GtkGestureClick *gesture, 167 gint n_press, 168 gdouble x, 169 gdouble y, 170 gpointer user_data) 171 { 172 (void) n_press; 173 (void) x; 174 (void) y; 175 (void) user_data; 176 gtk_gesture_set_state (GTK_GESTURE (gesture), 177 GTK_EVENT_SEQUENCE_CLAIMED); 178 } 179 180 181 /** 182 * Function to validate an input by regular expression ("validation-regex"). 183 * 184 * @param input text to validate 185 * @param regexp regular expression to validate form 186 * @return true if validation passed, else false 187 */ 188 static bool 189 validate_regex (const char *input, 190 const char *regexp) 191 { 192 regex_t regex; 193 194 if (0 != regcomp (®ex, 195 regexp, 196 REG_EXTENDED)) 197 { 198 GNUNET_break (0); 199 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 200 "Failed to compile regular expression `%s'.", 201 regexp); 202 return true; 203 } 204 /* check if input has correct form */ 205 if (0 != regexec (®ex, 206 input, 207 0, 208 NULL, 209 0)) 210 { 211 regfree (®ex); 212 return false; 213 } 214 regfree (®ex); 215 return true; 216 } 217 218 219 void 220 AG_progress_update (void) 221 { 222 const char *sel_name; 223 GListModel *steps; 224 const char *state; 225 guint n; 226 227 state = json_string_value (json_object_get (AG_redux_state, 228 "backup_state")); 229 if (NULL == state) 230 { 231 state = json_string_value (json_object_get (AG_redux_state, 232 "recovery_state")); 233 if (NULL == state) 234 { 235 GNUNET_break (0); 236 return; 237 } 238 sel_name = "anastasis_gtk_recovery_progress_tree_selection"; 239 steps = G_LIST_MODEL (AG_list ( 240 "anastasis_gtk_recovery_progress_liststore")); 241 } 242 else 243 { 244 sel_name = "anastasis_gtk_backup_progress_tree_selection"; 245 steps = G_LIST_MODEL (AG_list ( 246 "anastasis_gtk_backup_progress_liststore")); 247 } 248 if (NULL == steps) 249 return; 250 n = g_list_model_get_n_items (steps); 251 for (guint i = 0; i < n; i++) 252 { 253 AGRow *row = g_list_model_get_item (steps, 254 i); 255 bool match; 256 257 match = validate_regex (state, 258 AG_row_string (row, 259 "regex")); 260 g_object_unref (row); 261 if (match) 262 { 263 /* The selection is what highlights the step the user is at. Nothing 264 else ever moves it: the lists are not focusable and they swallow 265 clicks. */ 266 AG_select_row (sel_name, 267 i); 268 return; 269 } 270 } 271 /* the reducer is in a state none of the steps above cover */ 272 GNUNET_break (0); 273 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 274 "No progress step matches state `%s'\n", 275 state); 276 }