8 #include "stuffkeeper-data-item.h"
12 #include "stuffkeeper-data-backend.h"
17 PRIVATE_FIELD_GPGKEY = 0
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;
40 private gulong signal_backend_locked = {0};
42 /* Encryption stuff */
43 private gpgme_ctx_t ctx = NULL;
44 private gpgme_key_t keys[2];
46 private gboolean unlocked = FALSE;
53 if(self_has_key(self))
55 const gchar *text = gtk_entry_get_text(GTK_ENTRY(self->_priv->entry));
56 if(self->_priv->field)
58 gpgme_data_t dh_plain = 0, dh_cipher = 0;
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,
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);
80 self_set_lock(self, FALSE);
83 gpgme_data_release(dh_plain);
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;
96 changed(self, gpointer data)
98 if(self->_priv->changed_entry_timeout)
100 g_source_remove(self->_priv->changed_entry_timeout);
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));
110 item_changed(self,const gchar *field, StuffkeeperDataItem *item)
112 const gchar *text = gtk_entry_get_text(GTK_ENTRY(self->_priv->entry));
114 if(self->_priv->field && field && self_has_key(self))
116 if(strcmp(field, self->_priv->field) == 0)
118 value = stuffkeeper_data_item_get_string(item, self->_priv->field);
119 if(value && strcmp(text,value))
121 g_signal_handler_block(self->_priv->entry,self->_priv->changed_entry);
122 gpgme_data_t dh_plain = 0, dh_cipher = 0;
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);
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);
138 g_debug("Error decrypting: %s. Locking entry\n", gpgme_strerror(err));
139 self_set_lock(self, FALSE);
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);
151 style_set(self, GtkStyle *prev, GtkWidget *wid)
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]);
160 backend_locked(self, GParamSpec *arg1, StuffkeeperDataBackend *backend)
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);
166 gtk_editable_set_editable(GTK_EDITABLE(self->_priv->entry), FALSE);
169 custom_field_changed(self, const gchar *id, int field, StuffkeeperDataSchema *schema)
171 if(field == PRIVATE_FIELD_GPGKEY)
175 /* safe pending changes */
176 if(self->_priv->changed_entry_timeout)
178 g_source_remove(self->_priv->changed_entry_timeout);
179 self->_priv->changed_entry_timeout = 0;
181 self_save_changes(self);
183 self->_priv->unlocked = FALSE;
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);
190 if(self->_priv->keys[0])
192 gpgme_key_unref(self->_priv->keys[0]);
193 self->_priv->keys[0]= 0;
195 value = stuffkeeper_data_schema_get_custom_field_string(schema, self->_priv->field,field);
198 err = gpgme_get_key(self->_priv->ctx, value, &(self->_priv->keys[0]), 1);
200 g_debug("getting key: %s\n", gpgme_strerror(err));
201 gtk_widget_set_sensitive(self->_priv->button,FALSE);
203 gtk_widget_set_sensitive(self->_priv->button,TRUE);
208 self_backend_locked(self,NULL, STUFFKEEPER_DATA_BACKEND(stuffkeeper_data_item_get_backend(self->_priv->item)));
214 new(StuffkeeperDataItem *item, const gchar *field (check null))
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);
243 obj->_priv->item = item;
245 obj->_priv->field = g_strdup(field);
247 /* Setup the encryption stuff */
248 obj->_priv->keys[0] = 0;
249 obj->_priv->keys[1] = 0;
250 err = gpgme_new(&(obj->_priv->ctx));
252 g_debug("Failed to create gpgme context: %i:%s\n",
254 gpgme_strerror(err));
256 gpgme_set_armor((obj->_priv->ctx), 1);
258 value = stuffkeeper_data_schema_get_custom_field_string(stuffkeeper_data_item_get_schema(item), obj->_priv->field,PRIVATE_FIELD_GPGKEY);
261 err = gpgme_get_key(obj->_priv->ctx, value, &(obj->_priv->keys[0]), 1);
265 g_debug("getting key: %s\n", gpgme_strerror(err));
266 gtk_widget_set_sensitive(obj->_priv->button,FALSE);
271 obj->_priv->changed_item_entry = g_signal_connect_swapped(G_OBJECT(item), "item-changed", G_CALLBACK(self_item_changed), obj);
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))
286 gtk_editable_set_editable(GTK_EDITABLE(obj->_priv->entry), FALSE);
288 self_item_changed(obj, obj->_priv->field, obj->_priv->item);
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);
299 dispose (G:Object *obj)
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;
306 if(self->_priv->changed_item_entry)
308 g_signal_handler_disconnect(self->_priv->item,self->_priv->changed_item_entry);
309 self->_priv->changed_item_entry = 0;
311 if(self->_priv->changed_entry_timeout)
313 g_source_remove(self->_priv->changed_entry_timeout);
314 self->_priv->changed_entry_timeout = 0;
316 self_save_changes(self);
318 if(self->_priv->custom_field_changed)
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;
326 /* clear encryption context */
329 gpgme_release(self->_priv->ctx);
330 self->_priv->ctx = NULL;
333 if(self->_priv->keys[0])
335 gpgme_key_unref(self->_priv->keys[0]);
336 self->_priv->keys[0]= 0;
343 unlock_clicked(self, GtkWidget *button)
345 g_debug("%s activate\n", __FUNCTION__);
346 self_set_lock(self, !self->_priv->unlocked);
350 set_lock(self, gboolean lock)
352 g_debug("Unlock/Lock key\n");
353 if(self->_priv->keys[0]== 0) return;
355 if(lock && !self->_priv->unlocked)
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)
369 g_source_remove(self->_priv->changed_entry_timeout);
370 self->_priv->changed_entry_timeout = 0;
372 self_save_changes(self);
374 self->_priv->unlocked = FALSE;
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)));
388 return ((self->_priv->keys[0] != 0) && self->_priv->unlocked);