Update called vala api.
[stuffkeeper.git] / src / stuffkeeper-data-password.gob
blob17c237c1836a66aea82f44b5cd8c34da4ecfc5c2
3 %h{
4 #include <gtk/gtk.h>
5 #include <config.h>
6 #include <gpgme.h>
7 #include "misc.h"
8 #include "stuffkeeper-data-item.h"
9 %}
11 %ph{
12 #include "stuffkeeper-data-backend.h"
16         enum {
17                 PRIVATE_FIELD_GPGKEY = 0
18         };
22 class Stuffkeeper:Data:Password from Gtk:HBox
24         private GtkWidget *entry = {NULL};
25         private GtkWidget *button = {NULL};
26         private GtkWidget *butimg = {NULL};
28         private StuffkeeperDataItem *item = {NULL};
29         private gchar *field = {NULL} destroywith g_free;
30         private gulong changed_item_entry = {0};
31         private gulong changed_entry = {0};
32         private gulong custom_field_changed = {0};
34         private guint changed_entry_timeout = {0};
35         private GdkColor writing ;
36         private GdkColor base;
37         private GdkColor text;
39         /* lock signal */
40         private gulong signal_backend_locked = {0};
41         
42         /* Encryption stuff */
43         private gpgme_ctx_t ctx = NULL;
44         private gpgme_key_t keys[2];
46         private gboolean unlocked = FALSE;
49         private
50                 gboolean  
51                 save_changes(self)
52                 {
53                         if(self_has_key(self))
54                         {
55                                 const gchar *text = gtk_entry_get_text(GTK_ENTRY(self->_priv->entry));
56                                 if(self->_priv->field)
57                                 {
58                                         gpgme_data_t dh_plain = 0, dh_cipher = 0;
59                                         gpgme_error_t err;
60                                         gpgme_data_new_from_mem(&dh_plain,text, strlen(text), 0);
61                                         gpgme_data_new(&dh_cipher);
62                                         err = gpgme_op_encrypt(self->_priv->ctx, 
63                                                         &(self->_priv->keys[0]),
64                                                         GPGME_ENCRYPT_ALWAYS_TRUST,
65                                                         dh_plain,
66                                                         dh_cipher);
67                                         if(!err)
68                                         {
69                                                 size_t nRead = 0;
70                                                 gchar *cipher = NULL;
71                                                 cipher = gpgme_data_release_and_get_mem(dh_cipher, &nRead);
72                                                 gchar *temp = g_malloc0((nRead+2)*sizeof(gchar *));
73                                                 memcpy(temp, cipher, nRead);
74                                                 g_signal_handler_block(self->_priv->item,self->_priv->changed_item_entry);
75                                                 stuffkeeper_data_item_set_string(self->_priv->item, self->_priv->field, temp);
76                                                 g_signal_handler_unblock(self->_priv->item,self->_priv->changed_item_entry);
77                                                 g_free(temp);
78                                                 gpgme_free(cipher);
79                                         }else {
80                                                 self_set_lock(self, FALSE);
81                                         }
82                                 
83                                         gpgme_data_release(dh_plain);
84                                 }
85                         }
86                         gtk_widget_modify_text(GTK_WIDGET(self->_priv->entry), GTK_STATE_NORMAL, &(self->_priv->text));
87                         gtk_widget_modify_base(GTK_WIDGET(self->_priv->entry), GTK_STATE_NORMAL, &(self->_priv->base));
88                         self->_priv->changed_entry_timeout = 0;
89                         return FALSE;
90                 }
94         private
95                 void
96                 changed(self, gpointer data)
97                 {
98                         if(self->_priv->changed_entry_timeout)
99                         {
100                                 g_source_remove(self->_priv->changed_entry_timeout);
101                         }
102                         self->_priv->changed_entry_timeout = g_timeout_add(1000,(GSourceFunc)self_save_changes,self);
104                         gtk_widget_modify_text(GTK_WIDGET(self->_priv->entry), GTK_STATE_NORMAL, &(GTK_WIDGET(self)->style->black));
105                         gtk_widget_modify_base(GTK_WIDGET(self->_priv->entry), GTK_STATE_NORMAL, &(self->_priv->writing));
106                 }
108         private
109                 void
110                 item_changed(self,const gchar *field, StuffkeeperDataItem *item)
111                 {
112                         const gchar *text = gtk_entry_get_text(GTK_ENTRY(self->_priv->entry));
113                         gchar *value = NULL;
114                         if(self->_priv->field && field && self_has_key(self))
115                         {
116                                 if(strcmp(field, self->_priv->field) == 0)
117                                 {
118                                         value = stuffkeeper_data_item_get_string(item, self->_priv->field);
119                                         if(value && strcmp(text,value))
120                                         {
121                                                 g_signal_handler_block(self->_priv->entry,self->_priv->changed_entry);
122                                                 gpgme_data_t dh_plain = 0, dh_cipher = 0;
123                                                 gpgme_error_t err;
124                                                 gpgme_data_new_from_mem(&dh_cipher,value, strlen(value), 0);
125                                                 gpgme_data_new(&dh_plain);
126                                                 err = gpgme_op_decrypt(self->_priv->ctx, dh_cipher,dh_plain);
127                                                 if(!err)
128                                                 {
129                                                         size_t nRead = 0;
130                                                         gchar *plain= NULL;
131                                                         plain = gpgme_data_release_and_get_mem(dh_plain, &nRead);
132                                                         gchar *temp = g_malloc0((nRead+2)*sizeof(gchar *));
133                                                         memcpy(temp, plain, nRead);
134                                                         gtk_entry_set_text(GTK_ENTRY(self->_priv->entry), temp);
135                                                         g_free(temp);
136                                                         gpgme_free(plain);
137                                                 }else{
138                                                         g_debug("Error decrypting: %s. Locking entry\n", gpgme_strerror(err));
139                                                         self_set_lock(self, FALSE);
140                                                 }
141                                                 gpgme_data_release(dh_cipher);
142 //                                              gtk_entry_set_text(GTK_ENTRY(self), value);
143                                                 g_signal_handler_unblock(self->_priv->entry,self->_priv->changed_entry);
144                                         }
145                                         g_free(value);
146                                 }
147                         }
148                 }
149         private 
150                 void
151                 style_set(self, GtkStyle *prev, GtkWidget *wid)
152                 {
153                         if(self->_priv->changed_entry_timeout == 0) {
154                                 self->_priv->base = (GTK_WIDGET(self)->style->base[GTK_STATE_NORMAL]);
155                                 self->_priv->text = (GTK_WIDGET(self)->style->text[GTK_STATE_NORMAL]);
156                         }
157                 }
158         private
159                 void
160                 backend_locked(self, GParamSpec *arg1, StuffkeeperDataBackend *backend)
161                 {
162                         gboolean locked = stuffkeeper_data_backend_get_locked(backend);
163                         if(self_has_key(self))
164                                 gtk_editable_set_editable(GTK_EDITABLE(self->_priv->entry), !locked);
165                         else
166                                 gtk_editable_set_editable(GTK_EDITABLE(self->_priv->entry), FALSE);
167                 }
168         private void
169         custom_field_changed(self, const gchar *id, int field, StuffkeeperDataSchema *schema)
170         {
171                 if(field == PRIVATE_FIELD_GPGKEY)
172                 {
173                         gpgme_error_t err;
174                         gchar  *value = NULL;
175                         /* safe pending changes */
176                         if(self->_priv->changed_entry_timeout)
177                         {
178                                 g_source_remove(self->_priv->changed_entry_timeout);
179                                 self->_priv->changed_entry_timeout = 0;
181                                 self_save_changes(self);
182                         }
183                         self->_priv->unlocked = FALSE;
184                         /* clear */
186                         g_signal_handler_block(self->_priv->entry,self->_priv->changed_entry);
187                         gtk_entry_set_text(GTK_ENTRY(self->_priv->entry), "**********");
188                         g_signal_handler_unblock(self->_priv->entry,self->_priv->changed_entry);
189                         /** destroy key */
190                         if(self->_priv->keys[0])
191                         {
192                                 gpgme_key_unref(self->_priv->keys[0]);
193                                 self->_priv->keys[0]= 0;
194                         }
195                         value = stuffkeeper_data_schema_get_custom_field_string(schema, self->_priv->field,field); 
196                         if(value)
197                         {
198                                 err = gpgme_get_key(self->_priv->ctx, value, &(self->_priv->keys[0]), 1);
199                                 if(err){
200                                         g_debug("getting key: %s\n", gpgme_strerror(err));
201                                         gtk_widget_set_sensitive(self->_priv->button,FALSE);
202                                 }else {
203                                         gtk_widget_set_sensitive(self->_priv->button,TRUE);
204                                 }
205                                 g_free(value);
206                         }
208                         self_backend_locked(self,NULL, STUFFKEEPER_DATA_BACKEND(stuffkeeper_data_item_get_backend(self->_priv->item)));
209                 }
210         }
212         public
213                 GtkWidget *
214                 new(StuffkeeperDataItem *item, const gchar *field (check null))
215                 {
216                         Self *obj = GET_NEW;
217                         gchar *value =NULL;
218                         gpgme_error_t err;
220                         obj->_priv->entry = gtk_entry_new();
221                         gtk_entry_set_text(GTK_ENTRY(obj->_priv->entry), "**********");
222                         gtk_box_pack_start(GTK_BOX(obj), obj->_priv->entry,TRUE,TRUE,0);
224                         obj->_priv->button = gtk_button_new();
225                         gtk_button_set_relief(GTK_BUTTON(obj->_priv->button), GTK_RELIEF_NONE);
226                         gtk_box_pack_start(GTK_BOX(obj), obj->_priv->button,FALSE,FALSE,0);
227                         obj->_priv->butimg = gtk_image_new_from_stock(GTK_STOCK_DIALOG_AUTHENTICATION, GTK_ICON_SIZE_MENU);
228                         gtk_container_add(GTK_CONTAINER(obj->_priv->button), GTK_WIDGET(obj->_priv->butimg));
230                         if(!g_key_file_get_boolean(config_file, "interface", "has-border",NULL))
231                                 gtk_entry_set_has_frame(GTK_ENTRY(obj->_priv->entry), FALSE);
233                         obj->_priv->base = (GTK_WIDGET(obj)->style->base[GTK_STATE_NORMAL]);
234                         obj->_priv->text = (GTK_WIDGET(obj)->style->text[GTK_STATE_NORMAL]);
235                         obj->_priv->writing.red = 255*255;
236                         obj->_priv->writing.green = 253*255;
237                         obj->_priv->writing.blue = 197*255;
238                         gdk_colormap_alloc_color(gtk_widget_get_default_colormap(), &(obj->_priv->writing), TRUE,TRUE);
239                         g_signal_connect_swapped(G_OBJECT(obj), "style-set", G_CALLBACK(self_style_set),obj);
242                         /* store item */
243                         obj->_priv->item = item; 
244                         /* field */
245                         obj->_priv->field = g_strdup(field);
246                         
247                         /* Setup the encryption stuff */
248                         obj->_priv->keys[0] = 0;
249                         obj->_priv->keys[1] = 0;
250                         err = gpgme_new(&(obj->_priv->ctx));
251                         if(err){
252                                 g_debug("Failed to create gpgme context: %i:%s\n",
253                                                 err,
254                                                 gpgme_strerror(err));
255                         }
256                         gpgme_set_armor((obj->_priv->ctx), 1);
257                         /* setup key */
258                         value = stuffkeeper_data_schema_get_custom_field_string(stuffkeeper_data_item_get_schema(item), obj->_priv->field,PRIVATE_FIELD_GPGKEY); 
259                         if(value){
261                                 err = gpgme_get_key(obj->_priv->ctx, value, &(obj->_priv->keys[0]), 1);
264                                 if(err){
265                                         g_debug("getting key: %s\n", gpgme_strerror(err));
266                                         gtk_widget_set_sensitive(obj->_priv->button,FALSE);
267                                 }
268                                 g_free(value);
269                         }
271                         obj->_priv->changed_item_entry = g_signal_connect_swapped(G_OBJECT(item), "item-changed", G_CALLBACK(self_item_changed), obj);
272         
274                         obj->_priv->signal_backend_locked = g_signal_connect_swapped(G_OBJECT(stuffkeeper_data_item_get_backend(item)), 
275                                         "notify::locked", G_CALLBACK(self_backend_locked), obj);
277                         gtk_widget_show_all(GTK_WIDGET(obj));
278                         self_backend_locked(obj,NULL, STUFFKEEPER_DATA_BACKEND(stuffkeeper_data_item_get_backend(item)));
280                         /* this is destroyed when self is destroyed, so no need to disconnect myself */
281                         obj->_priv->changed_entry = g_signal_connect_swapped(G_OBJECT(obj->_priv->entry), "changed", G_CALLBACK(self_changed), obj);
284                         if(self_has_key(obj))
285                         {/*
286                                 gtk_editable_set_editable(GTK_EDITABLE(obj->_priv->entry), FALSE);
287                         }else {*/
288                                 self_item_changed(obj, obj->_priv->field, obj->_priv->item);
289                         }
290                         g_signal_connect_swapped(G_OBJECT(obj->_priv->button), "clicked", G_CALLBACK(self_unlock_clicked), obj);                        
292                         obj->_priv->custom_field_changed = g_signal_connect_swapped(stuffkeeper_data_item_get_schema(obj->_priv->item), 
293                                         "schema_custom_field_changed", G_CALLBACK(self_custom_field_changed), obj);
294                         return GTK_WIDGET(obj);
295                 }
297         override (G:Object)
298                 void
299                 dispose (G:Object *obj)
300                 {
301                         Self *self = SELF(obj);
302                         if(self->_priv->signal_backend_locked) {                                                                     
303                                 g_signal_handler_disconnect(G_OBJECT(stuffkeeper_data_item_get_backend(self->_priv->item)), self->_priv->signal_backend_locked);
304                                 self->_priv->signal_backend_locked = 0;
305                         }
306                         if(self->_priv->changed_item_entry)
307                         {
308                                 g_signal_handler_disconnect(self->_priv->item,self->_priv->changed_item_entry);
309                                 self->_priv->changed_item_entry = 0;
310                         }
311                         if(self->_priv->changed_entry_timeout)
312                         {
313                                 g_source_remove(self->_priv->changed_entry_timeout);
314                                 self->_priv->changed_entry_timeout = 0;
316                                 self_save_changes(self);
317                         }
318                         if(self->_priv->custom_field_changed)
319                         {
320                                 g_signal_handler_disconnect(stuffkeeper_data_item_get_schema(self->_priv->item),self->_priv->custom_field_changed);
321                                 self->_priv->custom_field_changed = 0;
322                         }
326                         /* clear encryption context */
327                         if(self->_priv->ctx)
328                         {
329                                 gpgme_release(self->_priv->ctx);
330                                 self->_priv->ctx = NULL;
331                         }
332                         /* clear key */
333                         if(self->_priv->keys[0])
334                         {
335                                 gpgme_key_unref(self->_priv->keys[0]);
336                                 self->_priv->keys[0]= 0;
337                         }
338                         PARENT_HANDLER(obj);
339                 }
341         private 
342         void
343         unlock_clicked(self, GtkWidget *button)
344         {
345                 g_debug("%s activate\n", __FUNCTION__);
346                 self_set_lock(self, !self->_priv->unlocked);
347         }
348         private
349         void
350         set_lock(self, gboolean lock)
351         {       
352                 g_debug("Unlock/Lock key\n");
353                 if(self->_priv->keys[0]== 0) return;
355                 if(lock && !self->_priv->unlocked)
356                 {
357                         g_debug("UnLock key\n");
358                         self->_priv->unlocked = TRUE;
359                         g_signal_handler_block(self->_priv->entry,self->_priv->changed_entry);
360                         gtk_entry_set_text(GTK_ENTRY(self->_priv->entry), "");
361                         g_signal_handler_unblock(self->_priv->entry,self->_priv->changed_entry);
362                         self_backend_locked(self,NULL, STUFFKEEPER_DATA_BACKEND(stuffkeeper_data_item_get_backend(self->_priv->item)));
363                         self_item_changed(self, self->_priv->field, self->_priv->item);
364                 }else if (!lock && self->_priv->unlocked){
365                         g_debug("Lock key\n");
366                         /* safe pending changes */
367                         if(self->_priv->changed_entry_timeout)
368                         {
369                                 g_source_remove(self->_priv->changed_entry_timeout);
370                                 self->_priv->changed_entry_timeout = 0;
372                                 self_save_changes(self);
373                         }
374                         self->_priv->unlocked = FALSE;
375                         /* clear */
377                         g_signal_handler_block(self->_priv->entry,self->_priv->changed_entry);
378                         gtk_entry_set_text(GTK_ENTRY(self->_priv->entry), "**********");
379                         g_signal_handler_unblock(self->_priv->entry,self->_priv->changed_entry);
380                         self_backend_locked(self,NULL, STUFFKEEPER_DATA_BACKEND(stuffkeeper_data_item_get_backend(self->_priv->item)));
381                 }
382         }
384         private
385         gboolean
386         has_key(self)
387         {
388                 return ((self->_priv->keys[0] != 0) && self->_priv->unlocked);
389         }