? .EncryptionManager.cs.swp
? .Note.cs.swp
? EncryptionManager.cs
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/Makefile.am,v
retrieving revision 1.49
diff -u -8 -p -r1.49 Makefile.am
--- Makefile.am	22 Nov 2006 09:58:06 -0000	1.49
+++ Makefile.am	5 Dec 2006 00:16:35 -0000
@@ -40,16 +40,17 @@ CSFILES = 					\
 	$(srcdir)/Preferences.cs		\
 	$(srcdir)/RecentChanges.cs		\
 	$(srcdir)/Tray.cs 			\
 	$(srcdir)/Trie.cs			\
 	$(srcdir)/Undo.cs 			\
 	$(srcdir)/Utils.cs			\
 	$(srcdir)/Watchers.cs			\
 	$(srcdir)/XKeybinder.cs			\
+	$(srcdir)/EncryptionManager.cs	\
 	\
 	$(srcdir)/panelapplet/*.cs		\
 	\
 	$(DBUS_CSFILES)	
 
 
 ASSEMBLIES = 		\
 	$(TOMBOY_LIBS) 	\
Index: Note.cs
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/Note.cs,v
retrieving revision 1.37
diff -u -8 -p -r1.37 Note.cs
--- Note.cs	15 Nov 2006 19:41:30 -0000	1.37
+++ Note.cs	5 Dec 2006 00:16:36 -0000
@@ -5,35 +5,46 @@ using System.Diagnostics;
 using System.IO;
 using System.Xml;
 using Mono.Unix;
 
 namespace Tomboy
 {
 	public delegate void NoteRenameHandler (Note sender, string old_title);
 
+	public class DecryptionRequiredException: Exception
+	{
+	}
+
 	// Contains all pure note data, like the note title and note text.
 	public class NoteData
 	{
 		readonly string uri;
 		string title;
 		string text;
+		byte[] encrypted_text;
+		byte[] encryption_key;	// The hashed password used to encrypt this note
+		bool encrypted;			// Set true if the note is encrypted or to be encrypted
+		bool text_changed;		// Set true if the encrypted text needs to be re-encrypted
 		DateTime create_date;
 		DateTime change_date;
 
 		int cursor_pos;
 		int width, height;
 		int x, y;
 
 		const int noPosition = -1;
 
 		public NoteData (string uri)
 		{
 			this.uri = uri;
 			this.text = "";
+			encrypted_text = null;
+			encrypted = false;
+			text_changed = false;
 			x = noPosition;
 			y = noPosition;
 		}
 
 		public string Uri
 		{
 			get { return uri; }
 		}
@@ -41,18 +52,75 @@ namespace Tomboy
 		public string Title
 		{
 			get { return title; }
 			set { title = value; }
 		}
 
 		public string Text
 		{
-			get { return text; }
-			set { text = value; }
+			get 
+			{ 
+				// May throw DecryptionRequiredException
+				if (Locked)
+					text = EncryptionManager.Instance.HandleEncryptedNote (this);
+				return text;
+			}
+			set 
+			{ 
+				text = value; 
+				encrypted_text = null;
+				text_changed = true;
+			}
+		}
+
+		public byte[] EncryptedText
+		{
+			get 
+			{ 
+				if (!encrypted) return null;
+				if ((text_changed || encrypted_text == null) && encryption_key != null)
+				{
+					encrypted_text = EncryptionManager.Instance.Encrypt (text, encryption_key);
+					text_changed = false;
+				}
+
+				return encrypted_text; 
+			}
+
+			set 
+			{ 
+				encrypted_text = value; 
+				text = "";
+				encrypted = true;
+			}
+		}
+
+		public byte[] EncryptionKey
+		{
+			get { return encryption_key; }
+			set { encryption_key = value; }
+		}
+
+		public bool Encrypted
+		{
+			get { return encrypted; }
+			set 
+			{ 
+				if (value == true && encryption_key == null && encrypted_text == null)
+					throw new ArgumentException ("EncryptionKey or EncryptedText must be specified before Encrypted is set to true");
+				if (value == false && Locked)
+					throw new ArgumentException ("Note must be decrypted before Encrypted is set to false");
+				encrypted = value;
+			}
+		}
+
+		public bool Locked
+		{
+			get { return text == "" && encrypted_text != null; }
 		}
 
 		public DateTime CreateDate
 		{
 			get { return create_date; }
 			set { create_date = value; }
 		}
 
@@ -681,16 +749,21 @@ namespace Tomboy
 					case "title":
 						note.Title = xml.ReadString ();
 						break;
 					case "text":
 						// <text> is just a wrapper around <note-content>
 						// NOTE: Use .text here to avoid triggering a save.
 						note.Text = xml.ReadInnerXml ();
 						break;
+					case "encrypted-text":
+						if (xml.GetAttribute ("type") != "AES-128")
+							throw new Exception("unknown encryption text algorithm");
+						note.EncryptedText = Convert.FromBase64String (xml.ReadString ());
+						break;
 					case "last-change-date":
 						note.ChangeDate = 
 							XmlConvert.ToDateTime (xml.ReadString ());
 						break;
 					case "create-date":
 						note.CreateDate = 
 							XmlConvert.ToDateTime (xml.ReadString ());
 						break;
@@ -788,21 +861,31 @@ namespace Tomboy
 						 "size", 
 						 null, 
 						 "http://beatniksoftware.com/tomboy/size");
 
 			xml.WriteStartElement (null, "title", null);
 			xml.WriteString (note.Title);
 			xml.WriteEndElement ();
 
-			xml.WriteStartElement (null, "text", null);
-			xml.WriteAttributeString ("xml", "space", null, "preserve");
-			// Insert <note-content> blob...
-			xml.WriteRaw (note.Text);
-			xml.WriteEndElement ();
+			if (note.Encrypted)
+			{
+				xml.WriteStartElement (null, "encrypted-text", null);
+				xml.WriteAttributeString (null, "type", null, "AES-128");
+				xml.WriteBase64 (note.EncryptedText, 0, note.EncryptedText.Length);
+				xml.WriteEndElement ();
+			}
+			else
+			{
+				xml.WriteStartElement (null, "text", null);
+				xml.WriteAttributeString ("xml", "space", null, "preserve");
+				// Insert <note-content> blob...
+				xml.WriteRaw (note.Text);
+				xml.WriteEndElement ();
+			}
 
 			xml.WriteStartElement (null, "last-change-date", null);
 			xml.WriteString (XmlConvert.ToString (note.ChangeDate));
 			xml.WriteEndElement ();
 
 			if (note.CreateDate != DateTime.MinValue) {
 				xml.WriteStartElement (null, "create-date", null);
 				xml.WriteString (XmlConvert.ToString (note.CreateDate));
Index: NoteWindow.cs
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/NoteWindow.cs,v
retrieving revision 1.54
diff -u -8 -p -r1.54 NoteWindow.cs
--- NoteWindow.cs	22 Nov 2006 09:58:06 -0000	1.54
+++ NoteWindow.cs	5 Dec 2006 00:16:36 -0000
@@ -464,17 +464,17 @@ namespace Tomboy
 
 			args.Menu.Append (close_all);
 			args.Menu.Append (close_window);
 		}
 
 		//
 		// Toolbar
 		//
-		// Add Link button, Font menu, Delete button to the window's
+		// Add Link button, Font menu, Encrypt and Delete buttons to the window's
 		// toolbar.
 		//
 
 		Gtk.Toolbar MakeToolbar ()
 		{
 			Gtk.Toolbar toolbar = new Gtk.Toolbar ();
 			toolbar.Tooltips = true;
 
@@ -523,30 +523,42 @@ namespace Tomboy
 						    Gtk.Stock.Execute,
 						    Catalog.GetString ("T_ools"),
 						    plugin_menu);
 			plugin_button.Show ();
 			toolbar.AppendWidget (plugin_button, 
 					      Catalog.GetString ("Use tools on this note"), 
 					      null);
 
+			Gtk.ToggleButton encrypt = (Gtk.ToggleButton)
+				toolbar.AppendElement (
+					Gtk.ToolbarChildType.Togglebutton,
+					null,
+					Catalog.GetString ("Encrypt"),
+					Catalog.GetString ("Encrypt this note"),
+					null,
+					new Gtk.Image (Gtk.Stock.Convert, toolbar.IconSize), // TODO : change
+					null);
+			encrypt.Toggled += EncryptButtonToggled;
+			encrypt.Active = note.Data.Encrypted;
+
 			toolbar.AppendSpace ();
 
 		        Gtk.Widget delete = 
 				toolbar.AppendItem (
 					Catalog.GetString ("Delete"), 
 					Catalog.GetString ("Delete this note"), 
 					null, 
 					new Gtk.Image (Gtk.Stock.Delete, toolbar.IconSize),
 					new Gtk.SignalFunc (DeleteButtonClicked));
 
 			// Don't allow deleting the "Start Here" note...
 			if (note.IsSpecial)
 				delete.Sensitive = false;
-
+			
 			return toolbar;
 		}
 
 		//
 		// Plugin toolbar menu
 		//
 		// Prefixed with Open Plugins Folder action, the rest being
 		// populated by individual plugins using
@@ -730,16 +742,32 @@ namespace Tomboy
 				search.SearchText = note.Buffer.Selection;
 			}
 			search.Present ();
 		}
 
 		void SearchActivate (object sender, EventArgs args)
 		{
 			SearchButtonClicked ();
+		}
+
+		void EncryptButtonToggled (object sender, EventArgs args)
+		{
+			Gtk.ToggleButton encrypt = (Gtk.ToggleButton)sender;
+			if (note.Data.EncryptionKey == null && encrypt.Active)
+			{
+				note.Data.EncryptionKey = EncryptionManager.Instance.GetEncryptionKey (this);
+				if (note.Data.EncryptionKey == null) 
+				{
+					encrypt.Active = false;
+					return;
+				}
+			}
+			note.Data.Encrypted = encrypt.Active;
+			note.QueueSave (false);
 		}
 	}
 	
 	public class NoteFindBar : Gtk.HBox
 	{
 		private Note note;
 
 		Gtk.Entry entry;

