[tomboy/mac-0.15.7] [WebSync] Bundle MonoHttp (for HttpListener) on Windows



commit 921e95411cfe5a890a9a2a81d941b1e0f481ad01
Author: Sandy Armstrong <sanfordarmstrong gmail com>
Date:   Tue Sep 8 10:49:48 2009 -0700

    [WebSync] Bundle MonoHttp (for HttpListener) on Windows
    
    This works around the problem that .NET's HttpListener
    only works if you have admin privileges.

 .../MonoHttp/AuthenticationSchemeSelector.cs       |   37 +
 .../MonoHttp/AuthenticationSchemes.cs              |   51 ++
 .../Addins/WebSyncService/MonoHttp/ChunkStream.cs  |  333 ++++++++++
 .../WebSyncService/MonoHttp/ChunkedInputStream.cs  |  178 +++++
 .../WebSyncService/MonoHttp/EndPointListener.cs    |  326 +++++++++
 .../WebSyncService/MonoHttp/EndPointManager.cs     |  147 ++++
 .../WebSyncService/MonoHttp/HttpConnection.cs      |  353 ++++++++++
 .../Addins/WebSyncService/MonoHttp/HttpListener.cs |  319 +++++++++
 .../MonoHttp/HttpListenerBasicIdentity.cs          |   47 ++
 .../WebSyncService/MonoHttp/HttpListenerContext.cs |  139 ++++
 .../MonoHttp/HttpListenerException.cs              |   59 ++
 .../MonoHttp/HttpListenerPrefixCollection.cs       |  130 ++++
 .../WebSyncService/MonoHttp/HttpListenerRequest.cs |  450 +++++++++++++
 .../MonoHttp/HttpListenerResponse.cs               |  512 ++++++++++++++
 .../WebSyncService/MonoHttp/HttpRequestHeader.cs   |   77 +++
 .../WebSyncService/MonoHttp/HttpResponseHeader.cs  |   66 ++
 .../MonoHttp/HttpStreamAsyncResult.cs              |   97 +++
 .../Addins/WebSyncService/MonoHttp/HttpUtility.cs  |  105 +++
 .../WebSyncService/MonoHttp/ListenerAsyncResult.cs |  135 ++++
 .../WebSyncService/MonoHttp/ListenerPrefix.cs      |  163 +++++
 .../WebSyncService/MonoHttp/RequestStream.cs       |  226 +++++++
 .../WebSyncService/MonoHttp/ResponseStream.cs      |  243 +++++++
 Tomboy/Addins/WebSyncService/MonoHttp/Utility.cs   |   98 +++
 .../WebSyncService/MonoHttp/WebHeaderCollection.cs |  699 ++++++++++++++++++++
 .../WebSyncService/WebSyncPreferencesWidget.cs     |    5 +-
 Tomboy/Addins/WebSyncService/WebSyncService.csproj |   24 +
 26 files changed, 5016 insertions(+), 3 deletions(-)
---
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/AuthenticationSchemeSelector.cs b/Tomboy/Addins/WebSyncService/MonoHttp/AuthenticationSchemeSelector.cs
new file mode 100644
index 0000000..b16e11a
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/AuthenticationSchemeSelector.cs
@@ -0,0 +1,37 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.AuthenticationSchemeSelector.cs
+//
+// Author:
+//	Gonzalo Paniagua Javier  <gonzalo novell com>
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if !NET_2_0
+
+using System; using System.Net; namespace MonoHttp {
+	internal delegate AuthenticationSchemes AuthenticationSchemeSelector (HttpListenerRequest httpRequest);
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/AuthenticationSchemes.cs b/Tomboy/Addins/WebSyncService/MonoHttp/AuthenticationSchemes.cs
new file mode 100644
index 0000000..cce5fa9
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/AuthenticationSchemes.cs
@@ -0,0 +1,51 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.AuthenticationSchemes.cs
+//
+// Author:
+//	Atsushi Enomoto  <atsushi ximian com>
+//
+// (C) 2005 Novell, Inc. (http://www.novell.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if !NET_2_0
+
+using System.Collections;
+using System.Configuration;
+
+using System; using System.Net; namespace MonoHttp
+{
+	[Flags]
+	internal enum AuthenticationSchemes {
+		None,
+		Digest = 1,
+		Negotiate = 2,
+		Ntlm = 4,
+		IntegratedWindowsAuthentication = 6,
+		Basic = 8,
+		Anonymous = 0x8000,
+	}
+}
+
+#endif
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/ChunkStream.cs b/Tomboy/Addins/WebSyncService/MonoHttp/ChunkStream.cs
new file mode 100644
index 0000000..c2314f9
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/ChunkStream.cs
@@ -0,0 +1,333 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.ChunkStream
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// (C) 2003 Ximian, Inc (http://www.ximian.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using System; using System.Net; namespace MonoHttp
+{
+	class ChunkStream
+	{
+		enum State {
+			None,
+			Body,
+			BodyFinished,
+			Trailer
+		}
+
+		class Chunk {
+			public byte [] Bytes;
+			public int Offset;
+
+			public Chunk (byte [] chunk)
+			{
+				this.Bytes = chunk;
+			}
+
+			public int Read (byte [] buffer, int offset, int size)
+			{
+				int nread = (size > Bytes.Length - Offset) ? Bytes.Length - Offset : size;
+				Buffer.BlockCopy (Bytes, Offset, buffer, offset, nread);
+				Offset += nread;
+				return nread;
+			}
+		}
+
+		internal WebHeaderCollection headers;
+		int chunkSize;
+		int chunkRead;
+		State state;
+		//byte [] waitBuffer;
+		StringBuilder saved;
+		bool sawCR;
+		bool gotit;
+		int trailerState;
+		ArrayList chunks;
+		
+		public ChunkStream (byte [] buffer, int offset, int size, WebHeaderCollection headers)
+					: this (headers)
+		{
+			Write (buffer, offset, size);
+		}
+
+		public ChunkStream (WebHeaderCollection headers)
+		{
+			this.headers = headers;
+			saved = new StringBuilder ();
+			chunks = new ArrayList ();
+			chunkSize = -1;
+		}
+
+		public void ResetBuffer ()
+		{
+			chunkSize = -1;
+			chunkRead = 0;
+			chunks.Clear ();
+		}
+		
+		public void WriteAndReadBack (byte [] buffer, int offset, int size, ref int read)
+		{
+			if (offset + read > 0)
+				Write (buffer, offset, offset+read);
+			read = Read (buffer, offset, size);
+		}
+
+		public int Read (byte [] buffer, int offset, int size)
+		{
+			return ReadFromChunks (buffer, offset, size);
+		}
+
+		int ReadFromChunks (byte [] buffer, int offset, int size)
+		{
+			int count = chunks.Count;
+			int nread = 0;
+			for (int i = 0; i < count; i++) {
+				Chunk chunk = (Chunk) chunks [i];
+				if (chunk == null)
+					continue;
+
+				if (chunk.Offset == chunk.Bytes.Length) {
+					chunks [i] = null;
+					continue;
+				}
+				
+				nread += chunk.Read (buffer, offset + nread, size - nread);
+				if (nread == size)
+					break;
+			}
+
+			return nread;
+		}
+		
+		public void Write (byte [] buffer, int offset, int size)
+		{
+			InternalWrite (buffer, ref offset, size);
+		}
+		
+		void InternalWrite (byte [] buffer, ref int offset, int size)
+		{
+			if (state == State.None) {
+				state = GetChunkSize (buffer, ref offset, size);
+				if (state == State.None)
+					return;
+				
+				saved.Length = 0;
+				sawCR = false;
+				gotit = false;
+			}
+			
+			if (state == State.Body && offset < size) {
+				state = ReadBody (buffer, ref offset, size);
+				if (state == State.Body)
+					return;
+			}
+			
+			if (state == State.BodyFinished && offset < size) {
+				state = ReadCRLF (buffer, ref offset, size);
+				if (state == State.BodyFinished)
+					return;
+
+				sawCR = false;
+			}
+			
+			if (state == State.Trailer && offset < size) {
+				state = ReadTrailer (buffer, ref offset, size);
+				if (state == State.Trailer)
+					return;
+
+				saved.Length = 0;
+				sawCR = false;
+				gotit = false;
+			}
+
+			if (offset < size)
+				InternalWrite (buffer, ref offset, size);
+		}
+
+		public bool WantMore {
+			get { return (chunkRead != chunkSize || chunkSize != 0 || state != State.None); }
+		}
+
+		public int ChunkLeft {
+			get { return chunkSize - chunkRead; }
+		}
+		
+		State ReadBody (byte [] buffer, ref int offset, int size)
+		{
+			if (chunkSize == 0)
+				return State.BodyFinished;
+
+			int diff = size - offset;
+			if (diff + chunkRead > chunkSize)
+				diff = chunkSize - chunkRead;
+
+			byte [] chunk = new byte [diff];
+			Buffer.BlockCopy (buffer, offset, chunk, 0, diff);
+			chunks.Add (new Chunk (chunk));
+			offset += diff;
+			chunkRead += diff;
+			return (chunkRead == chunkSize) ? State.BodyFinished : State.Body;
+				
+		}
+		
+		State GetChunkSize (byte [] buffer, ref int offset, int size)
+		{
+			char c = '\0';
+			while (offset < size) {
+				c = (char) buffer [offset++];
+				if (c == '\r') {
+					if (sawCR)
+						ThrowProtocolViolation ("2 CR found");
+
+					sawCR = true;
+					continue;
+				}
+				
+				if (sawCR && c == '\n')
+					break;
+
+				if (c == ' ')
+					gotit = true;
+
+				if (!gotit)
+					saved.Append (c);
+
+				if (saved.Length > 20)
+					ThrowProtocolViolation ("chunk size too long.");
+			}
+
+			if (!sawCR || c != '\n') {
+				if (offset < size)
+					ThrowProtocolViolation ("Missing \\n");
+
+				try {
+					if (saved.Length > 0)
+						chunkSize = Int32.Parse (saved.ToString (), NumberStyles.HexNumber);
+				} catch (Exception) {
+					ThrowProtocolViolation ("Cannot parse chunk size.");
+				}
+
+				return State.None;
+			}
+
+			chunkRead = 0;
+			try {
+				chunkSize = Int32.Parse (saved.ToString (), NumberStyles.HexNumber);
+			} catch (Exception) {
+				ThrowProtocolViolation ("Cannot parse chunk size.");
+			}
+			
+			if (chunkSize == 0) {
+				trailerState = 2;
+				return State.Trailer;
+			}
+
+			return State.Body;
+		}
+
+		State ReadCRLF (byte [] buffer, ref int offset, int size)
+		{
+			if (!sawCR) {
+				if ((char) buffer [offset++] != '\r')
+					ThrowProtocolViolation ("Expecting \\r");
+
+				sawCR = true;
+				if (offset == size)
+					return State.BodyFinished;
+			}
+			
+			if (sawCR && (char) buffer [offset++] != '\n')
+				ThrowProtocolViolation ("Expecting \\n");
+
+			return State.None;
+		}
+
+		State ReadTrailer (byte [] buffer, ref int offset, int size)
+		{
+			char c = '\0';
+
+			// short path
+			if (trailerState == 2 && (char) buffer [offset] == '\r' && saved.Length == 0) {
+				offset++;
+				if (offset < size && (char) buffer [offset] == '\n') {
+					offset++;
+					return State.None;
+				}
+				offset--;
+			}
+			
+			int st = trailerState;
+			string stString = "\r\n\r";
+			while (offset < size && st < 4) {
+				c = (char) buffer [offset++];
+				if ((st == 0 || st == 2) && c == '\r') {
+					st++;
+					continue;
+				}
+
+				if ((st == 1 || st == 3) && c == '\n') {
+					st++;
+					continue;
+				}
+
+				if (st > 0) {
+					saved.Append (stString.Substring (0, saved.Length == 0? st-2: st));
+					st = 0;
+				}
+			}
+
+			if (st < 4) {
+				trailerState = st;
+				if (offset <  size)
+					ThrowProtocolViolation ("Error reading trailer.");
+
+				return State.Trailer;
+			}
+
+			StringReader reader = new StringReader (saved.ToString ());
+			string line;
+			while ((line = reader.ReadLine ()) != null && line != "")
+				headers.Add (line);
+
+			return State.None;
+		}
+
+		static void ThrowProtocolViolation (string message)
+		{
+			WebException we = new WebException (message, null, WebExceptionStatus.ServerProtocolViolation, null);
+			throw we;
+		}
+	}
+}
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/ChunkedInputStream.cs b/Tomboy/Addins/WebSyncService/MonoHttp/ChunkedInputStream.cs
new file mode 100644
index 0000000..2d004a4
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/ChunkedInputStream.cs
@@ -0,0 +1,178 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.ChunkedInputStream
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#if EMBEDDED_IN_1_0
+
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System; using System.Net; namespace MonoHttp {
+	class ChunkedInputStream : RequestStream {
+		bool disposed;
+		ChunkStream decoder;
+		HttpListenerContext context;
+		bool no_more_data;
+
+		class ReadBufferState {
+			public byte [] Buffer;
+			public int Offset;
+			public int Count;
+			public int InitialCount;
+			public HttpStreamAsyncResult Ares;
+			public ReadBufferState (byte [] buffer, int offset, int count,
+						HttpStreamAsyncResult ares)
+			{
+				Buffer = buffer;
+				Offset = offset;
+				Count = count;
+				InitialCount = count;
+				Ares = ares;
+			}
+		}
+
+		public ChunkedInputStream (HttpListenerContext context, Stream stream,
+						byte [] buffer, int offset, int length)
+					: base (stream, buffer, offset, length)
+		{
+			this.context = context;
+			WebHeaderCollection coll = (WebHeaderCollection) context.Request.Headers;
+			decoder = new ChunkStream (coll);
+		}
+
+		public ChunkStream Decoder {
+			get { return decoder; }
+			set { decoder = value; }
+		}
+
+		public override int Read ([In,Out] byte [] buffer, int offset, int count)
+		{
+			IAsyncResult ares = BeginRead (buffer, offset, count, null, null);
+			return EndRead (ares);
+		}
+
+		public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
+							AsyncCallback cback, object state)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType ().ToString ());
+
+			if (buffer == null)
+				throw new ArgumentNullException ("buffer");
+
+			int len = buffer.Length;
+			if (offset < 0 || offset > len)
+				throw new ArgumentOutOfRangeException ("offset exceeds the size of buffer");
+
+			if (count < 0 || offset > len - count)
+				throw new ArgumentOutOfRangeException ("offset+size exceeds the size of buffer");
+
+			HttpStreamAsyncResult ares = new HttpStreamAsyncResult ();
+			ares.Callback = cback;
+			ares.State = state;
+			if (no_more_data) {
+				ares.Complete ();
+				return ares;
+			}
+			int nread = decoder.Read (buffer, offset, count);
+			offset += nread;
+			count -= nread;
+			if (count == 0) {
+				// got all we wanted, no need to bother the decoder yet
+				ares.Count = nread;
+				ares.Complete ();
+				return ares;
+			}
+			if (!decoder.WantMore) {
+				no_more_data = nread == 0;
+				ares.Count = nread;
+				ares.Complete ();
+				return ares;
+			}
+			ares.Buffer = new byte [8192];
+			ares.Offset = 0;
+			ares.Count = 8192;
+			ReadBufferState rb = new ReadBufferState (buffer, offset, count, ares);
+			rb.InitialCount += nread;
+			base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
+			return ares;
+		}
+
+		void OnRead (IAsyncResult base_ares)
+		{
+			ReadBufferState rb = (ReadBufferState) base_ares.AsyncState;
+			HttpStreamAsyncResult ares = rb.Ares;
+			try {
+				int nread = base.EndRead (base_ares);
+				decoder.Write (ares.Buffer, ares.Offset, nread);
+				nread = decoder.Read (rb.Buffer, rb.Offset, rb.Count);
+				rb.Offset += nread;
+				rb.Count -= nread;
+				if (rb.Count == 0 || !decoder.WantMore || nread == 0) {
+					no_more_data = !decoder.WantMore && nread == 0;
+					ares.Count = rb.InitialCount - rb.Count;
+					ares.Complete ();
+					return;
+				}
+				ares.Offset = 0;
+				ares.Count = Math.Min (8192, decoder.ChunkLeft + 6);
+				base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
+			} catch (Exception e) {
+				context.Connection.SendError (e.Message, 400);
+				ares.Complete (e);
+			}
+		}
+
+		public override int EndRead (IAsyncResult ares)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType ().ToString ());
+
+			HttpStreamAsyncResult my_ares = ares as HttpStreamAsyncResult;
+			if (ares == null)
+				throw new ArgumentException ("Invalid IAsyncResult", "ares");
+
+			if (!ares.IsCompleted)
+				ares.AsyncWaitHandle.WaitOne ();
+
+			if (my_ares.Error != null)
+				throw new HttpListenerException (400, "I/O operation aborted.");
+
+			return my_ares.Count;
+		}
+
+		public override void Close ()
+		{
+			if (!disposed) {
+				disposed = true;
+				base.Close ();
+			}
+		}
+	}
+}
+#endif
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/EndPointListener.cs b/Tomboy/Addins/WebSyncService/MonoHttp/EndPointListener.cs
new file mode 100644
index 0000000..1fc1edd
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/EndPointListener.cs
@@ -0,0 +1,326 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.EndPointListener
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if !NET_2_0
+
+using System.IO;
+using System.Net.Sockets;
+using System.Collections;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+//using Mono.Security.Authenticode;
+
+using System; using System.Net; namespace MonoHttp {
+	
+	sealed class EndPointListener : IHttpListenerContextBinder
+	{
+		IPEndPoint endpoint;
+		Socket sock;
+		Hashtable prefixes;  // Dictionary <ListenerPrefix, HttpListener>
+		ArrayList unhandled; // List<ListenerPrefix> unhandled; host = '*'
+		ArrayList all;       // List<ListenerPrefix> all;  host = '+'
+		
+		AsymmetricAlgorithm key;
+		bool secure;
+
+		public EndPointListener (IPAddress addr, int port, bool secure)
+		{
+#if !EMBEDDED_IN_1_0
+			if (secure) {
+				this.secure = secure;
+				LoadCertificateAndKey (addr, port);
+			}
+#endif
+
+			endpoint = new IPEndPoint (addr, port);
+			sock = new Socket (addr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+			sock.Bind (endpoint);
+			sock.Listen (500);
+			sock.BeginAccept (OnAccept, this);
+			prefixes = new Hashtable ();
+		}
+#if !EMBEDDED_IN_1_0
+		void LoadCertificateAndKey (IPAddress addr, int port)
+		{
+			// Actually load the certificate
+			try {
+				string dirname = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+				string path = Path.Combine (dirname, ".mono");
+				path = Path.Combine (path, "httplistener");
+				string cert_file = Path.Combine (path, String.Format ("{0}.cer", port));
+				string pvk_file = Path.Combine (path, String.Format ("{0}.pvk", port));
+				cert = new X509Certificate2 (cert_file);
+				key = PrivateKey.CreateFromFile (pvk_file).RSA;
+			} catch {
+				// ignore errors
+			}
+		}
+#endif
+		static void OnAccept (IAsyncResult ares)
+		{
+			EndPointListener epl = (EndPointListener) ares.AsyncState;
+			Socket accepted = null;
+			try {
+				accepted = epl.sock.EndAccept (ares);
+			} catch {
+				// Anything to do here?
+			} finally {
+				try {
+					epl.sock.BeginAccept (OnAccept, epl);
+				} catch {
+					if (accepted != null) {
+						try {
+							accepted.Close ();
+						} catch {}
+						accepted = null;
+					}
+				} 
+			}
+
+			if (accepted == null)
+				return;
+
+			if (epl.secure && (epl.key == null)) {
+				accepted.Close ();
+				return;
+			}
+			HttpConnection conn = new HttpConnection (accepted, epl);
+			conn.BeginReadRequest ();
+		}
+
+		public bool BindContext (HttpListenerContext context)
+		{
+			HttpListenerRequest req = context.Request;
+			ListenerPrefix prefix;
+			HttpListener listener = SearchListener (req.UserHostName, req.RawUrl, out prefix);
+			if (listener == null)
+				return false;
+
+			context.Listener = listener;
+			context.Connection.Prefix = prefix;
+			listener.RegisterContext (context);
+			return true;
+		}
+
+		public void UnbindContext (HttpListenerContext context)
+		{
+			if (context == null || context.Request == null)
+				return;
+
+			HttpListenerRequest req = context.Request;
+			ListenerPrefix prefix;
+			HttpListener listener = SearchListener (req.UserHostName, req.RawUrl, out prefix);
+			if (listener != null)
+				listener.UnregisterContext (context);
+		}
+
+		HttpListener SearchListener (string host, string raw_url, out ListenerPrefix prefix)
+		{
+			prefix = null;
+			if (raw_url == null)
+				return null;
+
+			//TODO: We should use a ReaderWriterLock between this and the add/remove operations.
+			if (host != null) {
+				int colon = host.IndexOf (':');
+				if (colon >= 0)
+					host = host.Substring (0, colon);
+			}
+
+			string path;
+			Uri raw_uri;
+			#if NET_2_0
+if (MonoHttp.Utility.MaybeUri (raw_url) && Uri.TryCreate (raw_url, UriKind.Absolute, out raw_uri))
+#else
+try { raw_uri = new Uri (raw_url); } catch { raw_uri = null; } if (raw_uri != null)
+#endif
+
+				path = raw_uri.PathAndQuery;
+			else
+				path = HttpUtility.UrlDecode (raw_url);
+			
+			string path_slash = path [path.Length - 1] == '/' ? path : path + "/";
+			
+			HttpListener best_match = null;
+			int best_length = -1;
+
+			lock (prefixes) {
+				if (host != null && host != "") {
+					foreach (ListenerPrefix p in prefixes.Keys) {
+						string ppath = p.Path;
+						if (ppath.Length < best_length)
+							continue;
+
+						if (p.Host == host && (path.StartsWith (ppath) || path_slash.StartsWith (ppath))) {
+							best_length = ppath.Length;
+							best_match = (HttpListener) prefixes [p];
+							prefix = p;
+						}
+					}
+					if (best_length != -1)
+						return best_match;
+				}
+
+				best_match = MatchFromList (host, path, unhandled, out prefix);
+				if (best_match != null)
+					return best_match;
+
+				best_match = MatchFromList (host, path, all, out prefix);
+				if (best_match != null)
+					return best_match;
+			}
+			return null;
+		}
+
+		HttpListener MatchFromList (string host, string path, ArrayList list, out ListenerPrefix prefix)
+		{
+			prefix = null;
+			if (list == null)
+				return null;
+
+			HttpListener best_match = null;
+			int best_length = -1;
+			
+			foreach (ListenerPrefix p in list) {
+				string ppath = p.Path;
+				if (ppath.Length < best_length)
+					continue;
+
+				if (path.StartsWith (ppath)) {
+					best_length = ppath.Length;
+					best_match = p.Listener;
+					prefix = p;
+				}
+			}
+
+			return best_match;
+		}
+
+		void AddSpecial (ArrayList coll, ListenerPrefix prefix)
+		{
+			if (coll == null)
+				return;
+
+			foreach (ListenerPrefix p in coll) {
+				if (p.Path == prefix.Path) //TODO: code
+					throw new HttpListenerException (400, "Prefix already in use.");
+			}
+
+			coll.Add (prefix);
+		}
+
+		void RemoveSpecial (ArrayList coll, ListenerPrefix prefix)
+		{
+			if (coll == null)
+				return;
+
+			int c = coll.Count;
+			for (int i = 0; i < c; i++) {
+				ListenerPrefix p = (ListenerPrefix) coll [i];
+				if (p.Path == prefix.Path) {
+					coll.RemoveAt (i);
+					CheckIfRemove ();
+					return;
+				}
+			}
+		}
+
+		void CheckIfRemove ()
+		{
+			if (prefixes.Count > 0)
+				return;
+
+			if (unhandled != null && unhandled.Count > 0)
+				return;
+
+			if (all != null && all.Count > 0)
+				return;
+
+			EndPointManager.RemoveEndPoint (this, endpoint);
+		}
+
+		public void Close ()
+		{
+			sock.Close ();
+		}
+
+		public void AddPrefix (ListenerPrefix prefix, HttpListener listener)
+		{
+			lock (prefixes) {
+				if (prefix.Host == "*") {
+					if (unhandled == null)
+						unhandled = new ArrayList ();
+
+					prefix.Listener = listener;
+					AddSpecial (unhandled, prefix);
+					return;
+				}
+
+				if (prefix.Host == "+") {
+					if (all == null)
+						all = new ArrayList ();
+					prefix.Listener = listener;
+					AddSpecial (all, prefix);
+					return;
+				}
+
+				if (prefixes.ContainsKey (prefix)) {
+					HttpListener other = (HttpListener) prefixes [prefix];
+					if (other != listener) // TODO: code.
+						throw new HttpListenerException (400, "There's another listener for " + prefix);
+					return;
+				}
+
+				prefixes [prefix] = listener;
+			}
+		}
+
+		public void RemovePrefix (ListenerPrefix prefix, HttpListener listener)
+		{
+			lock (prefixes) {
+				if (prefix.Host == "*") {
+					RemoveSpecial (unhandled, prefix);
+					return;
+				}
+
+				if (prefix.Host == "+") {
+					RemoveSpecial (all, prefix);
+					return;
+				}
+
+				if (prefixes.ContainsKey (prefix)) {
+					prefixes.Remove (prefix);
+				}
+			}
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/EndPointManager.cs b/Tomboy/Addins/WebSyncService/MonoHttp/EndPointManager.cs
new file mode 100644
index 0000000..7ca0117
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/EndPointManager.cs
@@ -0,0 +1,147 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.EndPointManager
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if !NET_2_0
+
+using System.Collections;
+using System.Collections.Generic;
+using System; using System.Net; namespace MonoHttp {
+	sealed class EndPointManager
+	{
+		// Dictionary<IPAddress, Dictionary<int, EndPointListener>>
+		static Hashtable ip_to_endpoints = new Hashtable ();
+		
+		private EndPointManager ()
+		{
+		}
+
+		public static void AddListener (HttpListener listener)
+		{
+			ArrayList added = new ArrayList ();
+			try {
+				lock (ip_to_endpoints) {
+					foreach (string prefix in listener.Prefixes) {
+						AddPrefixInternal (prefix, listener);
+						added.Add (prefix);
+					}
+				}
+			} catch {
+				foreach (string prefix in added) {
+					RemovePrefixInternal (prefix, listener);
+				}
+				throw;
+			}
+		}
+
+		public static void AddPrefix (string prefix, HttpListener listener)
+		{
+			lock (ip_to_endpoints) {
+				AddPrefixInternal (prefix, listener);
+			}
+		}
+
+		static void AddPrefixInternal (string p, HttpListener listener)
+		{
+			ListenerPrefix lp = new ListenerPrefix (p);
+			if (lp.Path.IndexOf ('%') != -1)
+				throw new HttpListenerException (400, "Invalid path.");
+
+			if (lp.Path.IndexOf ("//") != -1) // TODO: Code?
+				throw new HttpListenerException (400, "Invalid path.");
+
+			// Always listens on all the interfaces, no matter the host name/ip used.
+			EndPointListener epl = GetEPListener (IPAddress.Any, lp.Port, listener, lp.Secure);
+			epl.AddPrefix (lp, listener);
+		}
+
+		static EndPointListener GetEPListener (IPAddress addr, int port, HttpListener listener, bool secure)
+		{
+			Hashtable p = null;  // Dictionary<int, EndPointListener>
+			if (ip_to_endpoints.ContainsKey (addr)) {
+				p = (Hashtable) ip_to_endpoints [addr];
+			} else {
+				p = new Hashtable ();
+				ip_to_endpoints [addr] = p;
+			}
+
+			EndPointListener epl = null;
+			if (p.ContainsKey (port)) {
+				epl = (EndPointListener) p [port];
+			} else {
+				epl = new EndPointListener (addr, port, secure);
+				p [port] = epl;
+			}
+
+			return epl;
+		}
+
+		public static void RemoveEndPoint (EndPointListener epl, IPEndPoint ep)
+		{
+			lock (ip_to_endpoints) {
+				// Dictionary<int, EndPointListener> p
+				Hashtable p = null;
+				p = (Hashtable) ip_to_endpoints [ep.Address];
+				p.Remove (ep.Port);
+				epl.Close ();
+			}
+		}
+
+		public static void RemoveListener (HttpListener listener)
+		{
+			lock (ip_to_endpoints) {
+				foreach (string prefix in listener.Prefixes) {
+					RemovePrefixInternal (prefix, listener);
+				}
+			}
+		}
+
+		public static void RemovePrefix (string prefix, HttpListener listener)
+		{
+			lock (ip_to_endpoints) {
+				RemovePrefixInternal (prefix, listener);
+			}
+		}
+
+		static void RemovePrefixInternal (string prefix, HttpListener listener)
+		{
+			ListenerPrefix lp = new ListenerPrefix (prefix);
+			if (lp.Path.IndexOf ('%') != -1)
+				return;
+
+			if (lp.Path.IndexOf ("//") != -1)
+				return;
+
+			EndPointListener epl = GetEPListener (IPAddress.Any, lp.Port, listener, lp.Secure);
+			epl.RemovePrefix (lp, listener);
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpConnection.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpConnection.cs
new file mode 100644
index 0000000..cd0121c
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpConnection.cs
@@ -0,0 +1,353 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpConnection
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System.IO;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Text;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+
+#if !EMBEDDED_IN_1_0
+using Mono.Security.Protocol.Tls;
+#endif
+
+using System; using System.Net; namespace MonoHttp {
+	
+	interface IHttpListenerContextBinder {
+		bool BindContext (HttpListenerContext context);
+		void UnbindContext (HttpListenerContext context);
+	}
+	
+	sealed class HttpConnection
+	{
+		const int BufferSize = 8192;
+		Socket sock;
+		Stream stream;
+		IHttpListenerContextBinder epl;
+		MemoryStream ms;
+		byte [] buffer;
+		HttpListenerContext context;
+		StringBuilder current_line;
+		ListenerPrefix prefix;
+		RequestStream i_stream;
+		ResponseStream o_stream;
+		bool chunked;
+		int chunked_uses;
+		bool context_bound;
+
+#if EMBEDDED_IN_1_0
+		public HttpConnection (Socket sock, IHttpListenerContextBinder epl)
+		{
+			this.sock = sock;
+			this.epl = epl;
+			stream = new NetworkStream (sock, false);
+			Init ();
+		}
+#else
+		public HttpConnection (Socket sock, IHttpListenerContextBinder epl, bool secure, X509Certificate2 cert, AsymmetricAlgorithm key)
+		{
+			this.sock = sock;
+			this.epl = epl;
+			this.secure = secure;
+			this.key = key;
+			if (secure == false) {
+				stream = new NetworkStream (sock, false);
+			} else {
+				SslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, false);
+				ssl_stream.PrivateKeyCertSelectionDelegate += OnPVKSelection;
+				stream = ssl_stream;
+
+			}
+			Init ();
+		}
+#endif
+
+		void Init ()
+		{
+			context_bound = false;
+			i_stream = null;
+			o_stream = null;
+			prefix = null;
+			chunked = false;
+			ms = new MemoryStream ();
+			position = 0;
+			input_state = InputState.RequestLine;
+			line_state = LineState.None;
+			context = new HttpListenerContext (this);
+		}
+
+		public int ChunkedUses {
+			get { return chunked_uses; }
+		}
+
+		public IPEndPoint LocalEndPoint {
+			get { return (IPEndPoint) sock.LocalEndPoint; }
+		}
+
+		public IPEndPoint RemoteEndPoint {
+			get { return (IPEndPoint) sock.RemoteEndPoint; }
+		}
+
+		public bool IsSecure {
+			get { return false; }
+		}
+
+		public ListenerPrefix Prefix {
+			get { return prefix; }
+			set { prefix = value; }
+		}
+
+		public void BeginReadRequest ()
+		{
+			if (buffer == null)
+				buffer = new byte [BufferSize];
+			try {
+				stream.BeginRead (buffer, 0, BufferSize, OnRead, this);
+			} catch {
+				sock.Close (); // stream disposed
+			}
+		}
+
+		public RequestStream GetRequestStream (bool chunked, long contentlength)
+		{
+			if (i_stream == null) {
+				byte [] buffer = ms.GetBuffer ();
+				int length = (int) ms.Length;
+				ms = null;
+				if (chunked) {
+					this.chunked = true;
+					context.Response.SendChunked = true;
+					i_stream = new ChunkedInputStream (context, stream, buffer, position, length - position);
+				} else {
+					i_stream = new RequestStream (stream, buffer, position, length - position, contentlength);
+				}
+			}
+			return i_stream;
+		}
+
+		public ResponseStream GetResponseStream ()
+		{
+			// TODO: can we get this stream before reading the input?
+			if (o_stream == null) {
+				bool ign = false;// ? true : listener.IgnoreWriteExceptions;
+				o_stream = new ResponseStream (stream, context.Response, ign);
+			}
+			return o_stream;
+		}
+
+		void OnRead (IAsyncResult ares)
+		{
+			// TODO: set a limit on ms length.
+			HttpConnection cnc = (HttpConnection) ares.AsyncState;
+			int nread = -1;
+			try {
+				nread = stream.EndRead (ares);
+				ms.Write (buffer, 0, nread);
+			} catch (Exception) {
+				//Console.WriteLine (e);
+				if (ms.Length > 0)
+					SendError ();
+				sock.Close ();
+				return;
+			}
+
+			if (nread == 0) {
+				//if (ms.Length > 0)
+				//	SendError (); // Why bother?
+				sock.Close ();
+				return;
+			}
+
+			if (ProcessInput (ms)) {
+				if (!context.HaveError)
+					context.Request.FinishInitialization ();
+
+				if (context.HaveError) {
+					SendError ();
+					Close ();
+					return;
+				}
+
+				if (!epl.BindContext (context)) {
+					SendError ("Invalid host", 400);
+					Close ();
+				}
+				context_bound = true;
+				return;
+			}
+			stream.BeginRead (buffer, 0, BufferSize, OnRead, cnc);
+		}
+
+		enum InputState {
+			RequestLine,
+			Headers
+		}
+
+		enum LineState {
+			None,
+			CR,
+			LF
+		}
+
+		InputState input_state = InputState.RequestLine;
+		LineState line_state = LineState.None;
+		int position;
+
+		// true -> done processing
+		// false -> need more input
+		bool ProcessInput (MemoryStream ms)
+		{
+			byte [] buffer = ms.GetBuffer ();
+			int len = (int) ms.Length;
+			int used = 0;
+			string line;
+			while ((line = ReadLine (buffer, position, len - position, ref used)) != null) {
+				position += used;
+				if (line == "") {
+					if (input_state == InputState.RequestLine)
+						continue;
+					current_line = null;
+					ms = null;
+					return true;
+				}
+
+				if (input_state == InputState.RequestLine) {
+					context.Request.SetRequestLine (line);
+					input_state = InputState.Headers;
+				} else {
+					context.Request.AddHeader (line);
+				}
+
+				if (context.HaveError)
+					return true;
+
+				if (position >= len)
+					break;
+			}
+
+			if (used == len) {
+				ms.SetLength (0);
+				position = 0;
+			}
+			return false;
+		}
+
+		string ReadLine (byte [] buffer, int offset, int len, ref int used)
+		{
+			if (current_line == null)
+				current_line = new StringBuilder ();
+			int last = offset + len;
+			used = 0;
+			for (int i = offset; i < last && line_state != LineState.LF; i++) {
+				used++;
+				byte b = buffer [i];
+				if (b == 13) {
+					line_state = LineState.CR;
+				} else if (b == 10) {
+					line_state = LineState.LF;
+				} else {
+					current_line.Append ((char) b);
+				}
+			}
+
+			string result = null;
+			if (line_state == LineState.LF) {
+				line_state = LineState.None;
+				result = current_line.ToString ();
+				current_line.Length = 0;
+			}
+
+			return result;
+		}
+
+		public void SendError (string msg, int status)
+		{
+			HttpListenerResponse response = context.Response;
+			response.StatusCode = status;
+			response.ContentType = "text/html";
+			string description = HttpListenerResponse.GetStatusDescription (status);
+			string str;
+			if (msg != null)
+				str = String.Format ("<h1>{0} ({1})</h1>", description, msg);
+			else
+				str = String.Format ("<h1>{0}</h1>", description);
+
+			byte [] error = context.Response.ContentEncoding.GetBytes (str);
+			response.Close (error, false);
+		}
+
+		public void SendError ()
+		{
+			SendError (context.ErrorMessage, context.ErrorStatus);
+		}
+
+		public void Close ()
+		{
+			if (sock != null) {
+				Stream st = GetResponseStream ();
+				st.Close ();
+				o_stream = null;
+			}
+
+			if (sock != null) {
+				if (chunked && context.Response.ForceCloseChunked == false) {
+					// Don't close. Keep working.
+					chunked_uses++;
+					Init ();
+					BeginReadRequest ();
+					return;
+				}
+
+				if (context.Response.Headers ["connection"] == "close") {
+					Socket s = sock;
+					sock = null;
+					try {
+						s.Shutdown (SocketShutdown.Both);
+					} catch {
+					} finally {
+						s.Close ();
+					}
+				} else {
+					Init ();
+					BeginReadRequest ();
+					return;
+				}
+
+				if (context_bound)
+					epl.UnbindContext (context);
+			}
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListener.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListener.cs
new file mode 100644
index 0000000..f1ff1b3
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListener.cs
@@ -0,0 +1,319 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListener
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if !NET_2_0
+
+using System.Collections;
+using System.Threading;
+//TODO: logging
+using System; using System.Net; namespace MonoHttp {
+	internal class HttpListener : IDisposable {
+		AuthenticationSchemes auth_schemes;
+		HttpListenerPrefixCollection prefixes;
+		AuthenticationSchemeSelector auth_selector; 
+		string realm;
+		bool ignore_write_exceptions;
+		bool unsafe_ntlm_auth;
+		bool listening;
+		bool disposed;
+
+		Hashtable registry;   // Dictionary<HttpListenerContext,HttpListenerContext> 
+		ArrayList ctx_queue;  // List<HttpListenerContext> ctx_queue;
+		ArrayList wait_queue; // List<ListenerAsyncResult> wait_queue;
+
+		public HttpListener ()
+		{
+			prefixes = new HttpListenerPrefixCollection (this);
+			registry = new Hashtable ();
+			ctx_queue = new ArrayList ();
+			wait_queue = new ArrayList ();
+			auth_schemes = AuthenticationSchemes.Anonymous;
+		}
+
+		// TODO: Digest, NTLM and Negotiate require ControlPrincipal
+		public AuthenticationSchemes AuthenticationSchemes {
+			get { return auth_schemes; }
+			set {
+				CheckDisposed ();
+				auth_schemes = value;
+			}
+		}
+
+		//TODO: when is this called?
+		public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate {
+			get { return auth_selector; }
+			set {
+				CheckDisposed ();
+				auth_selector = value;
+			}
+		}
+
+		public bool IgnoreWriteExceptions {
+			get { return ignore_write_exceptions; }
+			set {
+				CheckDisposed ();
+				ignore_write_exceptions = value;
+			}
+		}
+
+		public bool IsListening {
+			get { return listening; }
+		}
+
+		public static bool IsSupported {
+			get { return true; }
+		}
+
+		public HttpListenerPrefixCollection Prefixes {
+			get {
+				CheckDisposed ();
+				return prefixes;
+			}
+		}
+
+		// TODO: use this
+		public string Realm {
+			get { return realm; }
+			set {
+				CheckDisposed ();
+				realm = value;
+			}
+		}
+
+		//[MonoTODO ("Support for NTLM needs some loving.")]
+		public bool UnsafeConnectionNtlmAuthentication {
+			get { return unsafe_ntlm_auth; }
+			set {
+				CheckDisposed ();
+				unsafe_ntlm_auth = value;
+			}
+		}
+
+		public void Abort ()
+		{
+			if (disposed)
+				return;
+
+			if (!listening) {
+				return;
+			}
+
+			Close (true);
+		}
+
+		public void Close ()
+		{
+			if (disposed)
+				return;
+
+			if (!listening) {
+				disposed = true;
+				return;
+			}
+
+			Close (false);
+			disposed = true;
+		}
+
+		void Close (bool force)
+		{
+			CheckDisposed ();
+			EndPointManager.RemoveListener (this);
+			Cleanup (force);
+		}
+
+		void Cleanup (bool close_existing)
+		{
+			lock (registry) {
+				if (close_existing) {
+					foreach (HttpListenerContext context in registry.Keys) {
+						context.Connection.Close ();
+					}
+					registry.Clear (); // Just in case.
+				}
+
+				lock (ctx_queue) {
+					foreach (HttpListenerContext context in ctx_queue)
+						context.Connection.Close ();
+
+					ctx_queue.Clear ();
+				}
+
+				lock (wait_queue) {
+					foreach (ListenerAsyncResult ares in wait_queue) {
+						ares.Complete ("Listener was closed.");
+					}
+					wait_queue.Clear ();
+				}
+			}
+		}
+
+		public IAsyncResult BeginGetContext (AsyncCallback callback, Object state)
+		{
+			CheckDisposed ();
+			if (!listening)
+				throw new InvalidOperationException ("Please, call Start before using this method.");
+
+			ListenerAsyncResult ares = new ListenerAsyncResult (callback, state);
+
+			// lock wait_queue early to avoid race conditions
+			lock (wait_queue) {
+				lock (ctx_queue) {
+					HttpListenerContext ctx = GetContextFromQueue ();
+					if (ctx != null) {
+						ares.Complete (ctx, true);
+						return ares;
+					}
+				}
+
+				wait_queue.Add (ares);
+			}
+
+			return ares;
+		}
+
+		public HttpListenerContext EndGetContext (IAsyncResult asyncResult)
+		{
+			CheckDisposed ();
+			if (asyncResult == null)
+				throw new ArgumentNullException ("asyncResult");
+
+			ListenerAsyncResult ares = asyncResult as ListenerAsyncResult;
+			if (ares == null)
+				throw new ArgumentException ("Wrong IAsyncResult.", "asyncResult");
+
+			if (!ares.IsCompleted)
+				ares.AsyncWaitHandle.WaitOne ();
+
+			lock (wait_queue) {
+				int idx = wait_queue.IndexOf (ares);
+				if (idx >= 0)
+					wait_queue.RemoveAt (idx);
+			}
+
+			HttpListenerContext context = ares.GetContext ();
+			if (auth_schemes != AuthenticationSchemes.Anonymous) {
+				context.ParseAuthentication ();
+			}
+			return context; // This will throw on error.
+		}
+
+		public HttpListenerContext GetContext ()
+		{
+			// The prefixes are not checked when using the async interface!?
+			if (prefixes.Count == 0)
+				throw new InvalidOperationException ("Please, call AddPrefix before using this method.");
+
+			IAsyncResult ares = BeginGetContext (null, null);
+			return EndGetContext (ares);
+		}
+
+		public void Start ()
+		{
+			CheckDisposed ();
+			if (listening)
+				return;
+
+			EndPointManager.AddListener (this);
+			listening = true;
+		}
+
+		public void Stop ()
+		{
+			CheckDisposed ();
+			listening = false;
+			Close (false);
+		}
+
+		void IDisposable.Dispose ()
+		{
+			if (disposed)
+				return;
+
+			Close (true); //TODO: Should we force here or not?
+			disposed = true;
+		}
+
+		internal void CheckDisposed ()
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType ().ToString ());
+		}
+
+		// Must be called with a lock on ctx_queue
+		HttpListenerContext GetContextFromQueue ()
+		{
+			if (ctx_queue.Count == 0)
+				return null;
+
+			HttpListenerContext context = (HttpListenerContext) ctx_queue [0];
+			ctx_queue.RemoveAt (0);
+			return context;
+		}
+
+		internal void RegisterContext (HttpListenerContext context)
+		{
+			try {
+				Monitor.Enter (registry);
+				registry [context] = context;
+				Monitor.Enter (wait_queue);
+				Monitor.Enter (ctx_queue);
+				if (wait_queue.Count == 0) {
+					ctx_queue.Add (context);
+				} else {
+					ListenerAsyncResult ares = (ListenerAsyncResult) wait_queue [0];
+					wait_queue.RemoveAt (0);
+					ares.Complete (context);
+				}
+			} finally {
+				Monitor.Exit (ctx_queue);
+				Monitor.Exit (wait_queue);
+				Monitor.Exit (registry);
+			}
+		}
+
+		internal void UnregisterContext (HttpListenerContext context)
+		{
+			try {
+				Monitor.Enter (registry);
+				Monitor.Enter (ctx_queue);
+				int idx = ctx_queue.IndexOf (context);
+				if (idx >= 0)
+					ctx_queue.RemoveAt (idx);
+				registry.Remove (context);
+			} finally {
+				Monitor.Exit (ctx_queue);
+				Monitor.Exit (registry);
+			}
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerBasicIdentity.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerBasicIdentity.cs
new file mode 100644
index 0000000..e785bac
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerBasicIdentity.cs
@@ -0,0 +1,47 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListenerBasicIdentity
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if !NET_2_0
+using System.Security.Principal;
+using System; using System.Net; namespace MonoHttp {
+	internal class HttpListenerBasicIdentity : GenericIdentity {
+		string password;
+
+		public HttpListenerBasicIdentity (string username, string password) : base (username, "Basic")
+		{
+			this.password = password;
+		}
+
+		public virtual string Password {
+			get { return password; }
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerContext.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerContext.cs
new file mode 100644
index 0000000..b002a6a
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerContext.cs
@@ -0,0 +1,139 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListenerContext
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System.Collections.Specialized;
+using System.IO;
+using System.Security.Principal;
+using System.Text;
+using System; using System.Net; namespace MonoHttp {
+	internal class HttpListenerContext {
+		HttpListenerRequest request;
+		HttpListenerResponse response;
+		IPrincipal user;
+		HttpConnection cnc;
+		string error;
+		int err_status = 400;
+		internal HttpListener Listener;
+
+		internal HttpListenerContext (HttpConnection cnc)
+		{
+			this.cnc = cnc;
+			request = new HttpListenerRequest (this);
+			response = new HttpListenerResponse (this);
+		}
+
+		internal int ErrorStatus {
+			get { return err_status; }
+			set { err_status = value; }
+		}
+
+		internal string ErrorMessage {
+			get { return error; }
+			set { error = value; }
+		}
+
+		internal bool HaveError {
+			get { return (error != null); }
+		}
+
+		internal HttpConnection Connection {
+			get { return cnc; }
+		}
+
+		public HttpListenerRequest Request {
+			get { return request; }
+		}
+
+		public HttpListenerResponse Response {
+			get { return response; }
+		}
+
+		public IPrincipal User {
+			get { return user; }
+		}
+
+		internal void ParseAuthentication () {
+			// TODO: Handle NTLM/Digest modes
+			string header = request.Headers ["Authorization"];
+
+			if (header == null || header.Length < 2)
+				return;
+
+			string [] authenticationData = header.Substring (header.IndexOf (':') + 1).Split (new char [] {' '});
+
+			if (string.Compare (authenticationData [0], "basic", true) == 0) {
+				user = ParseBasicAuthentication (authenticationData [1]);
+			}
+		}
+	
+		internal IPrincipal ParseBasicAuthentication (string authData) {
+			try {
+				// Basic AUTH Data is a formatted Base64 String
+				//string domain = null;
+				string user = null;
+				string password = null;
+				int pos = -1;
+				string authString = System.Text.Encoding.Default.GetString (Convert.FromBase64String (authData));
+	
+				// The format is DOMAIN\username:password
+				// Domain is optional
+
+				pos = authString.IndexOf (':');
+	
+				// parse the password off the end
+				password = authString.Substring (pos+1);
+				
+				// discard the password
+				authString = authString.Substring (0, pos);
+	
+				// check if there is a domain
+				pos = authString.IndexOf ('\\');
+	
+				if (pos > 0) {
+					//domain = authString.Substring (0, pos);
+					user = authString.Substring (pos);
+				} else {
+					user = authString;
+				}
+	
+				HttpListenerBasicIdentity identity = new HttpListenerBasicIdentity (user, password);
+				// TODO: What are the roles MS sets
+				return new GenericPrincipal (identity, new string [0]);
+			} catch (Exception) {
+				// Invalid auth data is swallowed silently
+				return null;
+			} 
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerException.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerException.cs
new file mode 100644
index 0000000..036058e
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerException.cs
@@ -0,0 +1,59 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListenerException
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if !NET_2_0
+using System.ComponentModel;
+using System.Runtime.Serialization;
+using System; using System.Net; namespace MonoHttp {
+	[Serializable]
+	internal class HttpListenerException : Win32Exception
+	{
+		public HttpListenerException ()
+		{
+		}
+
+		public HttpListenerException (int errorCode) : base (errorCode)
+		{
+		}
+
+		public HttpListenerException (int errorCode, string message) : base (errorCode, message)
+		{
+		}
+
+		protected HttpListenerException (SerializationInfo serializationInfo, StreamingContext streamingContext) : base (serializationInfo, streamingContext)
+		{
+		}
+
+		public override int ErrorCode {
+			get { return base.ErrorCode; }
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerPrefixCollection.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerPrefixCollection.cs
new file mode 100644
index 0000000..bbcc25b
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerPrefixCollection.cs
@@ -0,0 +1,130 @@
+//#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListenerPrefixCollection.cs
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if !NET_2_0
+
+using System.Collections;
+using System.Collections.Generic;
+using System; using System.Net; namespace MonoHttp {
+#if EMBEDDED_IN_1_0
+	internal class HttpListenerPrefixCollection : IEnumerable, ICollection {
+		ArrayList prefixes;
+		
+#else
+	internal class HttpListenerPrefixCollection : ICollection<string>, IEnumerable<string>, IEnumerable {
+		List<string> prefixes = new List<string> ();
+#endif
+		HttpListener listener;
+
+		internal HttpListenerPrefixCollection (HttpListener listener)
+		{
+			this.listener = listener;
+		}
+
+		public int Count {
+			get { return prefixes.Count; }
+		}
+
+		public bool IsReadOnly {
+			get { return false; }
+		}
+
+		public bool IsSynchronized {
+			get { return false; }
+		}
+
+		public void Add (string uriPrefix)
+		{
+			listener.CheckDisposed ();
+			ListenerPrefix.CheckUri (uriPrefix);
+			if (prefixes.Contains (uriPrefix))
+				return;
+
+			prefixes.Add (uriPrefix);
+			if (listener.IsListening)
+				EndPointManager.AddPrefix (uriPrefix, listener);
+		}
+
+		public void Clear ()
+		{
+			listener.CheckDisposed ();
+			if (listener.IsListening)
+				EndPointManager.RemoveListener (listener);
+			prefixes.Clear ();
+		}
+
+		public bool Contains (string uriPrefix)
+		{
+			listener.CheckDisposed ();
+			return prefixes.Contains (uriPrefix);
+		}
+
+		public void CopyTo (string [] array, int offset)
+		{
+			listener.CheckDisposed ();
+			prefixes.CopyTo (array, offset);
+		}
+
+		public void CopyTo (Array array, int offset)
+		{
+			listener.CheckDisposed ();
+			((ICollection) prefixes).CopyTo (array, offset);
+		}
+
+#if !EMBEDDED_IN_1_0
+		public IEnumerator<string> GetEnumerator ()
+		{
+			return prefixes.GetEnumerator ();
+		}
+#else
+		object ICollection.SyncRoot { get { return this; } }
+#endif
+
+	
+		IEnumerator IEnumerable.GetEnumerator ()
+		{
+			return prefixes.GetEnumerator ();
+		}
+
+		public bool Remove (string uriPrefix)
+		{
+			listener.CheckDisposed ();
+			if (uriPrefix == null)
+				throw new ArgumentNullException ("uriPrefix");
+
+			bool result = prefixes.Contains (uriPrefix); if (result) prefixes.Remove (uriPrefix);;
+			if (result && listener.IsListening)
+				EndPointManager.RemovePrefix (uriPrefix, listener);
+
+			return result;
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerRequest.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerRequest.cs
new file mode 100644
index 0000000..143c392
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerRequest.cs
@@ -0,0 +1,450 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListenerRequest
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System.Collections;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System; using System.Net; namespace MonoHttp {
+	internal class HttpListenerRequest
+	{
+		string [] accept_types;
+//		int client_cert_error;
+//		bool no_get_certificate;
+		Encoding content_encoding;
+		long content_length;
+		bool cl_set;
+		CookieCollection cookies;
+		WebHeaderCollection headers;
+		string method;
+		Stream input_stream;
+		Version version;
+		NameValueCollection query_string; // check if null is ok, check if read-only, check case-sensitiveness
+		string raw_url;
+		Guid identifier;
+		Uri url;
+		Uri referrer;
+		string [] user_languages;
+		HttpListenerContext context;
+		bool is_chunked;
+		static byte [] _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
+		static readonly string [] no_body_methods = new string [] {
+			"GET", "HEAD", "DELETE" };
+
+		internal HttpListenerRequest (HttpListenerContext context)
+		{
+			this.context = context;
+			headers = new WebHeaderCollection ();
+			input_stream = Stream.Null;
+			version = HttpVersion.Version10;
+		}
+
+		static char [] separators = new char [] { ' ' };
+
+		internal void SetRequestLine (string req)
+		{
+			string [] parts = req.Split (separators, 3);
+			if (parts.Length != 3) {
+				context.ErrorMessage = "Invalid request line (parts).";
+				return;
+			}
+
+			method = parts [0];
+			foreach (char c in method){
+				int ic = (int) c;
+
+				if ((ic >= 'A' && ic <= 'Z') ||
+				    (ic > 32 && c < 127 && c != '(' && c != ')' && c != '<' &&
+				     c != '<' && c != '>' && c != '@' && c != ',' && c != ';' &&
+				     c != ':' && c != '\\' && c != '"' && c != '/' && c != '[' &&
+				     c != ']' && c != '?' && c != '=' && c != '{' && c != '}'))
+					continue;
+
+				context.ErrorMessage = "(Invalid verb)";
+				return;
+			}
+
+			raw_url = parts [1];
+			if (parts [2].Length != 8 || !parts [2].StartsWith ("HTTP/")) {
+				context.ErrorMessage = "Invalid request line (version).";
+				return;
+			}
+
+			try {
+				version = new Version (parts [2].Substring (5));
+				if (version.Major < 1)
+					throw new Exception ();
+			} catch {
+				context.ErrorMessage = "Invalid request line (version).";
+				return;
+			}
+		}
+
+		void CreateQueryString (string query)
+		{
+			query_string = new NameValueCollection ();
+			if (query == null || query.Length == 0)
+				return;
+
+			if (query [0] == '?')
+				query = query.Substring (1);
+			string [] components = query.Split ('&');
+			foreach (string kv in components) {
+				int pos = kv.IndexOf ('=');
+				if (pos == -1) {
+					query_string.Add (null, HttpUtility.UrlDecode (kv));
+				} else {
+					string key = HttpUtility.UrlDecode (kv.Substring (0, pos));
+					string val = HttpUtility.UrlDecode (kv.Substring (pos + 1));
+					
+					query_string.Add (key, val);
+				}
+			}
+		}
+
+		internal void FinishInitialization ()
+		{
+			string host = UserHostName;
+			if (version > HttpVersion.Version10 && (host == null || host.Length == 0)) {
+				context.ErrorMessage = "Invalid host name";
+				return;
+			}
+
+			string path;
+			Uri raw_uri;
+			#if NET_2_0
+if (MonoHttp.Utility.MaybeUri (raw_url) && Uri.TryCreate (raw_url, UriKind.Absolute, out raw_uri))
+#else
+try { raw_uri = new Uri (raw_url); } catch { raw_uri = null; } if (url != raw_uri && (raw_uri.Host == null || raw_uri.Host.Length == 0)) raw_uri = null; if (raw_uri != null)
+#endif
+
+				path = raw_uri.PathAndQuery;
+			else
+				path = raw_url;
+
+			if ((host == null || host.Length == 0))
+				host = UserHostAddress;
+
+			if (raw_uri != null)
+				host = raw_uri.Host;
+	
+			int colon = host.IndexOf (':');
+			if (colon >= 0)
+				host = host.Substring (0, colon);
+
+			string base_uri = String.Format ("{0}://{1}:{2}",
+								(IsSecureConnection) ? "https" : "http",
+								host,
+								LocalEndPoint.Port);
+
+			#if NET_2_0
+if (!Uri.TryCreate (base_uri + path, UriKind.Absolute, out url)){
+#else
+try { url = new Uri (base_uri + path); } catch {}; if (url != null && (url.Host == null || url.Host.Length == 0)) url = null;  if (url == null) {
+#endif
+
+				context.ErrorMessage = "Invalid url: " + base_uri + path;
+				return;
+			}
+
+			CreateQueryString (url.Query);
+
+			string t_encoding = null;
+			if (version >= HttpVersion.Version11) {
+				t_encoding = Headers ["Transfer-Encoding"];
+				// 'identity' is not valid!
+				if (t_encoding != null && t_encoding != "chunked") {
+					context.Connection.SendError (null, 501);
+					return;
+				}
+			}
+
+			is_chunked = (t_encoding == "chunked");
+
+			foreach (string m in no_body_methods)
+				if (string.Compare (method, m, true, System.Globalization.CultureInfo.InvariantCulture) == 0)
+					return;
+
+			if (!is_chunked && !cl_set) {
+				context.Connection.SendError (null, 411);
+				return;
+			}
+
+			if (is_chunked || content_length > 0) {
+				input_stream = context.Connection.GetRequestStream (is_chunked, content_length);
+			}
+
+			if (Headers ["Expect"] == "100-continue") {
+				ResponseStream output = context.Connection.GetResponseStream ();
+				output.InternalWrite (_100continue, 0, _100continue.Length);
+			}
+		}
+
+		internal static string Unquote (String str) {
+			int start = str.IndexOf ('\"');
+			int end = str.LastIndexOf ('\"');
+			if (start >= 0 && end >=0)
+				str = str.Substring (start + 1, end - 1);
+			return str.Trim ();
+		}
+
+		internal void AddHeader (string header)
+		{
+			int colon = header.IndexOf (':');
+			if (colon == -1 || colon == 0) {
+				context.ErrorMessage = "Bad Request";
+				return;
+			}
+
+			string name = header.Substring (0, colon).Trim ();
+			string val = header.Substring (colon + 1).Trim ();
+			string lower = name.ToLower (CultureInfo.InvariantCulture);
+			headers.SetInternal (name, val);
+			switch (lower) {
+				case "accept-language":
+					user_languages = val.Split (','); // yes, only split with a ','
+					break;
+				case "accept":
+					accept_types = val.Split (','); // yes, only split with a ','
+					break;
+				case "content-length":
+					try {
+						//TODO: max. content_length?
+						content_length = Int64.Parse (val.Trim ());
+						if (content_length < 0)
+							context.ErrorMessage = "Invalid Content-Length.";
+						cl_set = true;
+					} catch {
+						context.ErrorMessage = "Invalid Content-Length.";
+					}
+
+					break;
+				case "referer":
+					try {
+						referrer = new Uri (val);
+					} catch {
+						referrer = new Uri ("http://someone.is.screwing.with.the.headers.com/";);
+					}
+					break;
+				case "cookie":
+					if (cookies == null)
+						cookies = new CookieCollection();
+
+					string[] cookieStrings = val.Split(new char[] {',', ';'});
+					Cookie current = null;
+					int version = 0;
+					foreach (string cookieString in cookieStrings) {
+						string str = cookieString.Trim ();
+						if (str.Length == 0)
+							continue;
+						if (str.StartsWith ("$Version")) {
+							version = Int32.Parse (Unquote (str.Substring (str.IndexOf ("=") + 1)));
+						} else if (str.StartsWith ("$Path")) {
+							if (current != null)
+								current.Path = str.Substring (str.IndexOf ("=") + 1).Trim ();
+						} else if (str.StartsWith ("$Domain")) {
+							if (current != null)
+								current.Domain = str.Substring (str.IndexOf ("=") + 1).Trim ();
+						} else if (str.StartsWith ("$Port")) {
+							if (current != null)
+								current.Port = str.Substring (str.IndexOf ("=") + 1).Trim ();
+						} else {
+							if (current != null) {
+								cookies.Add (current);
+							}
+							current = new Cookie ();
+							int idx = str.IndexOf ("=");
+							if (idx > 0) {
+								current.Name = str.Substring (0, idx).Trim ();
+								current.Value =  str.Substring (idx + 1).Trim ();
+							} else {
+								current.Name = str.Trim ();
+								current.Value = String.Empty;
+							}
+							current.Version = version;
+						}
+					}
+					if (current != null) {
+						cookies.Add (current);
+					}
+					break;
+			}
+		}
+
+		public string [] AcceptTypes {
+			get { return accept_types; }
+		}
+
+		//[MonoTODO ("Always returns 0")]
+		public int ClientCertificateError {
+			get {
+/*				
+				if (no_get_certificate)
+					throw new InvalidOperationException (
+						"Call GetClientCertificate() before calling this method.");
+				return client_cert_error;
+*/
+				return 0;
+			}
+		}
+
+		public Encoding ContentEncoding {
+			get {
+				if (content_encoding == null)
+					content_encoding = Encoding.Default;
+				return content_encoding;
+			}
+		}
+
+		public long ContentLength64 {
+			get { return content_length; }
+		}
+
+		public string ContentType {
+			get { return headers ["content-type"]; }
+		}
+
+		public CookieCollection Cookies {
+			get {
+				// TODO: check if the collection is read-only
+				if (cookies == null)
+					cookies = new CookieCollection ();
+				return cookies;
+			}
+		}
+
+		public bool HasEntityBody {
+			get { return (content_length > 0 || is_chunked); }
+		}
+
+		public NameValueCollection Headers {
+			get { return headers; }
+		}
+
+		public string HttpMethod {
+			get { return method; }
+		}
+
+		public Stream InputStream {
+			get { return input_stream; }
+		}
+
+		//[MonoTODO ("Always returns false")]
+		public bool IsAuthenticated {
+			get { return false; }
+		}
+
+		public bool IsLocal {
+			get { return IPAddress.IsLoopback (RemoteEndPoint.Address); }
+		}
+
+		public bool IsSecureConnection {
+			get { return context.Connection.IsSecure; } 
+		}
+
+		public bool KeepAlive {
+			get { return false; }
+		}
+
+		public IPEndPoint LocalEndPoint {
+			get { return context.Connection.LocalEndPoint; }
+		}
+
+		public Version ProtocolVersion {
+			get { return version; }
+		}
+
+		public NameValueCollection QueryString {
+			get { return query_string; }
+		}
+
+		public string RawUrl {
+			get { return raw_url; }
+		}
+
+		public IPEndPoint RemoteEndPoint {
+			get { return context.Connection.RemoteEndPoint; }
+		}
+
+		public Guid RequestTraceIdentifier {
+			get { return identifier; }
+		}
+
+		public Uri Url {
+			get { return url; }
+		}
+
+		public Uri UrlReferrer {
+			get { return referrer; }
+		}
+
+		public string UserAgent {
+			get { return headers ["user-agent"]; }
+		}
+
+		public string UserHostAddress {
+			get { return LocalEndPoint.ToString (); }
+		}
+
+		public string UserHostName {
+			get { return headers ["host"]; }
+		}
+
+		public string [] UserLanguages {
+			get { return user_languages; }
+		}
+
+		public IAsyncResult BeginGetClientCertificate (AsyncCallback requestCallback, Object state)
+		{
+			return null;
+		}
+#if SECURITY_DEP
+		public X509Certificate2 EndGetClientCertificate (IAsyncResult asyncResult)
+		{
+			return null;
+			// set no_client_certificate once done.
+		}
+
+		public X509Certificate2 GetClientCertificate ()
+		{
+			// set no_client_certificate once done.
+
+			// InvalidOp if call in progress.
+			return null;
+		}
+#endif
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerResponse.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerResponse.cs
new file mode 100644
index 0000000..dc3bdbc
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpListenerResponse.cs
@@ -0,0 +1,512 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpListenerResponse
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System; using System.Net; namespace MonoHttp {
+	internal class HttpListenerResponse : IDisposable
+	{
+		bool disposed;
+		Encoding content_encoding;
+		long content_length;
+		bool cl_set;
+		string content_type;
+		CookieCollection cookies;
+		WebHeaderCollection headers = new WebHeaderCollection ();
+		bool keep_alive = true;
+		ResponseStream output_stream;
+		Version version = HttpVersion.Version11;
+		string location;
+		int status_code = 200;
+		string status_description = "OK";
+		bool chunked;
+		HttpListenerContext context;
+		internal bool HeadersSent;
+		bool force_close_chunked;
+
+		internal HttpListenerResponse (HttpListenerContext context)
+		{
+			this.context = context;
+		}
+
+		internal bool ForceCloseChunked {
+			get { return force_close_chunked; }
+		}
+
+		public Encoding ContentEncoding {
+			get {
+				if (content_encoding == null)
+					content_encoding = Encoding.Default;
+				return content_encoding;
+			}
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				//TODO: is null ok?
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+					
+				content_encoding = value;
+			}
+		}
+
+		public long ContentLength64 {
+			get { return content_length; }
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+
+				if (value < 0)
+					throw new ArgumentOutOfRangeException ("Must be >= 0", "value");
+
+				cl_set = true;
+				content_length = value;
+			}
+		}
+		
+		public string ContentType {
+			get { return content_type; }
+			set {
+				// TODO: is null ok?
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+
+				content_type = value;
+			}
+		}
+
+		// RFC 2109, 2965 + the netscape specification at http://wp.netscape.com/newsref/std/cookie_spec.html
+		public CookieCollection Cookies {
+			get {
+				if (cookies == null)
+					cookies = new CookieCollection ();
+				return cookies;
+			}
+			set { cookies = value; } // null allowed?
+		}
+
+		public WebHeaderCollection Headers {
+			get { return headers; }
+			set {
+		/**
+		 *	"If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, or
+		 *	WWW-Authenticate header using the Headers property, an exception will be
+		 *	thrown. Use the KeepAlive or ContentLength64 properties to set these headers.
+		 *	You cannot set the Transfer-Encoding or WWW-Authenticate headers manually."
+		*/
+		// TODO: check if this is marked readonly after headers are sent.
+				headers = value;
+			}
+		}
+
+		public bool KeepAlive {
+			get { return keep_alive; }
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+					
+				keep_alive = value;
+			}
+		}
+
+		public Stream OutputStream {
+			get {
+				if (output_stream == null)
+					output_stream = context.Connection.GetResponseStream ();
+				return output_stream;
+			}
+		}
+		
+		public Version ProtocolVersion {
+			get { return version; }
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+					
+				if (value == null)
+					throw new ArgumentNullException ("value");
+
+				if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1))
+					throw new ArgumentException ("Must be 1.0 or 1.1", "value");
+
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				version = value;
+			}
+		}
+
+		public string RedirectLocation {
+			get { return location; }
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+					
+				location = value;
+			}
+		}
+
+		public bool SendChunked {
+			get { return chunked; }
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+					
+				chunked = value;
+			}
+		}
+
+		public int StatusCode {
+			get { return status_code; }
+			set {
+				if (disposed)
+					throw new ObjectDisposedException (GetType ().ToString ());
+
+				if (HeadersSent)
+					throw new InvalidOperationException ("Cannot be changed after headers are sent.");
+					
+				if (value < 100 || value > 999)
+					throw new ProtocolViolationException ("StatusCode must be between 100 and 999.");
+				status_code = value;
+				status_description = GetStatusDescription (value);
+			}
+		}
+
+		internal static string GetStatusDescription (int code)
+		{
+			switch (code){
+			case 100: return "Continue";
+			case 101: return "Switching Protocols";
+			case 102: return "Processing";
+			case 200: return "OK";
+			case 201: return "Created";
+			case 202: return "Accepted";
+			case 203: return "Non-Authoritative Information";
+			case 204: return "No Content";
+			case 205: return "Reset Content";
+			case 206: return "Partial Content";
+			case 207: return "Multi-Status";
+			case 300: return "Multiple Choices";
+			case 301: return "Moved Permanently";
+			case 302: return "Found";
+			case 303: return "See Other";
+			case 304: return "Not Modified";
+			case 305: return "Use Proxy";
+			case 307: return "Temporary Redirect";
+			case 400: return "Bad Request";
+			case 401: return "Unauthorized";
+			case 402: return "Payment Required";
+			case 403: return "Forbidden";
+			case 404: return "Not Found";
+			case 405: return "Method Not Allowed";
+			case 406: return "Not Acceptable";
+			case 407: return "Proxy Authentication Required";
+			case 408: return "Request Timeout";
+			case 409: return "Conflict";
+			case 410: return "Gone";
+			case 411: return "Length Required";
+			case 412: return "Precondition Failed";
+			case 413: return "Request Entity Too Large";
+			case 414: return "Request-Uri Too Long";
+			case 415: return "Unsupported Media Type";
+			case 416: return "Requested Range Not Satisfiable";
+			case 417: return "Expectation Failed";
+			case 422: return "Unprocessable Entity";
+			case 423: return "Locked";
+			case 424: return "Failed Dependency";
+			case 500: return "Internal Server Error";
+			case 501: return "Not Implemented";
+			case 502: return "Bad Gateway";
+			case 503: return "Service Unavailable";
+			case 504: return "Gateway Timeout";
+			case 505: return "Http Version Not Supported";
+			case 507: return "Insufficient Storage";
+			}
+			return "";
+		}
+
+		public string StatusDescription {
+			get { return status_description; }
+			set {
+				status_description = value;
+			}
+		}
+
+		void IDisposable.Dispose ()
+		{
+			Close (true); //TODO: Abort or Close?
+		}
+
+		public void Abort ()
+		{
+			if (disposed)
+				return;
+
+			Close (true);
+		}
+
+		public void AddHeader (string name, string value)
+		{
+			if (name == null)
+				throw new ArgumentNullException ("name");
+
+			if (name == "")
+				throw new ArgumentException ("'name' cannot be empty", "name");
+			
+			//TODO: check for forbidden headers and invalid characters
+			if (value.Length > 65535)
+				throw new ArgumentOutOfRangeException ("value");
+
+			headers.Set (name, value);
+		}
+
+		public void AppendCookie (Cookie cookie)
+		{
+			if (cookie == null)
+				throw new ArgumentNullException ("cookie");
+			
+			Cookies.Add (cookie);
+		}
+
+		public void AppendHeader (string name, string value)
+		{
+			if (name == null)
+				throw new ArgumentNullException ("name");
+
+			if (name == "")
+				throw new ArgumentException ("'name' cannot be empty", "name");
+			
+			if (value.Length > 65535)
+				throw new ArgumentOutOfRangeException ("value");
+
+			headers.Add (name, value);
+		}
+
+		void Close (bool force)
+		{
+			// TODO: use the 'force' argument
+			context.Connection.Close ();
+			disposed = true;
+		}
+
+		public void Close ()
+		{
+			if (disposed)
+				return;
+
+			Close (false);
+		}
+
+		public void Close (byte [] responseEntity, bool willBlock)
+		{
+			if (disposed)
+				return;
+
+			if (responseEntity == null)
+				throw new ArgumentNullException ("responseEntity");
+
+			//TODO: if willBlock -> BeginWrite + Close ?
+			ContentLength64 = responseEntity.Length;
+			OutputStream.Write (responseEntity, 0, (int) content_length);
+			Close (false);
+		}
+
+		public void CopyFrom (HttpListenerResponse templateResponse)
+		{
+			headers.Clear ();
+			headers.Add (templateResponse.headers);
+			content_length = templateResponse.content_length;
+			status_code = templateResponse.status_code;
+			status_description = templateResponse.status_description;
+			keep_alive = templateResponse.keep_alive;
+			version = templateResponse.version;
+		}
+
+		public void Redirect (string url)
+		{
+			StatusCode = 302; // Found
+			location = url;
+		}
+
+		bool FindCookie (Cookie cookie)
+		{
+			string name = cookie.Name;
+			string domain = cookie.Domain;
+			string path = cookie.Path;
+			foreach (Cookie c in cookies) {
+				if (name != c.Name)
+					continue;
+				if (domain != c.Domain)
+					continue;
+				if (path == c.Path)
+					return true;
+			}
+
+			return false;
+		}
+
+		internal void SendHeaders (bool closing, MemoryStream ms)
+		{
+			//TODO: When do we send KeepAlive?
+			Encoding encoding = content_encoding;
+			if (encoding == null)
+				encoding = Encoding.Default;
+
+			if (content_type != null) {
+				if (content_encoding != null && content_type.IndexOf ("charset=") == -1) {
+					string enc_name = content_encoding.WebName;
+					headers.SetInternal ("Content-Type", content_type + "; charset=" + enc_name);
+				} else {
+					headers.SetInternal ("Content-Type", content_type);
+				}
+			}
+
+			if (headers ["Server"] == null)
+				headers.SetInternal ("Server", "Mono-HTTPAPI/1.0");
+
+			CultureInfo inv = CultureInfo.InvariantCulture;
+			if (headers ["Date"] == null)
+				headers.SetInternal ("Date", DateTime.UtcNow.ToString ("r", inv));
+
+			if (!chunked) {
+				if (!cl_set && closing) {
+					cl_set = true;
+					content_length = 0;
+				}
+
+				if (cl_set)
+					headers.SetInternal ("Content-Length", content_length.ToString (inv));
+			}
+
+			Version v = context.Request.ProtocolVersion;
+			if (!cl_set && !chunked && v >= HttpVersion.Version11)
+				chunked = true;
+				
+			/* Apache forces closing the connection for these status codes:
+			 *	HttpStatusCode.BadRequest 		400
+			 *	HttpStatusCode.RequestTimeout 		408
+			 *	HttpStatusCode.LengthRequired 		411
+			 *	HttpStatusCode.RequestEntityTooLarge 	413
+			 *	HttpStatusCode.RequestUriTooLong 	414
+			 *	HttpStatusCode.InternalServerError 	500
+			 *	HttpStatusCode.ServiceUnavailable 	503
+			 */
+			bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 ||
+					status_code == 413 || status_code == 414 || status_code == 500 ||
+					status_code == 503);
+
+			if (conn_close == false) {
+				conn_close = (context.Request.Headers ["connection"] == "close");
+				conn_close |= (v <= HttpVersion.Version10);
+			}
+
+			// They sent both KeepAlive: true and Connection: close!?
+			if (!keep_alive || conn_close)
+				headers.SetInternal ("Connection", "close");
+
+			if (chunked)
+				headers.SetInternal ("Transfer-Encoding", "chunked");
+
+			int chunked_uses = context.Connection.ChunkedUses;
+			if (chunked_uses >= 100) {
+				force_close_chunked = true;
+				if (!conn_close)
+					headers.SetInternal ("Connection", "close");
+			}
+
+			if (location != null)
+				headers.SetInternal ("Location", location);
+
+			if (cookies != null) {
+				bool firstDone = false;
+				StringBuilder cookieSB = new StringBuilder ();
+				foreach (Cookie cookie in cookies) {
+					if (firstDone)
+						cookieSB.Append (",");
+					firstDone = true;
+					cookieSB.Append (MonoHttp.Utility.ToClientString (cookie));
+				}
+				headers.SetInternal("Set-Cookie2", cookieSB.ToString ());
+			}
+
+			StreamWriter writer = new StreamWriter (ms, encoding);
+			writer.Write ("HTTP/{0} {1} {2}\r\n", version, status_code, status_description);
+			string headers_str = headers.ToString ();
+			writer.Write (headers_str);
+			writer.Flush ();
+			int preamble = encoding.GetPreamble ().Length;
+			if (output_stream == null)
+				output_stream = context.Connection.GetResponseStream ();
+
+			/* Assumes that the ms was at position 0 */
+			ms.Position = preamble;
+			HeadersSent = true;
+		}
+
+		public void SetCookie (Cookie cookie)
+		{
+			if (cookie == null)
+				throw new ArgumentNullException ("cookie");
+
+			if (cookies != null) {
+				if (FindCookie (cookie))
+					throw new ArgumentException ("The cookie already exists.");
+			} else {
+				cookies = new CookieCollection ();
+			}
+
+			cookies.Add (cookie);
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpRequestHeader.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpRequestHeader.cs
new file mode 100644
index 0000000..66783bf
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpRequestHeader.cs
@@ -0,0 +1,77 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpRequestHeader
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if !NET_2_0
+using System; using System.Net; namespace MonoHttp {
+	internal enum HttpRequestHeader {
+		CacheControl,
+		Connection,
+		Date,
+		KeepAlive,
+		Pragma,
+		Trailer,
+		TransferEncoding,
+		Upgrade,
+		Via,
+		Warning,
+		Allow,
+		ContentLength,
+		ContentType,
+		ContentEncoding,
+		ContentLanguage,
+		ContentLocation,
+		ContentMd5,
+		ContentRange,
+		Expires,
+		LastModified,
+		Accept,
+		AcceptCharset,
+		AcceptEncoding,
+		AcceptLanguage,
+		Authorization,
+		Cookie,
+		Expect,
+		From,
+		Host,
+		IfMatch,
+		IfModifiedSince,
+		IfNoneMatch,
+		IfRange,
+		IfUnmodifiedSince,
+		MaxForwards,
+		ProxyAuthorization,
+		Referer,
+		Range,
+		Te,
+		Translate,
+		UserAgent
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpResponseHeader.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpResponseHeader.cs
new file mode 100644
index 0000000..6493ecc
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpResponseHeader.cs
@@ -0,0 +1,66 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpResponseHeader
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if !NET_2_0
+using System; using System.Net; namespace MonoHttp {
+	internal enum HttpResponseHeader {
+		CacheControl,
+		Connection,
+		Date,
+		KeepAlive,
+		Pragma,
+		Trailer,
+		TransferEncoding,
+		Upgrade,
+		Via,
+		Warning,
+		Allow,
+		ContentLength,
+		ContentType,
+		ContentEncoding,
+		ContentLanguage,
+		ContentLocation,
+		ContentMd5,
+		ContentRange,
+		Expires,
+		LastModified,
+		AcceptRanges,
+		Age,
+		ETag,
+		Location,
+		ProxyAuthenticate,
+		RetryAfter,
+		Server,
+		SetCookie,
+		Vary,
+		WwwAuthenticate
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpStreamAsyncResult.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpStreamAsyncResult.cs
new file mode 100644
index 0000000..41aa236
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpStreamAsyncResult.cs
@@ -0,0 +1,97 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpStreamAsyncResult
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if EMBEDDED_IN_1_0
+using System.Threading;
+
+using System; using System.Net; namespace MonoHttp {
+	class HttpStreamAsyncResult : IAsyncResult {
+		object locker = new object ();
+		ManualResetEvent handle;
+		bool completed;
+
+		internal byte [] Buffer;
+		internal int Offset;
+		internal int Count;
+		internal AsyncCallback Callback;
+		internal object State;
+		internal int SynchRead;
+		internal Exception Error;
+
+		public void Complete (Exception e)
+		{
+			Error = e;
+			Complete ();
+		}
+
+		public void Complete ()
+		{
+			lock (locker) {
+				if (completed)
+					return;
+
+				completed = true;
+				if (handle != null)
+					handle.Set ();
+
+				if (Callback != null)
+					Callback.BeginInvoke (this, null, null);
+			}
+		}
+		
+		public object AsyncState {
+			get { return State; }
+		}
+
+		public WaitHandle AsyncWaitHandle {
+			get {
+				lock (locker) {
+					if (handle == null)
+						handle = new ManualResetEvent (completed);
+				}
+				
+				return handle;
+			}
+		}
+
+		public bool CompletedSynchronously {
+			get { return (SynchRead == Count); }
+		}
+
+		public bool IsCompleted {
+			get {
+				lock (locker) {
+					return completed;
+				}
+			}
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/HttpUtility.cs b/Tomboy/Addins/WebSyncService/MonoHttp/HttpUtility.cs
new file mode 100644
index 0000000..3ee4747
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/HttpUtility.cs
@@ -0,0 +1,105 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.HttpUtility
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if EMBEDDED_IN_1_0
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System; using System.Net; namespace MonoHttp {
+	sealed class HttpUtility
+	{
+		private HttpUtility ()
+		{
+		}
+
+		public static string UrlDecode (string s)
+		{
+			return UrlDecode (s, null);
+		}
+
+		static char [] GetChars (MemoryStream b, Encoding e)
+		{
+			return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
+		}
+
+		public static string UrlDecode (string s, Encoding e)
+		{
+			if (null == s) 
+				return null;
+
+			if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
+				return s;
+
+			if (e == null)
+				e = Encoding.GetEncoding (28591);
+	
+			StringBuilder output = new StringBuilder ();
+			long len = s.Length;
+			NumberStyles hexa = NumberStyles.HexNumber;
+			MemoryStream bytes = new MemoryStream ();
+	
+			for (int i = 0; i < len; i++) {
+				if (s [i] == '%' && i + 2 < len) {
+					if (s [i + 1] == 'u' && i + 5 < len) {
+						if (bytes.Length > 0) {
+							output.Append (GetChars (bytes, e));
+							bytes.SetLength (0);
+						}
+						output.Append ((char) Int32.Parse (s.Substring (i + 2, 4), hexa));
+						i += 5;
+					} else {
+						bytes.WriteByte ((byte) Int32.Parse (s.Substring (i + 1, 2), hexa));
+						i += 2;
+					}
+					continue;
+				}
+
+				if (bytes.Length > 0) {
+					output.Append (GetChars (bytes, e));
+					bytes.SetLength (0);
+				}
+
+				if (s [i] == '+') {
+					output.Append (' ');
+				} else {
+					output.Append (s [i]);
+				}
+	         	}
+	
+			if (bytes.Length > 0) {
+				output.Append (GetChars (bytes, e));
+			}
+
+			bytes = null;
+			return output.ToString ();
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/ListenerAsyncResult.cs b/Tomboy/Addins/WebSyncService/MonoHttp/ListenerAsyncResult.cs
new file mode 100644
index 0000000..f4348d9
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/ListenerAsyncResult.cs
@@ -0,0 +1,135 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.ListenerAsyncResult
+//
+// Authors:
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//
+// Copyright (c) 2005 Ximian, Inc (http://www.ximian.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System.Threading;
+using System; using System.Net; namespace MonoHttp {
+	class ListenerAsyncResult : IAsyncResult {
+		ManualResetEvent handle;
+		bool synch;
+		bool completed;
+		AsyncCallback cb;
+		object state;
+		Exception exception;
+		HttpListenerContext context;
+		object locker = new object ();
+
+		public ListenerAsyncResult (AsyncCallback cb, object state)
+		{
+			this.cb = cb;
+			this.state = state;
+		}
+
+		internal void Complete (string error)
+		{
+			//FIXME: error_code?
+			exception = new HttpListenerException (0, error);
+			lock (locker) {
+				completed = true;
+				if (handle != null)
+					handle.Set ();
+
+				if (cb != null)
+					ThreadPool.QueueUserWorkItem (InvokeCallback, this);
+			}
+		}
+
+		static void InvokeCallback (object o)
+		{
+			ListenerAsyncResult ares = (ListenerAsyncResult) o;
+			ares.cb (ares);
+		}
+
+		internal void Complete (HttpListenerContext context)
+		{
+			Complete (context, false);
+		}
+
+		internal void Complete (HttpListenerContext context, bool synch)
+		{
+			this.synch = synch;
+			this.context = context;
+			lock (locker) {
+				completed = true;
+				if (handle != null)
+					handle.Set ();
+
+				if ((context.Listener.AuthenticationSchemes == AuthenticationSchemes.Basic || context.Listener.AuthenticationSchemes == AuthenticationSchemes.Negotiate) && context.Request.Headers ["Authorization"] == null) {
+					context.Listener.EndGetContext (this);
+					context.Response.StatusCode = 401;
+					context.Response.Headers ["WWW-Authenticate"] = AuthenticationSchemes.Basic + " realm=\"\"";
+					context.Response.OutputStream.Close ();
+					context.Listener.BeginGetContext (cb, state);
+				} else if (cb != null)
+					ThreadPool.QueueUserWorkItem (InvokeCallback, this);
+			}
+		}
+
+		internal HttpListenerContext GetContext ()
+		{
+			if (exception != null)
+				throw exception;
+
+			return context;
+		}
+		
+		public object AsyncState {
+			get { return state; }
+		}
+
+		public WaitHandle AsyncWaitHandle {
+			get {
+				lock (locker) {
+					if (handle == null)
+						handle = new ManualResetEvent (completed);
+				}
+				
+				return handle;
+			}
+		}
+
+		public bool CompletedSynchronously {
+			get { return synch; }
+		}
+
+		public bool IsCompleted {
+			get {
+				lock (locker) {
+					return completed;
+				}
+			}
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/ListenerPrefix.cs b/Tomboy/Addins/WebSyncService/MonoHttp/ListenerPrefix.cs
new file mode 100644
index 0000000..f857bab
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/ListenerPrefix.cs
@@ -0,0 +1,163 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.ListenerPrefix
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//	Oleg Mihailik (mihailik gmail co_m)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System; using System.Net; namespace MonoHttp {
+	sealed class ListenerPrefix
+	{
+		string original;
+		string host;
+		ushort port;
+		string path;
+		bool secure;
+		IPAddress [] addresses;
+		public HttpListener Listener;
+
+		public ListenerPrefix (string prefix)
+		{
+			this.original = prefix;
+			Parse (prefix);
+		}
+
+		public override string ToString ()
+		{
+			return original;
+		}
+
+		public IPAddress [] Addresses {
+			get { return addresses; }
+			set { addresses = value; }
+		}
+		public bool Secure {
+			get { return secure; }
+		}
+
+		public string Host {
+			get { return host; }
+		}
+
+		public int Port {
+			get { return (int) port; }
+		}
+
+		public string Path {
+			get { return path; }
+		}
+
+		// Equals and GetHashCode are required to detect duplicates in HttpListenerPrefixCollection.
+		public override bool Equals (object o)
+		{
+			ListenerPrefix other = o as ListenerPrefix;
+			if (other == null)
+				return false;
+
+			return (original == other.original);
+		}
+
+		public override int GetHashCode ()
+		{
+			return original.GetHashCode ();
+		}
+
+		void Parse (string uri)
+		{
+			int default_port = (uri.StartsWith ("http://";)) ? 80 : -1;
+			if (default_port == -1) {
+				default_port = (uri.StartsWith ("https://";)) ? 443 : -1;
+				secure = true;
+			}
+
+			int length = uri.Length;
+			int start_host = uri.IndexOf (':') + 3;
+			if (start_host >= length)
+				throw new ArgumentException ("No host specified.");
+
+			int colon = uri.IndexOf (':', start_host, length - start_host);
+			int root;
+			if (colon > 0) {
+				host = uri.Substring (start_host, colon - start_host);
+				root = uri.IndexOf ('/', colon, length - colon);
+				port = (ushort) Int32.Parse (uri.Substring (colon + 1, root - colon - 1));
+				path = uri.Substring (root);
+			} else {
+				root = uri.IndexOf ('/', start_host, length - start_host);
+				host = uri.Substring (start_host, root - start_host);
+				path = uri.Substring (root);
+			}
+		}
+
+		public static void CheckUri (string uri)
+		{
+			if (uri == null)
+				throw new ArgumentNullException ("uriPrefix");
+
+			int default_port = (uri.StartsWith ("http://";)) ? 80 : -1;
+			if (default_port == -1)
+				default_port = (uri.StartsWith ("https://";)) ? 443 : -1;
+			if (default_port == -1)
+				throw new ArgumentException ("Only 'http' and 'https' schemes are supported.");
+
+			int length = uri.Length;
+			int start_host = uri.IndexOf (':') + 3;
+			if (start_host >= length)
+				throw new ArgumentException ("No host specified.");
+
+			int colon = uri.IndexOf (':', start_host, length - start_host);
+			if (start_host == colon)
+				throw new ArgumentException ("No host specified.");
+
+			int root;
+			if (colon > 0) {
+				root = uri.IndexOf ('/', colon, length - colon);
+				if (root == -1)
+					throw new ArgumentException ("No path specified.");
+
+				try {
+					int p = Int32.Parse (uri.Substring (colon + 1, root - colon - 1));
+					if (p <= 0 || p >= 65536)
+						throw new Exception ();
+				} catch {
+					throw new ArgumentException ("Invalid port.");
+				}
+			} else {
+				root = uri.IndexOf ('/', start_host, length - start_host);
+				if (root == -1)
+					throw new ArgumentException ("No path specified.");
+			}
+
+			if (uri [uri.Length - 1] != '/')
+				throw new ArgumentException ("The prefix must end with '/'");
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/RequestStream.cs b/Tomboy/Addins/WebSyncService/MonoHttp/RequestStream.cs
new file mode 100644
index 0000000..42212e1
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/RequestStream.cs
@@ -0,0 +1,226 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.RequestStream
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if EMBEDDED_IN_1_0
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System; using System.Net; namespace MonoHttp {
+	class RequestStream : Stream
+	{
+		byte [] buffer;
+		int offset;
+		int length;
+		long remaining_body;
+		bool disposed;
+		Stream stream;
+
+		internal RequestStream (Stream stream, byte [] buffer, int offset, int length)
+			: this (stream, buffer, offset, length, -1)
+		{
+		}
+
+		internal RequestStream (Stream stream, byte [] buffer, int offset, int length, long contentlength)
+		{
+			this.stream = stream;
+			this.buffer = buffer;
+			this.offset = offset;
+			this.length = length;
+			this.remaining_body = contentlength;
+		}
+
+		public override bool CanRead {
+			get { return true; }
+		}
+
+		public override bool CanSeek {
+			get { return false; }
+		}
+
+		public override bool CanWrite {
+			get { return false; }
+		}
+
+		public override long Length {
+			get { throw new NotSupportedException (); }
+		}
+
+		public override long Position {
+			get { throw new NotSupportedException (); }
+			set { throw new NotSupportedException (); }
+		}
+
+
+		public override void Close ()
+		{
+			disposed = true;
+		}
+
+		public override void Flush ()
+		{
+		}
+
+		
+		// Returns 0 if we can keep reading from the base stream,
+		// > 0 if we read something from the buffer.
+		// -1 if we had a content length set and we finished reading that many bytes.
+		int FillFromBuffer (byte [] buffer, int off, int count)
+		{
+			if (buffer == null)
+				throw new ArgumentNullException ("buffer");
+			if (off < 0)
+				throw new ArgumentOutOfRangeException ("offset", "< 0");
+			if (count < 0)
+				throw new ArgumentOutOfRangeException ("count", "< 0");
+			int len = buffer.Length;
+			if (off > len)
+				throw new ArgumentException ("destination offset is beyond array size");
+			if (off > len - count)
+				throw new ArgumentException ("Reading would overrun buffer");
+
+			if (this.remaining_body == 0)
+				return -1;
+
+			if (this.length == 0)
+				return 0;
+
+			int size = Math.Min (this.length, count);
+			if (this.remaining_body > 0)
+				size = (int) Math.Min (size, this.remaining_body);
+
+			if (this.offset > this.buffer.Length - size) {
+				size = Math.Min (size, this.buffer.Length - this.offset);
+			}
+			if (size == 0)
+				return 0;
+
+			Buffer.BlockCopy (this.buffer, this.offset, buffer, off, size);
+			this.offset += size;
+			this.length -= size;
+			if (this.remaining_body > 0)
+				remaining_body -= size;
+			return size;
+		}
+
+		public override int Read ([In,Out] byte[] buffer, int offset, int count)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (typeof (RequestStream).ToString ());
+
+			// Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
+			int nread = FillFromBuffer (buffer, offset, count);
+			if (nread == -1) { // No more bytes available (Content-Length)
+				return 0;
+			} else if (nread > 0) {
+				return nread;
+			}
+
+			nread = stream.Read (buffer, offset, count);
+			if (nread > 0 && remaining_body > 0)
+				remaining_body -= nread;
+			return nread;
+		}
+
+		public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
+							AsyncCallback cback, object state)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (typeof (RequestStream).ToString ());
+
+			int nread = FillFromBuffer (buffer, offset, count);
+			if (nread > 0 || nread == -1) {
+				HttpStreamAsyncResult ares = new HttpStreamAsyncResult ();
+				ares.Buffer = buffer;
+				ares.Offset = offset;
+				ares.Count = count;
+				ares.Callback = cback;
+				ares.State = state;
+				ares.SynchRead = nread;
+				ares.Complete ();
+				return ares;
+			}
+
+			// Avoid reading past the end of the request to allow
+			// for HTTP pipelining
+			if (remaining_body >= 0 && count > remaining_body)
+				count = (int) Math.Min (Int32.MaxValue, remaining_body);
+			return stream.BeginRead (buffer, offset, count, cback, state);
+		}
+
+		public override int EndRead (IAsyncResult ares)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (typeof (RequestStream).ToString ());
+
+			if (ares == null)
+				throw new ArgumentNullException ("async_result");
+
+			if (ares is HttpStreamAsyncResult) {
+				HttpStreamAsyncResult r = (HttpStreamAsyncResult) ares;
+				if (!ares.IsCompleted)
+					ares.AsyncWaitHandle.WaitOne ();
+				return r.SynchRead;
+			}
+
+			// Close on exception?
+			int nread = stream.EndRead (ares);
+			if (remaining_body > 0 && nread > 0)
+				remaining_body -= nread;
+			return nread;
+		}
+
+		public override long Seek (long offset, SeekOrigin origin)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override void SetLength (long value)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override void Write (byte[] buffer, int offset, int count)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
+							AsyncCallback cback, object state)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override void EndWrite (IAsyncResult async_result)
+		{
+			throw new NotSupportedException ();
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/ResponseStream.cs b/Tomboy/Addins/WebSyncService/MonoHttp/ResponseStream.cs
new file mode 100644
index 0000000..ae386bc
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/ResponseStream.cs
@@ -0,0 +1,243 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.ResponseStream
+//
+// Author:
+//	Gonzalo Paniagua Javier (gonzalo novell com)
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if EMBEDDED_IN_1_0
+
+using System.IO;
+using System.Net.Sockets;
+using System.Text;
+using System.Runtime.InteropServices;
+using System; using System.Net; namespace MonoHttp {
+	// FIXME: Does this buffer the response until Close?
+	// Update: we send a single packet for the first non-chunked Write
+	// What happens when we set content-length to X and write X-1 bytes then close?
+	// what if we don't set content-length at all?
+	class ResponseStream : Stream
+	{
+		HttpListenerResponse response;
+		bool ignore_errors;
+		bool disposed;
+		bool trailer_sent;
+		Stream stream;
+
+		internal ResponseStream (Stream stream, HttpListenerResponse response, bool ignore_errors)
+		{
+			this.response = response;
+			this.ignore_errors = ignore_errors;
+			this.stream = stream;
+		}
+
+		public override bool CanRead {
+			get { return false; }
+		}
+
+		public override bool CanSeek {
+			get { return false; }
+		}
+
+		public override bool CanWrite {
+			get { return true; }
+		}
+
+		public override long Length {
+			get { throw new NotSupportedException (); }
+		}
+
+		public override long Position {
+			get { throw new NotSupportedException (); }
+			set { throw new NotSupportedException (); }
+		}
+
+
+		public override void Close ()
+		{
+			if (disposed == false) {
+				disposed = true;
+				byte [] bytes = null;
+				MemoryStream ms = GetHeaders (true);
+				bool chunked = response.SendChunked;
+				if (ms != null) {
+					long start = ms.Position;
+					if (chunked && !trailer_sent) {
+						bytes = GetChunkSizeBytes (0, true);
+						ms.Position = ms.Length;
+						ms.Write (bytes, 0, bytes.Length);
+					}
+					InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start));
+					trailer_sent = true;
+				} else if (chunked && !trailer_sent) {
+					bytes = GetChunkSizeBytes (0, true);
+					InternalWrite (bytes, 0, bytes.Length);
+					trailer_sent = true;
+				}
+				response.Close ();
+			}
+		}
+
+		MemoryStream GetHeaders (bool closing)
+		{
+			if (response.HeadersSent)
+				return null;
+			MemoryStream ms = new MemoryStream ();
+			response.SendHeaders (closing, ms);
+			return ms;
+		}
+
+		public override void Flush ()
+		{
+		}
+
+		static byte [] crlf = new byte [] { 13, 10 };
+		static byte [] GetChunkSizeBytes (int size, bool final)
+		{
+			string str = String.Format ("{0:x}\r\n{1}", size, final ? "\r\n" : "");
+			return Encoding.ASCII.GetBytes (str);
+		}
+
+		internal void InternalWrite (byte [] buffer, int offset, int count)
+		{
+			if (ignore_errors) {
+				try {
+					stream.Write (buffer, offset, count);
+				} catch { }
+			} else {
+				stream.Write (buffer, offset, count);
+			}
+		}
+
+		public override void Write (byte [] buffer, int offset, int count)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType ().ToString ());
+
+			byte [] bytes = null;
+			MemoryStream ms = GetHeaders (false);
+			bool chunked = response.SendChunked;
+			if (ms != null) {
+				long start = ms.Position; // After the possible preamble for the encoding
+				ms.Position = ms.Length;
+				if (chunked) {
+					bytes = GetChunkSizeBytes (count, false);
+					ms.Write (bytes, 0, bytes.Length);
+				}
+
+				int new_count = Math.Min (count, 16384 - (int) ms.Position + (int) start);
+				ms.Write (buffer, offset, new_count);
+				count -= new_count;
+				offset += new_count;
+				InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start));
+				ms.SetLength (0);
+				ms.Capacity = 0; // 'dispose' the buffer in ms.
+			} else if (chunked) {
+				bytes = GetChunkSizeBytes (count, false);
+				InternalWrite (bytes, 0, bytes.Length);
+			}
+
+			if (count > 0)
+				InternalWrite (buffer, offset, count);
+			if (chunked)
+				InternalWrite (crlf, 0, 2);
+		}
+
+		public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
+							AsyncCallback cback, object state)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType ().ToString ());
+
+			byte [] bytes = null;
+			MemoryStream ms = GetHeaders (false);
+			bool chunked = response.SendChunked;
+			if (ms != null) {
+				long start = ms.Position;
+				ms.Position = ms.Length;
+				if (chunked) {
+					bytes = GetChunkSizeBytes (count, false);
+					ms.Write (bytes, 0, bytes.Length);
+				}
+				ms.Write (buffer, offset, count);
+				buffer = ms.GetBuffer ();
+				offset = (int) start;
+				count = (int) (ms.Position - start);
+			} else if (chunked) {
+				bytes = GetChunkSizeBytes (count, false);
+				InternalWrite (bytes, 0, bytes.Length);
+			}
+
+			return stream.BeginWrite (buffer, offset, count, cback, state);
+		}
+
+		public override void EndWrite (IAsyncResult ares)
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType ().ToString ());
+
+			if (ignore_errors) {
+				try {
+					stream.EndWrite (ares);
+					if (response.SendChunked)
+						stream.Write (crlf, 0, 2);
+				} catch { }
+			} else {
+				stream.EndWrite (ares);
+				if (response.SendChunked)
+					stream.Write (crlf, 0, 2);
+			}
+		}
+
+		public override int Read ([In,Out] byte[] buffer, int offset, int count)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override IAsyncResult BeginRead (byte [] buffer, int offset, int count,
+							AsyncCallback cback, object state)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override int EndRead (IAsyncResult ares)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override long Seek (long offset, SeekOrigin origin)
+		{
+			throw new NotSupportedException ();
+		}
+
+		public override void SetLength (long value)
+		{
+			throw new NotSupportedException ();
+		}
+	}
+}
+#endif
+
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/Utility.cs b/Tomboy/Addins/WebSyncService/MonoHttp/Utility.cs
new file mode 100644
index 0000000..fe6100d
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/Utility.cs
@@ -0,0 +1,98 @@
+
+
+using System;
+using System.Text;
+
+namespace MonoHttp
+{
+	class Utility
+	{
+	
+		#region from System.Uri
+		
+		internal static bool MaybeUri (string s)
+		{
+			int p = s.IndexOf (':');
+			if (p == -1)
+				return false;
+
+			if (p >= 10)
+				return false;
+
+			return IsPredefinedScheme (s.Substring (0, p));
+		}
+		
+		private static bool IsPredefinedScheme (string scheme)
+		{
+			switch (scheme) {
+			case "http":
+			case "https":
+			case "file":
+			case "ftp":
+			case "nntp":
+			case "gopher":
+			case "mailto":
+			case "news":
+#if NET_2_0
+			case "net.pipe":
+			case "net.tcp":
+#endif
+				return true;
+			default:
+				return false;
+			}
+		}
+		
+		#endregion
+		
+		#region from System.Net.Cookiie
+		
+		internal static string ToClientString (System.Net.Cookie cookie) 
+		{
+			if (cookie.Name.Length == 0) 
+				return String.Empty;
+
+			StringBuilder result = new StringBuilder (64);
+	
+			if (cookie.Version > 0) 
+				result.Append ("Version=").Append (cookie.Version).Append (";");
+				
+			result.Append (cookie.Name).Append ("=").Append (cookie.Value);
+
+			if (cookie.Path != null && cookie.Path.Length != 0)
+				result.Append (";Path=").Append (QuotedString (cookie, cookie.Path));
+				
+			if (cookie.Domain != null && cookie.Domain.Length != 0)
+				result.Append (";Domain=").Append (QuotedString (cookie, cookie.Domain));			
+	
+			if (cookie.Port != null && cookie.Port.Length != 0)
+				result.Append (";Port=").Append (cookie.Port);	
+						
+			return result.ToString ();
+		}
+
+		// See par 3.6 of RFC 2616
+  	    	static string QuotedString (System.Net.Cookie cookie, string value)
+	    	{
+			if (cookie.Version == 0 || IsToken (value))
+				return value;
+			else 
+				return "\"" + value.Replace("\"", "\\\"") + "\"";
+	    	}			    	    
+
+	    	static bool IsToken (string value) 
+	    	{
+			int len = value.Length;
+			for (int i = 0; i < len; i++) {
+			    	char c = value [i];
+				if (c < 0x20 || c >= 0x7f || tspecials.IndexOf (c) != -1)
+			      		return false;
+			}
+			return true;
+	    	}
+	    	
+	    	 static string tspecials = "()<>@,;:\\\"/[]?={} \t";   // from RFC 2965, 2068
+	    	
+		#endregion
+	}
+}
diff --git a/Tomboy/Addins/WebSyncService/MonoHttp/WebHeaderCollection.cs b/Tomboy/Addins/WebSyncService/MonoHttp/WebHeaderCollection.cs
new file mode 100644
index 0000000..a55384f
--- /dev/null
+++ b/Tomboy/Addins/WebSyncService/MonoHttp/WebHeaderCollection.cs
@@ -0,0 +1,699 @@
+#define EMBEDDED_IN_1_0
+
+//
+// System.Net.WebHeaderCollection
+//
+// Authors:
+// 	Lawrence Pit (loz cable a2000 nl)
+//	Gonzalo Paniagua Javier (gonzalo ximian com)
+//      Miguel de Icaza (miguel novell com)
+//
+// Copyright 2003 Ximian, Inc. (http://www.ximian.com)
+// Copyright 2007 Novell, Inc. (http://www.novell.com)
+//
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Text;
+    
+// See RFC 2068 par 4.2 Message Headers
+    
+using System; using System.Net; namespace MonoHttp 
+{
+	[Serializable]
+	[ComVisible(true)]
+	internal class WebHeaderCollection : NameValueCollection, ISerializable
+	{
+		private static readonly Hashtable restricted;
+		private static readonly Hashtable multiValue;
+		private bool internallyCreated = false;
+		
+		// Static Initializer
+		
+		static WebHeaderCollection () 
+		{
+			// the list of restricted header names as defined 
+			// by the ms.net spec
+			restricted = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
+						    CaseInsensitiveComparer.DefaultInvariant);
+
+			restricted.Add ("accept", true);
+			restricted.Add ("connection", true);
+			restricted.Add ("content-length", true);
+			restricted.Add ("content-type", true);
+			restricted.Add ("date", true);
+			restricted.Add ("expect", true);
+			restricted.Add ("host", true);
+			restricted.Add ("if-modified-since", true);
+			restricted.Add ("range", true);
+			restricted.Add ("referer", true);
+			restricted.Add ("transfer-encoding", true);
+			restricted.Add ("user-agent", true);			
+			
+			// see par 14 of RFC 2068 to see which header names
+			// accept multiple values each separated by a comma
+			multiValue = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
+						    CaseInsensitiveComparer.DefaultInvariant);
+
+			multiValue.Add ("accept", true);
+			multiValue.Add ("accept-charset", true);
+			multiValue.Add ("accept-encoding", true);
+			multiValue.Add ("accept-language", true);
+			multiValue.Add ("accept-ranges", true);
+			multiValue.Add ("allow", true);
+			multiValue.Add ("authorization", true);
+			multiValue.Add ("cache-control", true);
+			multiValue.Add ("connection", true);
+			multiValue.Add ("content-encoding", true);
+			multiValue.Add ("content-language", true);			
+			multiValue.Add ("expect", true);		
+			multiValue.Add ("if-match", true);
+			multiValue.Add ("if-none-match", true);
+			multiValue.Add ("proxy-authenticate", true);
+			multiValue.Add ("public", true);			
+			multiValue.Add ("range", true);
+			multiValue.Add ("transfer-encoding", true);
+			multiValue.Add ("upgrade", true);
+			multiValue.Add ("vary", true);
+			multiValue.Add ("via", true);
+			multiValue.Add ("warning", true);
+			multiValue.Add ("www-authenticate", true);
+
+			// Extra
+			multiValue.Add ("set-cookie", true);
+			multiValue.Add ("set-cookie2", true);
+		}
+		
+		// Constructors
+		
+		public WebHeaderCollection () {	}	
+		
+		protected WebHeaderCollection (SerializationInfo serializationInfo, 
+					       StreamingContext streamingContext)
+		{
+			int count;
+
+			try {
+				count = serializationInfo.GetInt32("Count");
+				for (int i = 0; i < count; i++) 
+					this.Add (serializationInfo.GetString (i.ToString ()),
+						  serializationInfo.GetString ((count + i).ToString ()));
+			} catch (SerializationException){
+				count = serializationInfo.GetInt32("count");
+				for (int i = 0; i < count; i++) 
+					this.Add (serializationInfo.GetString ("k" + i),
+						  serializationInfo.GetString ("v" + i));
+			}
+			
+		}
+		
+		internal WebHeaderCollection (bool internallyCreated)
+		{	
+			this.internallyCreated = internallyCreated;
+		}		
+		
+		// Methods
+		
+		public void Add (string header)
+		{
+			if (header == null)
+				throw new ArgumentNullException ("header");
+			int pos = header.IndexOf (':');
+			if (pos == -1)
+				throw new ArgumentException ("no colon found", "header");				
+			this.Add (header.Substring (0, pos), 
+				  header.Substring (pos + 1));
+		}
+		
+		public override void Add (string name, string value)
+		{
+			if (name == null)
+				throw new ArgumentNullException ("name");
+			if (internallyCreated && IsRestricted (name))
+				throw new ArgumentException ("This header must be modified with the appropiate property.");
+			this.AddWithoutValidate (name, value);
+		}
+
+		protected void AddWithoutValidate (string headerName, string headerValue)
+		{
+			if (!IsHeaderName (headerName))
+				throw new ArgumentException ("invalid header name: " + headerName, "headerName");
+			if (headerValue == null)
+				headerValue = String.Empty;
+			else
+				headerValue = headerValue.Trim ();
+			if (!IsHeaderValue (headerValue))
+				throw new ArgumentException ("invalid header value: " + headerValue, "headerValue");
+			base.Add (headerName, headerValue);			
+		}
+
+		public override string [] GetValues (string header)
+		{
+			if (header == null)
+				throw new ArgumentNullException ("header");
+
+			string [] values = base.GetValues (header);
+			if (values == null || values.Length == 0)
+				return null;
+
+			/*
+			if (IsMultiValue (header)) {
+				values = GetMultipleValues (values);
+			}
+			*/
+
+			return values;
+		}
+
+		public override string[] GetValues (int index)
+		{
+			string[] values = base.GetValues (index);
+			if (values == null || values.Length == 0) {
+				return(null);
+			}
+			
+			return(values);
+		}
+
+		/* Now i wonder why this is here...
+		static string [] GetMultipleValues (string [] values)
+		{
+			ArrayList mvalues = new ArrayList (values.Length);
+			StringBuilder sb = null;
+			for (int i = 0; i < values.Length; ++i) {
+				string val = values [i];
+				if (val.IndexOf (',') == -1) {
+					mvalues.Add (val);
+					continue;
+				}
+
+				if (sb == null)
+					sb = new StringBuilder ();
+
+				bool quote = false;
+				for (int k = 0; k < val.Length; k++) {
+					char c = val [k];
+					if (c == '"') {
+						quote = !quote;
+					} else if (!quote && c == ',') {
+						mvalues.Add (sb.ToString ().Trim ());
+						sb.Length = 0;
+						continue;
+					}
+					sb.Append (c);
+				}
+
+				if (sb.Length > 0) {
+					mvalues.Add (sb.ToString ().Trim ());
+					sb.Length = 0;
+				}
+			}
+
+			return (string []) mvalues.ToArray (typeof (string));
+		}
+		*/
+
+		public static bool IsRestricted (string headerName)
+		{
+			if (headerName == null)
+				throw new ArgumentNullException ("headerName");
+
+			if (headerName == "") // MS throw nullexception here!
+				throw new ArgumentException ("empty string", "headerName");
+
+			return restricted.ContainsKey (headerName);
+		}
+
+#if EMBEDDED_IN_1_0
+		//[MonoNotSupported("")]
+		public static bool IsRestricted (string headerName, bool response)
+		{
+			throw new NotImplementedException ();
+		}
+#endif
+
+		public override void OnDeserialization (object sender)
+		{
+		}
+
+		public override void Remove (string name)
+		{
+			if (name == null)
+				throw new ArgumentNullException ("name");
+			if (internallyCreated && IsRestricted (name))
+				throw new ArgumentException ("restricted header");
+			base.Remove (name);
+		}
+
+		public override void Set (string name, string value)
+		{
+			if (name == null)
+				throw new ArgumentNullException ("name");
+			if (internallyCreated && IsRestricted (name))
+				throw new ArgumentException ("restricted header");
+			if (!IsHeaderName (name))
+				throw new ArgumentException ("invalid header name");
+			if (value == null)
+				value = String.Empty;
+			else
+				value = value.Trim ();
+			if (!IsHeaderValue (value))
+				throw new ArgumentException ("invalid header value");
+			base.Set (name, value);			
+		}
+
+		public byte[] ToByteArray ()
+		{
+			return Encoding.UTF8.GetBytes(ToString ());
+		}
+
+		public override string ToString ()
+		{
+			StringBuilder sb = new StringBuilder();
+
+			int count = base.Count;
+			for (int i = 0; i < count ; i++)
+				sb.Append (GetKey (i))
+				  .Append (": ")
+				  .Append (Get (i))
+				  .Append ("\r\n");
+				  
+			return sb.Append("\r\n").ToString();
+		}
+#if !TARGET_JVM
+		void ISerializable.GetObjectData (SerializationInfo serializationInfo,
+						  StreamingContext streamingContext)
+		{
+			GetObjectData (serializationInfo, streamingContext);
+		}
+#endif
+		public override void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
+		{
+			int count = base.Count;
+			serializationInfo.AddValue ("Count", count);
+			for (int i = 0; i < count; i++) {
+				serializationInfo.AddValue (i.ToString (), GetKey (i));
+				serializationInfo.AddValue ((count + i).ToString (), Get (i));
+			}
+		}
+
+		public override string[] AllKeys
+		{
+			get {
+				return(base.AllKeys);
+			}
+		}
+		
+		public override int Count 
+		{
+			get {
+				return(base.Count);
+			}
+		}
+
+		public override KeysCollection Keys
+		{
+			get {
+				return(base.Keys);
+			}
+		}
+
+		public override string Get (int index)
+		{
+			return(base.Get (index));
+		}
+		
+		public override string Get (string name)
+		{
+			return(base.Get (name));
+		}
+		
+		public override string GetKey (int index)
+		{
+			return(base.GetKey (index));
+		}
+
+#if EMBEDDED_IN_1_0
+		public void Add (HttpRequestHeader header, string value)
+		{
+			Add (RequestHeaderToString (header), value);
+		}
+
+		public void Remove (HttpRequestHeader header)
+		{
+			Remove (RequestHeaderToString (header));
+		}
+
+		public void Set (HttpRequestHeader header, string value)
+		{
+			Set (RequestHeaderToString (header), value);
+		}
+
+		public void Add (HttpResponseHeader header, string value)
+		{
+			Add (ResponseHeaderToString (header), value);
+		}
+
+		public void Remove (HttpResponseHeader header)
+		{
+			Remove (ResponseHeaderToString (header));
+		}
+
+		public void Set (HttpResponseHeader header, string value)
+		{
+			Set (ResponseHeaderToString (header), value);
+		}
+
+		string RequestHeaderToString (HttpRequestHeader value)
+		{
+			switch (value){
+			case HttpRequestHeader.CacheControl:
+				return "cache-control";
+			case HttpRequestHeader.Connection:
+				return "connection";
+			case HttpRequestHeader.Date:
+				return "date";
+			case HttpRequestHeader.KeepAlive:
+				return "keep-alive";
+			case HttpRequestHeader.Pragma:
+				return "pragma";
+			case HttpRequestHeader.Trailer:
+				return "trailer";
+			case HttpRequestHeader.TransferEncoding:
+				return "transfer-encoding";
+			case HttpRequestHeader.Upgrade:
+				return "upgrade";
+			case HttpRequestHeader.Via:
+				return "via";
+			case HttpRequestHeader.Warning:
+				return "warning";
+			case HttpRequestHeader.Allow:
+				return "allow";
+			case HttpRequestHeader.ContentLength:
+				return "content-length";
+			case HttpRequestHeader.ContentType:
+				return "content-type";
+			case HttpRequestHeader.ContentEncoding:
+				return "content-encoding";
+			case HttpRequestHeader.ContentLanguage:
+				return "content-language";
+			case HttpRequestHeader.ContentLocation:
+				return "content-location";
+			case HttpRequestHeader.ContentMd5:
+				return "content-md5";
+			case HttpRequestHeader.ContentRange:
+				return "content-range";
+			case HttpRequestHeader.Expires:
+				return "expires";
+			case HttpRequestHeader.LastModified:
+				return "last-modified";
+			case HttpRequestHeader.Accept:
+				return "accept";
+			case HttpRequestHeader.AcceptCharset:
+				return "accept-charset";
+			case HttpRequestHeader.AcceptEncoding:
+				return "accept-encoding";
+			case HttpRequestHeader.AcceptLanguage:
+				return "accept-language";
+			case HttpRequestHeader.Authorization:
+				return "authorization";
+			case HttpRequestHeader.Cookie:
+				return "cookie";
+			case HttpRequestHeader.Expect:
+				return "expect";
+			case HttpRequestHeader.From:
+				return "from";
+			case HttpRequestHeader.Host:
+				return "host";
+			case HttpRequestHeader.IfMatch:
+				return "if-match";
+			case HttpRequestHeader.IfModifiedSince:
+				return "if-modified-since";
+			case HttpRequestHeader.IfNoneMatch:
+				return "if-none-match";
+			case HttpRequestHeader.IfRange:
+				return "if-range";
+			case HttpRequestHeader.IfUnmodifiedSince:
+				return "if-unmodified-since";
+			case HttpRequestHeader.MaxForwards:
+				return "max-forwards";
+			case HttpRequestHeader.ProxyAuthorization:
+				return "proxy-authorization";
+			case HttpRequestHeader.Referer:
+				return "referer";
+			case HttpRequestHeader.Range:
+				return "range";
+			case HttpRequestHeader.Te:
+				return "te";
+			case HttpRequestHeader.Translate:
+				return "translate";
+			case HttpRequestHeader.UserAgent:
+				return "user-agent";
+			default:
+				throw new InvalidOperationException ();
+			}
+		}
+		
+		
+		public string this[HttpRequestHeader hrh]
+		{
+			get {
+				return Get (RequestHeaderToString (hrh));
+			}
+			
+			set {
+				Add (RequestHeaderToString (hrh), value);
+			}
+		}
+
+		string ResponseHeaderToString (HttpResponseHeader value)
+		{
+			switch (value){
+			case HttpResponseHeader.CacheControl:
+				return "cache-control";
+			case HttpResponseHeader.Connection:
+				return "connection";
+			case HttpResponseHeader.Date:
+				return "date";
+			case HttpResponseHeader.KeepAlive:
+				return "keep-alive";
+			case HttpResponseHeader.Pragma:
+				return "pragma";
+			case HttpResponseHeader.Trailer:
+				return "trailer";
+			case HttpResponseHeader.TransferEncoding:
+				return "transfer-encoding";
+			case HttpResponseHeader.Upgrade:
+				return "upgrade";
+			case HttpResponseHeader.Via:
+				return "via";
+			case HttpResponseHeader.Warning:
+				return "warning";
+			case HttpResponseHeader.Allow:
+				return "allow";
+			case HttpResponseHeader.ContentLength:
+				return "content-length";
+			case HttpResponseHeader.ContentType:
+				return "content-type";
+			case HttpResponseHeader.ContentEncoding:
+				return "content-encoding";
+			case HttpResponseHeader.ContentLanguage:
+				return "content-language";
+			case HttpResponseHeader.ContentLocation:
+				return "content-location";
+			case HttpResponseHeader.ContentMd5:
+				return "content-md5";
+			case HttpResponseHeader.ContentRange:
+				return "content-range";
+			case HttpResponseHeader.Expires:
+				return "expires";
+			case HttpResponseHeader.LastModified:
+				return "last-modified";
+			case HttpResponseHeader.AcceptRanges:
+				return "accept-ranges";
+			case HttpResponseHeader.Age:
+				return "age";
+			case HttpResponseHeader.ETag:
+				return "etag";
+			case HttpResponseHeader.Location:
+				return "location";
+			case HttpResponseHeader.ProxyAuthenticate:
+				return "proxy-authenticate";
+			case HttpResponseHeader.RetryAfter:
+				return "RetryAfter";
+			case HttpResponseHeader.Server:
+				return "server";
+			case HttpResponseHeader.SetCookie:
+				return "set-cookie";
+			case HttpResponseHeader.Vary:
+				return "vary";
+			case HttpResponseHeader.WwwAuthenticate:
+				return "www-authenticate";
+			default:
+				throw new InvalidOperationException ();
+			}
+		}
+		public string this[HttpResponseHeader hrh]
+		{
+			get
+			{
+				return Get (ResponseHeaderToString (hrh));
+			}
+
+			set
+			{
+				Add (ResponseHeaderToString (hrh), value);
+			}
+		}
+
+
+#endif
+#if EMBEDDED_IN_1_0 && !EMBEDDED_IN_1_0
+		public override void Clear ()
+		{
+			base.Clear ();
+		}
+
+
+		public override IEnumerator GetEnumerator ()
+		{
+			return(base.GetEnumerator ());
+		}
+#endif
+
+		// Internal Methods
+		
+		// With this we don't check for invalid characters in header. See bug #55994.
+		internal void SetInternal (string header)
+		{
+			int pos = header.IndexOf (':');
+			if (pos == -1)
+				throw new ArgumentException ("no colon found", "header");				
+
+			SetInternal (header.Substring (0, pos), header.Substring (pos + 1));
+		}
+
+		internal void SetInternal (string name, string value)
+		{
+			if (value == null)
+				value = String.Empty;
+			else
+				value = value.Trim ();
+			if (!IsHeaderValue (value))
+				throw new ArgumentException ("invalid header value");
+
+			if (IsMultiValue (name)) {
+				base.Add (name, value);
+			} else {
+				base.Remove (name);
+				base.Set (name, value);	
+			}
+		}
+
+		internal void RemoveAndAdd (string name, string value)
+		{
+			if (value == null)
+				value = String.Empty;
+			else
+				value = value.Trim ();
+
+			base.Remove (name);
+			base.Set (name, value);
+		}
+
+		internal void RemoveInternal (string name)
+		{
+			if (name == null)
+				throw new ArgumentNullException ("name");
+			base.Remove (name);
+		}		
+		
+		// Private Methods
+		
+		internal static bool IsMultiValue (string headerName)
+		{
+			if (headerName == null || headerName == "")
+				return false;
+
+			return multiValue.ContainsKey (headerName);
+		}		
+		
+		internal static bool IsHeaderValue (string value)
+		{
+			// TEXT any 8 bit value except CTL's (0-31 and 127)
+			//      but including \r\n space and \t
+			//      after a newline at least one space or \t must follow
+			//      certain header fields allow comments ()
+				
+			int len = value.Length;
+			for (int i = 0; i < len; i++) {			
+				char c = value [i];
+				if (c == 127)
+					return false;
+				if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
+					return false;
+				if (c == '\n' && ++i < len) {
+					c = value [i];
+					if (c != ' ' && c != '\t')
+						return false;
+				}
+			}
+			
+			return true;
+		}
+		
+		internal static bool IsHeaderName (string name)
+		{
+			// token          = 1*<any CHAR except CTLs or tspecials>
+			// tspecials      = "(" | ")" | "<" | ">" | "@"
+			//                | "," | ";" | ":" | "\" | <">
+			//                | "/" | "[" | "]" | "?" | "="
+			//                | "{" | "}" | SP | HT
+			
+			if (name == null || name.Length == 0)
+				return false;
+
+			int len = name.Length;
+			for (int i = 0; i < len; i++) {			
+				char c = name [i];
+				if (c < 0x20 || c >= 0x7f)
+					return false;
+			}
+			
+			return name.IndexOfAny (tspecials) == -1;
+		}
+
+		private static char [] tspecials = 
+				new char [] {'(', ')', '<', '>', '@',
+					     ',', ';', ':', '\\', '"',
+					     '/', '[', ']', '?', '=',
+					     '{', '}', ' ', '\t'};
+							
+	}
+}
+
+
diff --git a/Tomboy/Addins/WebSyncService/WebSyncPreferencesWidget.cs b/Tomboy/Addins/WebSyncService/WebSyncPreferencesWidget.cs
index a99c2cc..79b2a78 100644
--- a/Tomboy/Addins/WebSyncService/WebSyncPreferencesWidget.cs
+++ b/Tomboy/Addins/WebSyncService/WebSyncPreferencesWidget.cs
@@ -24,7 +24,6 @@
 // 
 
 using System;
-using System.Net;
 using System.Web;
 
 using Mono.Unix;
@@ -37,7 +36,7 @@ namespace Tomboy.WebSync
 		private Gtk.Entry serverEntry;
 		private Gtk.Button authButton;
 		private Api.OAuth oauth;
-		private HttpListener listener;
+		private MonoHttp.HttpListener listener;
 		
 		private const string callbackHtmlTemplate =
 			@"<html><head><title>{0}</title></head><body><div><h1>{0}</h1>{1}</div></body></html>";
@@ -123,7 +122,7 @@ namespace Tomboy.WebSync
 			}
 
 			if (!Auth.IsAccessToken) {
-				listener = new HttpListener ();
+				listener = new MonoHttp.HttpListener ();
 				int portToTry = 8000;
 				string callbackUrl = string.Empty;
 				while (!listener.IsListening && portToTry < 9000) {
diff --git a/Tomboy/Addins/WebSyncService/WebSyncService.csproj b/Tomboy/Addins/WebSyncService/WebSyncService.csproj
index a04aaf8..e629a96 100644
--- a/Tomboy/Addins/WebSyncService/WebSyncService.csproj
+++ b/Tomboy/Addins/WebSyncService/WebSyncService.csproj
@@ -87,6 +87,30 @@
     <Compile Include="Hyena.Json\Token.cs" />
     <Compile Include="Hyena.Json\Tokenizer.cs" />
     <Compile Include="Hyena.Json\TokenType.cs" />
+    <Compile Include="MonoHttp\AuthenticationSchemes.cs" />
+    <Compile Include="MonoHttp\AuthenticationSchemeSelector.cs" />
+    <Compile Include="MonoHttp\ChunkedInputStream.cs" />
+    <Compile Include="MonoHttp\ChunkStream.cs" />
+    <Compile Include="MonoHttp\EndPointListener.cs" />
+    <Compile Include="MonoHttp\EndPointManager.cs" />
+    <Compile Include="MonoHttp\HttpConnection.cs" />
+    <Compile Include="MonoHttp\HttpListener.cs" />
+    <Compile Include="MonoHttp\HttpListenerBasicIdentity.cs" />
+    <Compile Include="MonoHttp\HttpListenerContext.cs" />
+    <Compile Include="MonoHttp\HttpListenerException.cs" />
+    <Compile Include="MonoHttp\HttpListenerPrefixCollection.cs" />
+    <Compile Include="MonoHttp\HttpListenerRequest.cs" />
+    <Compile Include="MonoHttp\HttpListenerResponse.cs" />
+    <Compile Include="MonoHttp\HttpRequestHeader.cs" />
+    <Compile Include="MonoHttp\HttpResponseHeader.cs" />
+    <Compile Include="MonoHttp\HttpStreamAsyncResult.cs" />
+    <Compile Include="MonoHttp\HttpUtility.cs" />
+    <Compile Include="MonoHttp\ListenerAsyncResult.cs" />
+    <Compile Include="MonoHttp\ListenerPrefix.cs" />
+    <Compile Include="MonoHttp\RequestStream.cs" />
+    <Compile Include="MonoHttp\ResponseStream.cs" />
+    <Compile Include="MonoHttp\Utility.cs" />
+    <Compile Include="MonoHttp\WebHeaderCollection.cs" />
     <Compile Include="OAuth\Base.cs" />
     <Compile Include="OAuth\Enums.cs" />
     <Compile Include="OAuth\Extensions.cs" />



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]