1 /* gpa-tofu-list.c - A list to show TOFU information.
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GPA
5  *
6  * GPA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GPA 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
14  * GNU 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 <https://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 
22 #include "gpa.h"
23 #include "convert.h"
24 #include "gtktools.h"
25 #include "keytable.h"
26 #include "gpa-tofu-list.h"
27 
28 #ifdef ENABLE_TOFU_INFO
29 
30 static gboolean tofu_list_query_tooltip_cb (GtkWidget *wdiget, int x, int y,
31                                             gboolean keyboard_mode,
32                                             GtkTooltip *tooltip,
33                                             gpointer user_data);
34 
35 
36 
37 typedef enum
38 {
39   TOFU_ADDRESS,
40   TOFU_VALIDITY,
41   TOFU_POLICY,
42   TOFU_COUNT,
43   TOFU_FIRSTSIGN,
44   TOFU_LASTSIGN,
45   TOFU_FIRSTENCR,
46   TOFU_LASTENCR,
47   TOFU_N_COLUMNS
48 } SubkeyListColumn;
49 
50 
51 /* Create a new subkey list.  */
52 GtkWidget *
gpa_tofu_list_new(void)53 gpa_tofu_list_new (void)
54 {
55   GtkListStore *store;
56   GtkWidget *list;
57   GtkTreeViewColumn *column;
58   GtkCellRenderer *renderer;
59 
60   /* Init the model */
61   store = gtk_list_store_new (TOFU_N_COLUMNS,
62 			      G_TYPE_STRING,  /* address */
63 			      G_TYPE_STRING,  /* validity */
64 			      G_TYPE_STRING,  /* policy */
65 			      G_TYPE_STRING,  /* count */
66 			      G_TYPE_STRING,  /* firstsign */
67 			      G_TYPE_STRING,  /* lastsign */
68 			      G_TYPE_STRING,  /* firstencr */
69 			      G_TYPE_STRING   /* lastencr */
70                               );
71 
72   /* The view */
73   list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
74   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (list), TRUE);
75 
76   /* Add the columns */
77   renderer = gtk_cell_renderer_text_new ();
78   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
79 						     "text", TOFU_ADDRESS,
80 						     NULL);
81   gpa_set_column_title (column, _("Address"),
82                         _("The mail address."));
83   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
84 
85   renderer = gtk_cell_renderer_text_new ();
86   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
87 						     "text", TOFU_VALIDITY,
88 						     NULL);
89   gpa_set_column_title (column, _("Validity"),
90                         _("The TOFU validity of the mail address:\n"
91                           " Minimal = Only little history available\n"));
92   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
93 
94   renderer = gtk_cell_renderer_text_new ();
95   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
96 						     "text", TOFU_POLICY,
97 						     NULL);
98   gpa_set_column_title (column, _("Policy"),
99                         _("The TOFU policy set for this mail address."));
100   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
101 
102   renderer = gtk_cell_renderer_text_new ();
103   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
104 						     "text", TOFU_COUNT,
105 						     NULL);
106   gpa_set_column_title (column, _("Count"),
107                         _("The number of signatures seen for this address\n"
108                           "and the number of encryption done to this address.")
109                         );
110   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
111 
112   renderer = gtk_cell_renderer_text_new ();
113   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
114 						     "text", TOFU_FIRSTSIGN,
115 						     NULL);
116   gpa_set_column_title (column, _("First Sig"),
117                         _("The date the first signature was verified."));
118   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
119 
120   renderer = gtk_cell_renderer_text_new ();
121   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
122 						     "text", TOFU_LASTSIGN,
123 						     NULL);
124   gpa_set_column_title (column, _("Last Sig"),
125                         _("The most recent date a signature was verified."));
126   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
127 
128   renderer = gtk_cell_renderer_text_new ();
129   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
130 						     "text", TOFU_FIRSTENCR,
131 						     NULL);
132   gpa_set_column_title (column, _("First Enc"),
133                         _("The date the first encrypted mail was sent."));
134   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
135 
136   renderer = gtk_cell_renderer_text_new ();
137   column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
138 						     "text", TOFU_LASTENCR,
139 						     NULL);
140   gpa_set_column_title (column, _("Last Enc"),
141                         _("The most recent date an encrypted mail was sent."));
142   gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
143 
144   g_object_set (list, "has-tooltip", TRUE, NULL);
145   g_signal_connect (list, "query-tooltip",
146                     G_CALLBACK (tofu_list_query_tooltip_cb), list);
147 
148   return list;
149 }
150 
151 
152 static const gchar *
tofu_validity_str(gpgme_tofu_info_t tofu)153 tofu_validity_str (gpgme_tofu_info_t tofu)
154 {
155   switch (tofu->validity)
156     {
157     case 0: return _("Conflict");
158     case 1: return _("Unknown");
159     case 2: return _("Minimal");
160     case 3: return _("Basic");
161     case 4: return _("Full");
162     default: return "?";
163     }
164 }
165 
166 
167 static const gchar *
tofu_policy_str(gpgme_tofu_info_t tofu)168 tofu_policy_str (gpgme_tofu_info_t tofu)
169 {
170   switch (tofu->policy)
171     {
172     case GPGME_TOFU_POLICY_NONE:    return _("None");
173     case GPGME_TOFU_POLICY_AUTO:    return _("Auto");
174     case GPGME_TOFU_POLICY_GOOD:    return _("Good");
175     case GPGME_TOFU_POLICY_UNKNOWN: return _("Unknown");
176     case GPGME_TOFU_POLICY_BAD:     return _("Bad");
177     case GPGME_TOFU_POLICY_ASK:     return _("Ask");
178     }
179   return "?";
180 }
181 
182 
183 /* Set the key whose subkeys should be displayed. */
184 void
gpa_tofu_list_set_key(GtkWidget * list,gpgme_key_t key)185 gpa_tofu_list_set_key (GtkWidget *list, gpgme_key_t key)
186 {
187   GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model
188                                         (GTK_TREE_VIEW (list)));
189   GtkTreeIter iter;
190   gpgme_user_id_t uid;
191   gpgme_tofu_info_t tofu;
192   char *countstr, *firstsign, *lastsign, *firstencr, *lastencr;
193 
194   /* Empty the list */
195   gtk_list_store_clear (store);
196 
197   if (!key || !key->uids)
198     return;
199 
200   for (uid = key->uids; uid; uid = uid->next)
201     {
202       if (!uid->address || !uid->tofu)
203         continue;  /* No address or tofu info.  */
204       tofu = uid->tofu;
205 
206       /* Note that we do not need to filter ADDRESS like we do with
207        * user ids because GPGME checked that it is a valid mail
208        * address.  */
209       countstr = g_strdup_printf ("%hu/%hu", tofu->signcount, tofu->encrcount);
210       firstsign = gpa_date_string (tofu->signfirst);
211       lastsign  = gpa_date_string (tofu->signlast);
212       firstencr = gpa_date_string (tofu->encrfirst);
213       lastencr  = gpa_date_string (tofu->encrlast);
214 
215       gtk_list_store_append (store, &iter);
216       gtk_list_store_set
217         (store, &iter,
218          TOFU_ADDRESS,  uid->address,
219          TOFU_VALIDITY, tofu_validity_str (tofu),
220          TOFU_POLICY,   tofu_policy_str (tofu),
221          TOFU_COUNT,    countstr,
222          TOFU_FIRSTSIGN,firstsign,
223          TOFU_LASTSIGN, lastsign,
224          TOFU_FIRSTENCR,firstencr,
225          TOFU_LASTENCR, lastencr,
226          -1);
227 
228       g_free (countstr);
229       g_free (firstsign);
230       g_free (lastsign);
231       g_free (firstencr);
232       g_free (lastencr);
233     }
234 
235 }
236 
237 
238 /* Tooltip display callback.  */
239 static gboolean
tofu_list_query_tooltip_cb(GtkWidget * widget,int x,int y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer user_data)240 tofu_list_query_tooltip_cb (GtkWidget *widget, int x, int y,
241                             gboolean keyboard_tip,
242                             GtkTooltip *tooltip, gpointer user_data)
243 {
244   GtkTreeView *tv = GTK_TREE_VIEW (widget);
245   GtkTreeViewColumn *column;
246   char *text;
247 
248   (void)user_data;
249 
250   if (!gtk_tree_view_get_tooltip_context (tv, &x, &y, keyboard_tip,
251                                           NULL, NULL, NULL))
252     return FALSE; /* Not at a row - do not show a tooltip.  */
253   if (!gtk_tree_view_get_path_at_pos (tv, x, y, NULL, &column, NULL, NULL))
254     return FALSE;
255 
256   widget = gtk_tree_view_column_get_widget (column);
257   text = widget? gtk_widget_get_tooltip_text (widget) : NULL;
258   if (!text)
259     return FALSE; /* No tooltip desired.  */
260 
261   gtk_tooltip_set_text (tooltip, text);
262   g_free (text);
263 
264   return TRUE; /* Show tooltip.  */
265 }
266 #endif /*ENABLE_TOFU_INFO*/
267