1 /*
2  * frogr-auth-dialog.c -- Authorization dialog
3  *
4  * Copyright (C) 2009-2018 Mario Sanchez Prada
5  * Authors: Mario Sanchez Prada <msanchez@gnome.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 3 of the GNU General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>
18  *
19  */
20 
21 #include "frogr-auth-dialog.h"
22 
23 #include "frogr-controller.h"
24 #include "frogr-global-defs.h"
25 #include "frogr-util.h"
26 
27 #include <config.h>
28 #include <glib/gi18n.h>
29 
30 #if GTK_CHECK_VERSION (3, 12, 0)
31 #define AUTH_DIALOG_FLAGS (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR)
32 #else
33 #define AUTH_DIALOG_FLAGS (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT)
34 #endif
35 
36 
37 /* Prototypes */
38 
39 static void _ask_for_authorization (GtkWindow *parent);
40 
41 static void _ask_for_authorization_response_cb (GtkDialog *dialog, gint response, gpointer data);
42 
43 static void _ask_for_auth_confirmation (GtkWindow *parent);
44 
45 static void _ask_for_auth_confirmation_response_cb (GtkDialog *dialog, gint response, gpointer data);
46 
47 /* Private API */
48 
49 static void
_ask_for_authorization(GtkWindow * parent)50 _ask_for_authorization (GtkWindow *parent)
51 {
52   GtkWidget *dialog = NULL;
53   g_autofree gchar *title = NULL;
54 
55   dialog = gtk_message_dialog_new (parent,
56                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
57                                    GTK_MESSAGE_INFO,
58                                    GTK_BUTTONS_OK,
59                                    _("Please press the button to authorize %s "
60                                      "and then come back to complete the process."),
61                                    APP_SHORTNAME);
62 
63   title = g_strdup_printf (_("Authorize %s"), APP_SHORTNAME);
64   gtk_window_set_title (GTK_WINDOW (dialog), title);
65 
66   g_signal_connect (G_OBJECT (dialog), "response",
67                     G_CALLBACK (_ask_for_authorization_response_cb), NULL);
68 
69   gtk_widget_show (dialog);
70 }
71 
72 static void
_ask_for_authorization_response_cb(GtkDialog * dialog,gint response,gpointer data)73 _ask_for_authorization_response_cb (GtkDialog *dialog, gint response, gpointer data)
74 {
75   if (response == GTK_RESPONSE_OK)
76     {
77       FrogrController *controller = frogr_controller_get_instance();
78       frogr_controller_open_auth_url (controller);
79     }
80 
81   gtk_widget_destroy (GTK_WIDGET (dialog));
82 }
83 
84 static void
_code_entry_text_inserted_cb(GtkEditable * editable,gchar * new_text,gint new_text_length,gint * position,gpointer data)85 _code_entry_text_inserted_cb (GtkEditable *editable, gchar *new_text,
86                               gint new_text_length, gint *position,
87                               gpointer data)
88 {
89   gint i = 0;
90   for (i = 0; i < new_text_length; i++)
91     {
92       /* Stop this signal's emission if one of the new characters is
93          not an integer, and stop searching, obviously */
94       if (!g_ascii_isdigit (new_text[i]))
95         {
96           g_signal_stop_emission_by_name (editable, "insert-text");
97           break;
98         }
99     }
100 }
101 
102 static GtkWidget *
_build_verification_code_entry_widget(GtkWidget * dialog)103 _build_verification_code_entry_widget (GtkWidget *dialog)
104 {
105   GtkWidget *hbox = NULL;
106   GtkWidget *entry = NULL;
107   GtkWidget *separator = NULL;
108   gchar *entry_key = NULL;
109   gint i = 0;
110 
111   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
112   gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
113   for (i = 0; i < 3; i++)
114     {
115       entry = gtk_entry_new ();
116       gtk_entry_set_max_length (GTK_ENTRY (entry), 3);
117       gtk_entry_set_width_chars (GTK_ENTRY (entry), 3);
118       gtk_entry_set_alignment (GTK_ENTRY (entry), 0.5);
119       gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 6);
120       gtk_widget_show (entry);
121 
122       entry_key = g_strdup_printf ("vercode-%d", i + 1);
123       g_object_set_data (G_OBJECT (dialog), entry_key, entry);
124       g_free (entry_key);
125 
126       g_signal_connect (G_OBJECT (entry), "insert-text",
127                     G_CALLBACK (_code_entry_text_inserted_cb),
128                     NULL);
129       if (i < 2)
130         {
131           separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
132           gtk_box_pack_start (GTK_BOX (hbox), separator, TRUE, TRUE, 0);
133           gtk_widget_show (separator);
134         }
135     }
136 
137   gtk_widget_show (hbox);
138   return hbox;
139 }
140 
141 static void
_ask_for_auth_confirmation(GtkWindow * parent)142 _ask_for_auth_confirmation (GtkWindow *parent)
143 {
144   GtkWidget *dialog = NULL;
145   GtkWidget *content_area = NULL;
146   GtkWidget *vbox = NULL;
147   GtkWidget *ver_code_entry = NULL;
148   GtkWidget *label = NULL;
149   g_autofree gchar *title = NULL;
150 
151   title = g_strdup_printf (_("Authorize %s"), APP_SHORTNAME);
152   dialog = gtk_dialog_new_with_buttons (title,
153                                         parent,
154                                         AUTH_DIALOG_FLAGS,
155                                         _("_Cancel"),
156                                         GTK_RESPONSE_CANCEL,
157                                         _("_Close"),
158                                         GTK_RESPONSE_CLOSE,
159                                         NULL);
160   gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
161 
162   /* Fill action area */
163   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
164   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
165   gtk_widget_set_margin_bottom (vbox, 6);
166   gtk_widget_show (vbox);
167 
168   /* Description label */
169   label = gtk_label_new (_("Enter verification code:"));
170   gtk_widget_set_halign (label, GTK_ALIGN_START);
171   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
172   gtk_widget_show (label);
173 
174   /* Entry widgets for the verification code */
175   ver_code_entry = _build_verification_code_entry_widget (dialog);
176   gtk_box_pack_start (GTK_BOX (vbox), ver_code_entry, FALSE, FALSE, 0);
177   gtk_widget_show (ver_code_entry);
178 
179   gtk_widget_show (content_area);
180   gtk_container_add (GTK_CONTAINER (content_area), vbox);
181 
182   g_signal_connect (G_OBJECT (dialog), "response",
183                     G_CALLBACK (_ask_for_auth_confirmation_response_cb), NULL);
184 
185   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
186 
187   gtk_window_set_default_size (GTK_WINDOW (dialog), 200, -1);
188   gtk_widget_show (dialog);
189 }
190 
191 static const gchar*
_get_entry_code_for_dialog(GtkDialog * dialog,const gchar * entry_key)192 _get_entry_code_for_dialog (GtkDialog *dialog, const gchar *entry_key)
193 {
194   GtkWidget *entry = g_object_get_data (G_OBJECT (dialog), entry_key);
195   if (entry == NULL)
196     return NULL;
197 
198   return gtk_entry_get_text (GTK_ENTRY (entry));
199 }
200 
201 static void
_ask_for_auth_confirmation_response_cb(GtkDialog * dialog,gint response,gpointer data)202 _ask_for_auth_confirmation_response_cb (GtkDialog *dialog, gint response, gpointer data)
203 {
204   gboolean valid = FALSE;
205 
206   if (response == GTK_RESPONSE_CLOSE)
207     {
208       const gchar *vercode_part1 = NULL;
209       const gchar *vercode_part2 = NULL;
210       const gchar *vercode_part3 = NULL;
211       g_autofree gchar *vercode_full = NULL;
212 
213       vercode_part1 = _get_entry_code_for_dialog (dialog, "vercode-1");
214       vercode_part2 = _get_entry_code_for_dialog (dialog, "vercode-2");
215       vercode_part3 = _get_entry_code_for_dialog (dialog, "vercode-3");
216 
217       vercode_full = g_strdup_printf ("%s-%s-%s", vercode_part1, vercode_part2, vercode_part3);
218 
219       /* Ensure the user enters a valid verification code */
220       if (g_regex_match_simple ("[0-9]{3}(-[0-9]{3}){2}", vercode_full, 0, 0))
221         {
222           frogr_controller_complete_auth (frogr_controller_get_instance(), vercode_full);
223           valid = TRUE;
224         }
225       else
226         frogr_util_show_error_dialog (GTK_WINDOW (dialog), _("Invalid verification code"));
227     }
228 
229   if (response == GTK_RESPONSE_CANCEL || valid)
230     gtk_widget_destroy (GTK_WIDGET (dialog));
231 }
232 
233 /* Public API */
234 
235 void
frogr_auth_dialog_show(GtkWindow * parent,FrogrAuthDialogStep step)236 frogr_auth_dialog_show (GtkWindow *parent, FrogrAuthDialogStep step)
237 {
238   switch (step) {
239   case REQUEST_AUTHORIZATION:
240     _ask_for_authorization (parent);
241     break;
242   case CONFIRM_AUTHORIZATION:
243     _ask_for_auth_confirmation (parent);
244     break;
245   default:
246     g_assert_not_reached();
247   }
248 }
249