context: // 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. 
  // 
  // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 
  // 
  // Authors: 
  //      Sandy Armstrong <sanfordarmstrong@gmail.com>
  // Based on code from:
  //      Bojan Rajkovic <bojanr@brandeis.edu>
  //      Shannon Whitley <swhitley@whitleymedia.com>
  //      Eran Sandler <http://eran.sandler.co.il/>
  // 
  
  using System;
  using System.Collections.Generic;
  using System.Net;
  using System.IO;
  using System.Text;
  using System.Web;
  
  using OAuth;
  using Mono.Rocks;
  
  namespace Tomboy.WebSync.Api
  {
  	// TODO: Rename to OAuthConnection ?
  	public class OAuth : Base, IWebConnection
  	{
  		#region Constructor
  		public OAuth ()
  		{
  			Debugging = false;
  		}
  		#endregion
  
  		#region Public Authorization Methods
  		public string GetAuthorizationUrl ()
  		{
  			var response = Post (RequestTokenBaseUrl, null, string.Empty);
  
  			if (response.Length > 0) {
  				// Response contains token and token secret.  We only need the token until we're authorized.
  				var qs = HttpUtility.ParseQueryString (response);
  				if (!string.IsNullOrEmpty (qs ["oauth_token"])) {
  					Token = qs ["oauth_token"];
  					TokenSecret = qs ["oauth_token_secret"];
  					var link = string.Format ("{0}?oauth_token={1}&oauth_callback={2}", AuthorizeLocation, qs ["oauth_token"], HttpUtility.UrlEncode (CallbackUrl));
  					Logger.Debug ("Response from request for auth url: {0}", response);
  					return link;
  				}
  			}
  
  			Logger.Error ("Asked server for preliminary token, but received nothing.");
  
  			return string.Empty;
  		}
  
  		public bool GetAccessAfterAuthorization ()
  		{
  			if (string.IsNullOrEmpty (Token))
  				throw new Exception ("Token");
  
  			Logger.Debug ("Asking server for access token based on authorization token.");
  
  			var response = Post (AccessTokenBaseUrl, null, string.Empty);
  
  			Logger.Debug ("Received response from server: {0}", response);
  
  			if (response.Length > 0) {
  				//Store the Token and Token Secret
  				var qs = HttpUtility.ParseQueryString (response);
  				if (!string.IsNullOrEmpty (qs ["oauth_token"]))
  					Token = qs ["oauth_token"];
  				if (!string.IsNullOrEmpty (qs ["oauth_token_secret"]))
  					TokenSecret = qs ["oauth_token_secret"];
  				Logger.Debug ("Got access token from server");
  				IsAccessToken = true;
  				return true;
  			} else {
  				Logger.Error ("Failed to get access token from server");
  				return false;
  			}
  		}
  		#endregion
  
  		#region IWebConnection implementation
  		public string Get (string uri, IDictionary<string, string> queryParameters)
  		{
  			return WebRequest (RequestMethod.GET,
  			                   BuildUri (uri, queryParameters),
  			                   null);
  		}
  		
  		public string Delete (string uri, IDictionary<string, string> queryParameters)
  		{
  			return WebRequest (RequestMethod.DELETE,
  			                   BuildUri (uri, queryParameters),
  			                   null);
  		}
  		
  		public string Put (string uri, IDictionary<string, string> queryParameters, string putValue)
  		{
  			return WebRequest (RequestMethod.PUT,
  			                   BuildUri (uri, queryParameters),
  			                   putValue);
  		}
  		
  		public string Post (string uri, IDictionary<string, string> queryParameters, string postValue)
  		{
  			return WebRequest (RequestMethod.POST,
  			                   BuildUri (uri, queryParameters),
  			                   postValue);
  		}
  		#endregion
  
  		#region Public Properties
  		public string Token { get; set; }
  
  		public string TokenSecret { get; set; }
  
  		public bool IsAccessToken { get; set; }
  
  		public string ConsumerKey { get; set; }
  
  		public string ConsumerSecret { get; set; }
  
  		public string AuthorizeLocation { get; set; }
  
  		public string RequestTokenBaseUrl { get; set; }
  
  		public string AccessTokenBaseUrl { get; set; }
  
  		public string Realm { get; set; }
  
  		public string CallbackUrl { get; set; }
  
  		public string Verifier { get; set; }
  		#endregion
  
  		#region Private Methods
  //		/// <summary>
  //		/// Submit a web request using OAuth, asynchronously.
  //		/// </summary>
  //		/// <param name="method">GET or POST.</param>
  //		/// <param name="url">The full URL, including the query string.</param>
  //		/// <param name="postData">Data to post (query string format), if POST methods.</param>
  //		/// <param name="callback">The callback to call with the web request data when the asynchronous web request finishes.</param>
  //		/// <returns>The return value of QueueUserWorkItem.</returns>
  //		public bool AsyncWebRequest (RequestMethod method, string url, string postData, Action<string> callback)
  //		{
  //			return ThreadPool.QueueUserWorkItem (new WaitCallback (delegate {
  //				callback (WebRequest (method, url, postData));
  //			}));
  //		}
  
  		/// <summary>
  		/// Submit a web request using OAuth.
  		/// </summary>
  		/// <param name="method">GET or POST.</param>
  		/// <param name="url">The full URL, including the query string.</param>
  		/// <param name="postData">Data to post (query string format), if POST methods.</param>
  		/// <returns>The web server response.</returns>
  		private string WebRequest (RequestMethod method, string url, string postData)
  		{
  			Uri uri = new Uri (url);
  
  			var nonce = GenerateNonce ();
  			var timeStamp = GenerateTimeStamp ();
  
  			Logger.Debug ("Building web request for URL: {0}", url);
  			if (Debugging) {
  				Logger.Debug ("Generated nonce is {0}", nonce);
  				Logger.Debug ("Generated time stamp is {0}", timeStamp);
  			}
  
  			var outUrl = string.Empty;
  			List<IQueryParameter<string>> parameters = null;
  
  			string callbackUrl = string.Empty;
  			if (url.StartsWith (RequestTokenBaseUrl) || url.StartsWith (AccessTokenBaseUrl))
  				callbackUrl = CallbackUrl;
  			var sig = GenerateSignature (uri, ConsumerKey, ConsumerSecret, Token, TokenSecret, Verifier, method,
  			                             timeStamp, nonce, callbackUrl, out outUrl, out parameters);
  
  			if (Debugging)
  				Logger.Debug ("Generated signature {0}", sig);
  
  			parameters.Add (new QueryParameter<string> ("oauth_signature",
  			                                            HttpUtility.UrlEncode (sig),
  			                                            s => string.IsNullOrEmpty (s)));
  			parameters.Sort ();
  
  			if (Debugging)
  				Logger.Debug ("Post data: {0}", postData);
  
  
gt: 			var ret = MakeWebRequest (method, url, parameters, postData);