<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>code:brook</title>
	<atom:link href="http://codebrook.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://codebrook.wordpress.com</link>
	<description>Brook Miles, a programmer</description>
	<lastBuildDate>Mon, 24 Oct 2011 03:29:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='codebrook.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>code:brook</title>
		<link>http://codebrook.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://codebrook.wordpress.com/osd.xml" title="code:brook" />
	<atom:link rel='hub' href='http://codebrook.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Twitter OAuth in C++ for Win32 &#8211; Part 3 &#8211; Updating Twitter Status</title>
		<link>http://codebrook.wordpress.com/2010/09/01/twitter-oauth-in-c-for-win32-part-3-updating-twitter-status/</link>
		<comments>http://codebrook.wordpress.com/2010/09/01/twitter-oauth-in-c-for-win32-part-3-updating-twitter-status/#comments</comments>
		<pubDate>Thu, 02 Sep 2010 06:35:45 +0000</pubDate>
		<dc:creator>Brook Miles</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[Win32]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[win32]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://codebrook.wordpress.com/?p=105</guid>
		<description><![CDATA[
 <a href="http://codebrook.wordpress.com/2010/09/01/twitter-oauth-in-c-for-win32-part-3-updating-twitter-status/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=105&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h3><span style="color:#444444;line-height:24px;font-size:16px;"><a href="http://codebrook.wordpress.com/2010/07/08/twitter-oauth-in-cpp-for-win32/">Part 1</a> covered the OAuth process at a high level, and <a href="http://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/">Part 2</a> went over the example code in detail.  Here in Part 3, we&#8217;ll finish things off by adding support for doing OAuth POST requests, enabling you to update your Twitter status.</span></h3>
<p>The <a href="https://code.google.com/p/codebrook-twitter-oauth/">example project and source files</a> are available on Google Code; C++ code for Win32, with a Visual Studio 2008 project file.</p>
<h3>OAuth POST Requests</h3>
<p>Doing a POST request isn&#8217;t much different from doing a GET request, but there are still a few important things that you need to get right and, like all things OAuth, if there is a single character out of place somewhere it won&#8217;t work.</p>
<p><span id="more-105"></span></p>
<p>First one simple cosmetic change for clarity, I renamed the <code>OAuthParameters</code> type to <code>HTTPParameters</code> to reflect its general nature. I&#8217;m using it for holding GET and POST query parameters as well as those used for OAuth.</p>
<p><pre class="brush: cpp;">typedef std::map&lt;wstring, wstring&gt; HTTPParameters;</pre></p>
<p>This name change is reflected throughout the code.  Next we add a new URL constant for accessing the status update API on twitter:</p>
<p><pre class="brush: cpp;">const wstring UserStatusUpdateUrl = L&quot;http://twitter.com/statuses/update.xml&quot;;
</pre></p>
<p>I added a quick interface to prompt the user for their status update after retrieving the user&#8217;s timeline:</p>
<p><pre class="brush: cpp;">	wprintf(L&quot;Enter your status update (Enter to skip): &quot;);

	wchar_t buf[500] = {L&quot;&quot;};
	_getws_s(buf, SIZEOF(buf));

	wstring input = buf;
	if(input.size() &gt; 0)
	{
		wprintf(L&quot;\r\nUpdating status: %s\r\n&quot;, input.c_str());

		HTTPParameters postParams;
		postParams[L&quot;status&quot;] = UrlEncode(input);

		wstring submitResult = OAuthWebRequestSubmit(UserStatusUpdateUrl, L&quot;POST&quot;, &amp;postParams, ConsumerKey, ConsumerSecret,
			oauthAccessToken, oauthAccessTokenSecret);

		wprintf(L&quot;\r\nUpdate Result:\r\n%s\r\n&quot;, submitResult.c_str());
	}</pre></p>
<p>After checking if the user has entered an update and not an empty string, the first step is to build an <code>HTTPParameters</code> object and assign the user&#8217;s text to the <code>'status'</code> parameter.  There are a number of other possible parameters which could also be added to <code>postParams</code>, as documented on the <a href="http://dev.twitter.com/doc/post/statuses/update">Twitter API statuses/update reference page</a>.</p>
<p>Note that the status text is URL Encoded immediately, before it is put into the parameters object.  I originally had made the mistake of leaving this until later, when I build the POST query string to send over HTTP.  This is incorrect (as I&#8217;ve implemented things), because when we generate the OAuth signature later, we need to sign the POST query values <em>as they are sent to the server</em>.  In this case, that means URL Encoded, and since I was only URL encoding the data as I sent it in the POST request, the signed data didn&#8217;t match (it wasn&#8217;t URL encoded).  One alternative would have been to do the URL encoding in multiple places, when I generate the OAuth signature, and when generating the POST form data.  Doing it once removes decreases your chances of forgetting or doing things differently in multiple places later.</p>
<p>There are two other changes of note here, one is that we are passing <code>"POST"</code> as the HTTP request method, indicating that we are passing parameters as the request body, and not as part of the URL as in GET requests.  The second is I&#8217;ve added a new parameter to <code>OAuthWebRequestSubmit</code>, following the request method is an optional pointer to an <code>HTTPParameters</code> list, here we provide <code>postParams</code> which contains the status value.</p>
<p>This second change is also reflected throughout the rest of the example code, where all of the other calls are using the <code>"GET"</code> HTTP request method I am simply passing <code>NULL </code>for the unused <code>postParameters</code> value.</p>
<p>The updated <code>OAuthWebRequestSubmit</code>:</p>
<p><pre class="brush: cpp; highlight: [4,19,23];">wstring OAuthWebRequestSubmit(
    const wstring&amp; url,
	const wstring&amp; httpMethod,
	const HTTPParameters* postParameters,
    const wstring&amp; consumerKey,
    const wstring&amp; consumerSecret,
    const wstring&amp; oauthToken = L&quot;&quot;,
    const wstring&amp; oauthTokenSecret = L&quot;&quot;,
    const wstring&amp; pin = L&quot;&quot;
    )
{
    wstring query = UrlGetQuery(url);
    HTTPParameters getParameters = ParseQueryString(query);

    HTTPParameters oauthSignedParameters = BuildSignedOAuthParameters(
        getParameters,
        url,
        httpMethod,
		postParameters,
        consumerKey, consumerSecret,
        oauthToken, oauthTokenSecret,
        pin );
	return OAuthWebRequestSignedSubmit(oauthSignedParameters, url, httpMethod, postParameters);
}</pre></p>
<p>The only difference is that we are now passing the new <code>postParameters </code>value to <code>BuildSignedOAuthParameters </code>and <code>OAuthWebRequestSignedSubmit</code> (formerly also named OAuthWebRequestSubmit, which wasn&#8217;t a great choice for clarity), as well as passing the <code>httpMethod</code> to <code>OAuthWebRequestSignedSubmit</code> which now takes the HTTP request method as an argument instead of hard coding it to <code>"GET"</code> internally.</p>
<p><code>BuildSignedOAuthParameters</code> actually does something useful with the new <code>postParameters</code> value:</p>
<p><pre class="brush: cpp; highlight: [4,5,6,7];">	// create a parameter list containing both oauth and original parameters
	// this will be used to create the parameter signature
	HTTPParameters allParameters = requestParameters;
	if(Compare(httpMethod, L&quot;POST&quot;, false) &amp;&amp; postParameters)
	{
		allParameters.insert(postParameters-&gt;begin(), postParameters-&gt;end());
	}
	allParameters.insert(oauthParameters.begin(), oauthParameters.end());

	// prepare a signature base, a carefully formatted string containing
	// all of the necessary information needed to generate a valid signature
	wstring normalUrl = OAuthNormalizeUrl(url);
	wstring normalizedParameters = OAuthNormalizeRequestParameters(allParameters);
	wstring signatureBase = OAuthConcatenateRequestElements(httpMethod, normalUrl, normalizedParameters);

	// obtain a signature and add it to header requestParameters
	wstring signature = OAuthCreateSignature(signatureBase, consumerSecret, requestTokenSecret);
	oauthParameters[L&quot;oauth_signature&quot;] = signature;

	return oauthParameters;</pre></p>
<p>Where before we were taking the request parameters (parsed from the URL) and adding in the OAuth parameters (that we just generated) and combining them into the same list, we are now adding the <code>postParameters</code> into the mix as well, but only if it&#8217;s a <code>"POST"</code> request, and there are any <code>postParameters</code> available to be added.  As you can see, this master list is then sent to <code>OAuthNormalizeRequestParameters</code> whose return value is then concatenated and ultimately included in the <code>OAuthCreateSignature</code> process.</p>
<p>Finally, after the signature is generated we pass our two new parameters to  <code>OAuthWebRequestSignedSubmit</code> where the actual working of doing the POSTing happens:</p>
<p><pre class="brush: cpp; highlight: [4,5,11,56,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88];">wstring OAuthWebRequestSignedSubmit(
	const HTTPParameters&amp; oauthParameters,
	const wstring&amp; url,
	const wstring&amp; httpMethod,
	const HTTPParameters* postParameters
	)
{
	_TRACE(&quot;OAuthWebRequestSignedSubmit(%s)&quot;, url.c_str());

	wstring oauthHeader = L&quot;Authorization: OAuth &quot;;
	oauthHeader += OAuthBuildHeader(oauthParameters);
	oauthHeader += L&quot;\r\n&quot;;

	_TRACE(&quot;%s&quot;, oauthHeader.c_str());

	wchar_t host[1024*4] = {};
	wchar_t path[1024*4] = {};

	URL_COMPONENTS components = { sizeof(URL_COMPONENTS) };

	components.lpszHostName = host;
	components.dwHostNameLength = SIZEOF(host);

	components.lpszUrlPath = path;
	components.dwUrlPathLength = SIZEOF(path);

	wstring normalUrl = url;

	BOOL crackUrlOk = InternetCrackUrl(url.c_str(), url.size(), 0, &amp;components);
	_ASSERTE(crackUrlOk);

	wstring result;

	// TODO you'd probably want to InternetOpen only once at app initialization
	HINTERNET hINet = InternetOpen(L&quot;tc2/1.0&quot;,
		INTERNET_OPEN_TYPE_PRECONFIG,
		NULL,
		NULL,
		0 );
	_ASSERTE( hINet != NULL );
	if ( hINet != NULL )
	{
		// TODO add support for HTTPS requests
		HINTERNET hConnection = InternetConnect(
			hINet,
			host,
			components.nPort,
			NULL,
			NULL,
			INTERNET_SERVICE_HTTP,
			0, 0 );
		_ASSERTE(hConnection != NULL);
		if ( hConnection != NULL)
		{
			HINTERNET hData = HttpOpenRequest( hConnection,
				httpMethod.c_str(),
				path,
				NULL,
				NULL,
				NULL,
				INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_RELOAD,
				0 );
			_ASSERTE(hData != NULL);
			if ( hData != NULL )
			{
				BOOL oauthHeaderOk = HttpAddRequestHeaders(hData,
					oauthHeader.c_str(),
					oauthHeader.size(),
					0);
				_ASSERTE(oauthHeaderOk);

				// NOTE POST requests are supported, but the MIME type is hardcoded to application/x-www-form-urlencoded (aka. form data)
				// TODO implement support for posting image, raw or other data types
				string postDataUTF8;
				if(Compare(httpMethod, L&quot;POST&quot;, false) &amp;&amp; postParameters)
				{
					wstring contentHeader = L&quot;Content-Type: application/x-www-form-urlencoded\r\n&quot;;
					BOOL contentHeaderOk = HttpAddRequestHeaders(hData,
						contentHeader.c_str(),
						contentHeader.size(),
						0);
					_ASSERTE(contentHeaderOk);

					postDataUTF8 = WideToUTF8(BuildQueryString(*postParameters));
					_TRACE(&quot;POST DATA: %S&quot;, postDataUTF8.c_str());
				}

				BOOL sendOk = HttpSendRequest( hData, NULL, 0, (LPVOID)(postDataUTF8.size() &gt; 0 ? postDataUTF8.c_str() : NULL), postDataUTF8.size());
				_ASSERTE(sendOk);

				// TODO dynamically allocate return buffer
				BYTE buffer[1024*32] = {};
				DWORD dwRead = 0;
				while(
					InternetReadFile( hData, buffer, SIZEOF(buffer) - 1, &amp;dwRead ) &amp;&amp;
					dwRead &gt; 0
					)
				{
					buffer[dwRead] = 0;
					result += UTF8ToWide((char*)buffer);
				}

				_TRACE(&quot;%s&quot;, result.c_str());

				InternetCloseHandle(hData);
			}
			InternetCloseHandle(hConnection);
		}
		InternetCloseHandle(hINet);
	}

	return result;
}
</pre></p>
<p>Another minor cosmetic change, I extracted the OAuth header parameter formatting out into its own function <code>OAuthBuildHeader</code>.</p>
<p>Farther down you can see in the call to <code>HttpOpenRequest</code> I am no longer blindly passing <code>"GET"</code>, and instead am passing in the new <code>httpMethod</code> parameter value.  Currently <code>"GET"</code> and <code>"POST"</code> are the only values likely to work.</p>
<p>And finally, just before calling <code>HttpSendRequest</code>, we again check to see if we&#8217;re processing a <code>"POST"</code> request, and if so, we take care of a couple of tasks.</p>
<p>First, we need to add a header indicating the <a href="http://en.wikipedia.org/wiki/MIME#Content-Type">MIME type</a> of the data that we&#8217;ll be posting, in this case <a href="http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2.3"><code>application/x-www-form-urlencoded</code></a> which is the data format used for submitting forms on websites.</p>
<p>Next we need to format the POST parameters into the <code>application/x-www-form-urlencoded</code> data format, which is simple.  It&#8217;s essentially the same as the query part of an URL used in a GET request (<code>var1=blah&amp;var2=foo&amp;var3=john</code>).  This is taken care of by the helper function <code>BuildQueryString</code>:</p>
<p><pre class="brush: cpp;">// parameters must already be URL encoded before calling BuildQueryString
wstring BuildQueryString( const HTTPParameters &amp;parameters )
{
	wstring query;

	for(HTTPParameters::const_iterator it = parameters.begin();
		it != parameters.end();
		++it)
	{
		_TRACE(&quot;%s = %s&quot;, it-&gt;first.c_str(), it-&gt;second.c_str());

		if(it != parameters.begin())
		{
			query += L&quot;&amp;&quot;;
		}

		wstring pair;
		pair += it-&gt;first + L&quot;=&quot; + it-&gt;second + L&quot;&quot;;
		query += pair;
	}
	return query;
}
</pre></p>
<p>The resulting query string must then be UTF8 encoded.  When we send the query string as part of a GET request, the WinInet APIs convert the entire URL to UTF8 for us, parameters and all.  Not so with POST data, which WinInet treats as raw binary and will pass along unchanged.</p>
<p>I forgot to do this the first time, and just sent my wide string data buffer as the POST data.  This resulted in an invalid signature error from Twitter since the data was UTF8 encoded as part of the signing process and therefor the signature didn&#8217;t match the raw wide string data that I sent with the POST (and which wouldn&#8217;t have worked anyway since the twitter API would almost certainly only accept UTF8 encoded POST data).</p>
<p>Last but not least, we pass the UTF8 encoded form data string to <code>HttpSendRequest</code>, or pass <code>NULL</code> if there is no data to send.</p>
<h3>Tweeted</h3>
<p>And that should be it.  Assuming everything has gone right so far, you have just sent a tweet out into the twitterverse.  The return value from the call (if it succeeds) should be a copy of the full tweet in XML format.  One thing to note while testing is that (according to the Twitter API docs) multiple tweets in a row with exactly the same text will be ignored, so make sure to change it up each time.</p>
<p>Since <code>UrlEncode</code> converts to UTF8 as an intermediate format as part of the encoding process (when we first added the status text to the <code>HTTPParameters</code> object), Unicode status text should work fine.  I tested it with Japanese and had no problems, but I had to hard code the string as I wasn&#8217;t able to enter Japanese into my console window.  A utility I found in order to do the test without saving my source file in Unicode is <a href="http://rishida.net/tools/conversion/">Richard Ishida&#8217;s Unicode Code Converter</a>, which looks super handy for a variety of Unicode related tasks.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/codebrook.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/codebrook.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/codebrook.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/codebrook.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/codebrook.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/codebrook.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/codebrook.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/codebrook.wordpress.com/105/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=105&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://codebrook.wordpress.com/2010/09/01/twitter-oauth-in-c-for-win32-part-3-updating-twitter-status/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fd55ea5acd8b687070cc70baffc960e6?s=96&#38;d=identicon&#38;r=PG" medium="image">
			<media:title type="html">brookmiles</media:title>
		</media:content>
	</item>
		<item>
		<title>No Sockets for Windows Phone 7</title>
		<link>http://codebrook.wordpress.com/2010/07/20/no-sockets-for-windows-phone-7/</link>
		<comments>http://codebrook.wordpress.com/2010/07/20/no-sockets-for-windows-phone-7/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 23:00:54 +0000</pubDate>
		<dc:creator>Brook Miles</dc:creator>
				<category><![CDATA[IRC]]></category>
		<category><![CDATA[Windows Mobile]]></category>
		<category><![CDATA[Windows Phone 7]]></category>
		<category><![CDATA[internet relay chat]]></category>
		<category><![CDATA[irc]]></category>
		<category><![CDATA[sockets]]></category>
		<category><![CDATA[windows mobile]]></category>
		<category><![CDATA[windows phone 7]]></category>

		<guid isPermaLink="false">http://codebrook.wordpress.com/?p=101</guid>
		<description><![CDATA[So this weekend I was looking into some Windows Phone 7 development, with the intention of getting started on a WP7 port of Pocket IRC.  It was all progressing along handily until, much to my dismay, I discovered that the &#8230; <a href="http://codebrook.wordpress.com/2010/07/20/no-sockets-for-windows-phone-7/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=101&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So this weekend I was looking into some Windows Phone 7 development, with the intention of getting started on a WP7 port of Pocket IRC.  It was all progressing along handily until, much to my dismay, I discovered that the initial release of WP7 <a href="http://social.msdn.microsoft.com/Forums/en-US/windowsphone7series/thread/9d57e6f4-098c-457d-baa3-bc4af2b5e8c7">will not provide application level support for sockets</a>.  I&#8217;ve seen other more authoritative links on the subject, but can&#8217;t find them at the moment.</p>
<p>The only networking capability provided is via the <em><a href="http://msdn.microsoft.com/en-us/netframework/aa663324.aspx">Windows Communication Foundation</a>, <span style="font-style:normal;">a high level interface, which will provide only single request/response access to HTTP.</span></em></p>
<p><em><span style="font-style:normal;">So that means no IRC, or any other protocol which doesn&#8217;t operate over HTTP.  I&#8217;m not sure how email will be implemented, but I imagine over HTTP gateways or simply through APIs not exposed to 3rd party applications.</span></em></p>
<p>WP7 also doesn&#8217;t have multitasking support, repeating the historical choice of the earlier iPhones.  This is also a bit of a shot to connection oriented protocols like IRC, where disconnecting and reconnecting has a noticeably detrimental impact on the user experience.</p>
<p><em><span style="font-style:normal;"><em> </em>From the sound of various MS posts and comments, they do intend to add socket support eventually, but not in the first release.  For the sake of the platform I hope limitations like this will not kill it before MS  gets a chance to release all the features they want. </span></em></p>
<p>At this point it looks like my choices are, simply wait for a future revision of the Windows Phone platform, or waste time and effort implementing some hack temporary solution like an IRC client that operates over an HTTP gateway, which has it&#8217;s own problems, namely having to run an HTTP gateway.</p>
<p>Windows Phone 7 looks like it has potential, but I&#8217;m a bit worried about its chances against iPhone and Android if it&#8217;s coming out of the gate with such glaring limitations.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/codebrook.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/codebrook.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/codebrook.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/codebrook.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/codebrook.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/codebrook.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/codebrook.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/codebrook.wordpress.com/101/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=101&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://codebrook.wordpress.com/2010/07/20/no-sockets-for-windows-phone-7/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fd55ea5acd8b687070cc70baffc960e6?s=96&#38;d=identicon&#38;r=PG" medium="image">
			<media:title type="html">brookmiles</media:title>
		</media:content>
	</item>
		<item>
		<title>Twitter OAuth in C++ for Win32 &#8211; Part 2</title>
		<link>http://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/</link>
		<comments>http://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 22:50:04 +0000</pubDate>
		<dc:creator>Brook Miles</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[Win32]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[win32]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://codebrook.wordpress.com/?p=77</guid>
		<description><![CDATA[Part 1 covered the OAuth process at a high level, and Part 2 goes over the example code in what will likely turn out to be too much detail. The example project and source files are available on Google Code; &#8230; <a href="http://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=77&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://codebrook.wordpress.com/2010/07/08/twitter-oauth-in-cpp-for-win32/">Part 1</a> covered the OAuth process at a high level, and Part 2 goes over the example code in what will likely turn out to be too much detail.</p>
<p>The <a title="codebrook-twitter-oauth project files" href="https://code.google.com/p/codebrook-twitter-oauth/">example  project and source files</a> are available on Google Code; C++ code for Win32, with a Visual Studio 2008 project file.  <strong>Update:</strong> <a href="http://codebrook.wordpress.com/2010/09/01/twitter-oauth-in-c-for-win32-part-3-updating-twitter-status/">Part 3</a> builds on the code in this section, however the older code as discussed here is still available under tags/blog-part-2.</p>
<h3>Making OAuth Requests</h3>
<p>Now lets take a look at what <code>OAuthWebRequest</code> actually does.  The  steps are essentially the same for any request, however not all of the  parameters are used all the time.</p>
<p><span id="more-77"></span></p>
<p><pre class="brush: cpp;">
wstring OAuthWebRequest(
    const wstring&amp; url,
    const wstring&amp; httpMethod,
    const wstring&amp; consumerKey,
    const wstring&amp; consumerSecret,
    const wstring&amp; oauthToken = L&quot;&quot;,
    const wstring&amp; oauthTokenSecret = L&quot;&quot;,
    const wstring&amp; pin = L&quot;&quot;
    )
{
    wstring query = UrlGetQuery(url);
    OAuthParameters originalParameters = ParseQueryString(query);

    OAuthParameters oauthSignedParameters = BuildSignedOAuthParameters(
        originalParameters,
        url, httpMethod,
        consumerKey, consumerSecret,
        oauthToken, oauthTokenSecret,
        pin );
    return OAuthWebRequestSubmit(oauthSignedParameters, url);
}

</pre></p>
<p>The first step is pretty basic, we call <code>UrlGetQuery</code> which  simply extracts the &#8220;query&#8221; part from the provided URL, if any.  None of  the URLs we are using for this example actually need any parameters,  but I stuck some extras in one of them just to prove this code works:</p>
<p>http://twitter.com/oauth/request_token<strong>?some_other_parameter=hello&#038;another_one=goodbye</strong>#meep</p>
<p>The unused parameters will just be ignored by the API, but since  they&#8217;re there, they need to be properly included in the OAuth signature  process.</p>
<p><code>ParseQueryString</code> splits the query section of the URL up into  invidual key/value pairs and stores them in an <code>OAuthParameters</code>,  which is simply a typedef for a map of strings:</p>
<p><pre class="brush: cpp;">typedef std::map&lt;wstring, wstring&gt; OAuthParameters;</pre></p>
<p>We pass these parameters (if any) to <code>BuildSignedOAuthParameters</code> which generates all of the additional information that makes an OAuth  request OAuth and not just another HTTP call.</p>
<p><pre class="brush: cpp;">OAuthParameters BuildSignedOAuthParameters(
    const OAuthParameters&amp; requestParameters,
    const wstring&amp; url,
    const wstring&amp; httpMethod,
    const wstring&amp; consumerKey,
    const wstring&amp; consumerSecret,
    const wstring&amp; requestToken = L&quot;&quot;,
    const wstring&amp; requestTokenSecret = L&quot;&quot;,
    const wstring&amp; pin = L&quot;&quot; )
{
    wstring timestamp = OAuthCreateTimestamp();
    wstring nonce = OAuthCreateNonce();

    // create oauth requestParameters
    OAuthParameters oauthParameters;

    oauthParameters[L&quot;oauth_timestamp&quot;] = timestamp;
    oauthParameters[L&quot;oauth_nonce&quot;] = nonce;
    oauthParameters[L&quot;oauth_version&quot;] = L&quot;1.0&quot;;
    oauthParameters[L&quot;oauth_signature_method&quot;] = L&quot;HMAC-SHA1&quot;;
    oauthParameters[L&quot;oauth_consumer_key&quot;] = consumerKey;

    // add the request token if found
    if (!requestToken.empty())
    {
        oauthParameters[L&quot;oauth_token&quot;] = requestToken;
    }

    // add the authorization pin if found
    if (!pin.empty())
    {
        oauthParameters[L&quot;oauth_verifier&quot;] = pin;
    }

    // create a parameter list containing both oauth and original parameters
    // this will be used to create the parameter signature
    OAuthParameters allParameters = requestParameters;
    allParameters.insert(oauthParameters.begin(), oauthParameters.end());

    // prepare a signature base, a carefully formatted string containing
    // all of the necessary information needed to generate a valid signature
    wstring normalUrl = OAuthNormalizeUrl(url);
    wstring normalizedParameters = OAuthNormalizeRequestParameters(allParameters);
    wstring signatureBase = OAuthConcatenateRequestElements(httpMethod, normalUrl, normalizedParameters);

    // obtain a signature and add it to header requestParameters
    wstring signature = OAuthCreateSignature(signatureBase, consumerSecret, requestTokenSecret);
    oauthParameters[L&quot;oauth_signature&quot;] = signature;

    return oauthParameters;
}</pre></p>
<p>The first couple of steps are pretty straightforward, <code>OAuthCreateTimestamp</code> simply formats the current time value in seconds as a string, and <code>OAuthCreateNonce</code> creates a <a href="http://en.wikipedia.org/wiki/Cryptographic_nonce">nonce value</a>,  a random string of characters used only for this request.</p>
<p><pre class="brush: cpp;">wstring OAuthCreateNonce()
{
    wchar_t ALPHANUMERIC[] = L&quot;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&quot;;
    wstring nonce;

    for(int i = 0; i &lt;= 16; ++i)
    {
        nonce += ALPHANUMERIC[rand() % (SIZEOF(ALPHANUMERIC) - 1)]; // don't count null terminator in array
    }
    return nonce;
}

wstring OAuthCreateTimestamp()
{
    __time64_t utcNow;
    __time64_t ret = _time64(&amp;utcNow);
    _ASSERTE(ret != -1);

    wchar_t buf[100] = {};
    swprintf_s(buf, SIZEOF(buf), L&quot;%I64u&quot;, utcNow);

    return buf;
}</pre></p>
<p>Next, <code>BuildSignedOAuthParameters</code> collects the nonce and timestamp  value, along with the OAuth version we&#8217;re using, the signature method  (Twitter only accepts the HMAC-SHA1 signature method), and our Consumer  Key.  In addition, if requestToken is set (may contain either a <em>Request  Token</em> or <em>Access Token</em>) we add that into the list; and if a  PIN is provided for authorization, we add that as well.</p>
<p>We currently have two lists of parameters, one that contains anything  that was included in the original URL, and one that contains all of the  needed OAuth values.  We create a new set of parameters called  allParameters, which includes both lists.</p>
<p>Now that we have a master list of parameters, we begin constructing a  <a href="http://oauth.net/core/1.0a/#anchor13">Signature Base String</a>,  according to the OAuth specification.  Basically this is a single  string that combines the URL, the query and OAuth parameters, and the  HTTP method (&#8220;GET&#8221; or &#8220;POST&#8221;) in a known and re-producable format.  The  server is going to perform all of the same steps in an attempt to create  exactly the same string, and validate our signature.  If even a single  character is the wrong case, missing, or out of place, then the whole  signature will be invalidated, and the request will be rejected by the  server.</p>
<p>We pass our master parameter list to <code>OAuthNormalizeRequestParameters</code> which creates a single string containing all of the key/value pairs, in  sorted order.</p>
<p><pre class="brush: cpp;">wstring OAuthNormalizeRequestParameters( const OAuthParameters&amp; requestParameters )
{
    list&lt;wstring&gt; sorted;
    for(OAuthParameters::const_iterator it = requestParameters.begin();
        it != requestParameters.end();
        ++it)
    {
        wstring param = it-&gt;first + L&quot;=&quot; + it-&gt;second;
        sorted.push_back(param);
    }
    sorted.sort();

    wstring params;
    for(list&lt;wstring&gt;::iterator it = sorted.begin(); it != sorted.end(); ++it)
    {
        if(params.size() &gt; 0)
        {
            params += L&quot;&amp;&quot;;
        }
        params += *it;
    }

    return params;
}</pre></p>
<p>We also need to normalize the URL, which consists of stripping off  the query section, and making sure the port number is included if it&#8217;s  non-standard (eg. not 80 for HTTP), and NOT included if it IS standard.</p>
<p><pre class="brush: cpp;">wstring OAuthNormalizeUrl( const wstring&amp; url )
{
    wchar_t scheme[1024*4] = {};
    wchar_t host[1024*4] = {};
    wchar_t path[1024*4] = {};

    URL_COMPONENTS components = { sizeof(URL_COMPONENTS) };

    components.lpszScheme = scheme;
    components.dwSchemeLength = SIZEOF(scheme);

    components.lpszHostName = host;
    components.dwHostNameLength = SIZEOF(host);

    components.lpszUrlPath = path;
    components.dwUrlPathLength = SIZEOF(path);

    wstring normalUrl = url;

    BOOL crackUrlOk = InternetCrackUrl(url.c_str(), url.size(), 0, &amp;components);
    _ASSERTE(crackUrlOk);
    if(crackUrlOk)
    {
        wchar_t port[10] = {};

        // The port number must only be included if it is non-standard
        if((Compare(scheme, L&quot;http&quot;, false) &amp;&amp; components.nPort != 80) ||
            (Compare(scheme, L&quot;https&quot;, false) &amp;&amp; components.nPort != 443))
        {
            swprintf_s(port, SIZEOF(port), L&quot;:%u&quot;, components.nPort);
        }

        // InternetCrackUrl includes ? and # elements in the path,
        // which we need to strip off
        wstring pathOnly = path;
        wstring::size_type q = pathOnly.find_first_of(L&quot;#?&quot;);
        if(q != wstring::npos)
        {
            pathOnly = pathOnly.substr(0, q);
        }

        normalUrl = wstring(scheme) + L&quot;://&quot; + host + port + pathOnly;
    }
    return normalUrl;
}</pre></p>
<p><code>OAuthNormalizeUrl</code> splits apart the URL using <code>InternetCrackUrl</code>, and  then recombines only the parts we need.</p>
<p>We&#8217;ve got all our normalized information ready, so we can stick it  all together in a single string using <code>OAuthConcatenateRequestElements</code>,  first the HTTP method, then the normalized URL, then the normalized  parameters.</p>
<p><pre class="brush: cpp;">wstring OAuthConcatenateRequestElements( const wstring&amp; httpMethod, wstring url, const wstring&amp; parameters )
{
    wstring escapedUrl = UrlEncode(url);
    wstring escapedParameters = UrlEncode(parameters);

    wstring ret = httpMethod + L&quot;&amp;&quot; + escapedUrl + L&quot;&amp;&quot; + escapedParameters;
    return ret;
}
</pre></p>
<p>The URL and parameters need to be <a href="http://en.wikipedia.org/wiki/Percent-encoding">URL encoded</a> before they are concatenated.  OAuth has <a href="http://oauth.net/core/1.0a/#encoding_parameters">specific  requirements</a> about how this should be done, namely:</p>
<ol>
<li>Alphanumeric characters (letters and digits), as well as &#8211; . _ ~  (dash, period, underscore, and tilde), MUST NOT be encoded.  They must  remain as they are.  These are confusingly named the <em>Unreserved  Characters</em>.</li>
<li>All other characters MUST be encoded.</li>
<li>The resulting encoded hexadecimal values must be in UPPERCASE, %1A,  not %1a.</li>
</ol>
<p><pre class="brush: cpp;">// char2hex and urlencode from http://www.zedwood.com/article/111/cpp-urlencode-function
// modified according to http://oauth.net/core/1.0a/#encoding_parameters
//
//5.1.  Parameter Encoding
//
//All parameter names and values are escaped using the [RFC3986]
//percent-encoding (%xx) mechanism. Characters not in the unreserved character set
//MUST be encoded. Characters in the unreserved character set MUST NOT be encoded.
//Hexadecimal characters in encodings MUST be upper case.
//Text names and values MUST be encoded as UTF-8
// octets before percent-encoding them per [RFC3629].
//
//  unreserved = ALPHA, DIGIT, '-', '.', '_', '~'

string char2hex( char dec )
{
    char dig1 = (dec&amp;0xF0)&gt;&gt;4;
    char dig2 = (dec&amp;0x0F);
    if ( 0&lt;= dig1 &amp;&amp; dig1&lt;= 9) dig1+=48;    //0,48 in ascii
    if (10&lt;= dig1 &amp;&amp; dig1&lt;=15) dig1+=65-10; //A,65 in ascii
    if ( 0&lt;= dig2 &amp;&amp; dig2&lt;= 9) dig2+=48;
    if (10&lt;= dig2 &amp;&amp; dig2&lt;=15) dig2+=65-10;

    string r;
    r.append( &amp;dig1, 1);
    r.append( &amp;dig2, 1);
    return r;
}

string urlencode(const string &amp;c)
{

    string escaped;
    int max = c.length();
    for(int i=0; i&lt;max; i++)
    {
        if ( (48 &lt;= c[i] &amp;&amp; c[i] &lt;= 57) ||//0-9
            (65 &lt;= c[i] &amp;&amp; c[i] &lt;= 90) ||//ABC...XYZ
            (97 &lt;= c[i] &amp;&amp; c[i] &lt;= 122) || //abc...xyz
            (c[i]=='~' || c[i]=='-' || c[i]=='_' || c[i]=='.')
            )
        {
            escaped.append( &amp;c[i], 1);
        }
        else
        {
            escaped.append(&quot;%&quot;);
            escaped.append( char2hex(c[i]) );//converts char 255 to string &quot;FF&quot;
        }
    }
    return escaped;
}

wstring UrlEncode( const wstring&amp; url )
{
    return UTF8ToWide(urlencode(WideToUTF8(url)));
}

</pre></p>
<p>We&#8217;re almost there.  We have our signature base, and we need to sign  it, and add the signature to our list of OAuth parameters.  To do this  we call <code>OAuthCreateSignature</code>.</p>
<p><pre class="brush: cpp;">wstring OAuthCreateSignature( const wstring&amp; signatureBase, const wstring&amp; consumerSecret, const wstring&amp; requestTokenSecret )
{
    // URL encode key elements http://oauth.net/core/1.0/#anchor16
    wstring escapedConsumerSecret = UrlEncode(consumerSecret);
    wstring escapedTokenSecret = UrlEncode(requestTokenSecret);

    wstring key = escapedConsumerSecret + L&quot;&amp;&quot; + escapedTokenSecret;
    string keyBytes = WideToUTF8(key);

    string data = WideToUTF8(signatureBase);
    string hash = HMACSHA1(keyBytes, data);
    wstring signature = Base64String(hash);

    // You must encode the URI for safe net travel
    signature = UrlEncode(signature);
    return signature;
}</pre></p>
<p>To create the key for signing, we URL encode the <em>Consumer Secret</em>,  and the <em>Access Token Secret</em>, and then concatenate them with an  &amp;.  Then we pass this key data, and our signature base that we want  to sign, to <code>HMACSHA1</code> which will create a signature in the form of  a binary hash value.  The hash value is then <a href="http://en.wikipedia.org/wiki/Base64">Base64 encoded</a> and  then URL encoded, before being returned.  In the interest of keeping  this article from being even longer than it already is, I won&#8217;t include  the Base64 code here as it is nothing out of the ordinary, you can check  it out on the Google Code project in Base64Coder.cpp or the original  file <a href="http://support.microsoft.com/kb/191239">provided by Microsoft</a>.</p>
<p>HMACSHA1 gave me the most trouble, as I am not particularly well  versed in cryptographic subjects, and don&#8217;t recall ever using the Crypto  API before.  Ultimately, my solution was based on this delightful  example on MSDN, <a href="http://msdn.microsoft.com/en-us/library/aa382379%28v=VS.85%29.aspx">Example  C Program: Creating an HMAC</a>, with a key change (oh, a pun!) to how  the key is created, based on a NetBSD support source file of all places,  <a href="http://mirror.leaseweb.com/NetBSD/NetBSD-release-5-0/src/dist/wpa/src/crypto/crypto_cryptoapi.c">crypto_cryptoapi.c</a></p>
<p>Presented for you in all it&#8217;s terrible glory, <code>HMACSHA1</code>&#8230;</p>
<p><pre class="brush: cpp;">string HMACSHA1( const string&amp; keyBytes, const string&amp; data )
{
    // based on http://msdn.microsoft.com/en-us/library/aa382379%28v=VS.85%29.aspx

    string hash;

    //--------------------------------------------------------------------
    // Declare variables.
    //
    // hProv:           Handle to a cryptographic service provider (CSP).
    //                  This example retrieves the default provider for
    //                  the PROV_RSA_FULL provider type.
    // hHash:           Handle to the hash object needed to create a hash.
    // hKey:            Handle to a symmetric key. This example creates a
    //                  key for the RC4 algorithm.
    // hHmacHash:       Handle to an HMAC hash.
    // pbHash:          Pointer to the hash.
    // dwDataLen:       Length, in bytes, of the hash.
    // Data1:           Password string used to create a symmetric key.
    // Data2:           Message string to be hashed.
    // HmacInfo:        Instance of an HMAC_INFO structure that contains
    //                  information about the HMAC hash.
    //
    HCRYPTPROV  hProv       = NULL;
    HCRYPTHASH  hHash       = NULL;
    HCRYPTKEY   hKey        = NULL;
    HCRYPTHASH  hHmacHash   = NULL;
    PBYTE       pbHash      = NULL;
    DWORD       dwDataLen   = 0;
    //BYTE        Data1[]     = {0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64};
    //BYTE        Data2[]     = {0x6D,0x65,0x73,0x73,0x61,0x67,0x65};
    HMAC_INFO   HmacInfo;

    //--------------------------------------------------------------------
    // Zero the HMAC_INFO structure and use the SHA1 algorithm for
    // hashing.

    ZeroMemory(&amp;HmacInfo, sizeof(HmacInfo));
    HmacInfo.HashAlgid = CALG_SHA1;

    //--------------------------------------------------------------------
    // Acquire a handle to the default RSA cryptographic service provider.

    if (!CryptAcquireContext(
        &amp;hProv,                   // handle of the CSP
        NULL,                     // key container name
        NULL,                     // CSP name
        PROV_RSA_FULL,            // provider type
        CRYPT_VERIFYCONTEXT))     // no key access is requested
    {
        _TRACE(&quot; Error in AcquireContext 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    //--------------------------------------------------------------------
    // Derive a symmetric key from a hash object by performing the
    // following steps:
    //    1. Call CryptCreateHash to retrieve a handle to a hash object.
    //    2. Call CryptHashData to add a text string (password) to the
    //       hash object.
    //    3. Call CryptDeriveKey to create the symmetric key from the
    //       hashed password derived in step 2.
    // You will use the key later to create an HMAC hash object.

    if (!CryptCreateHash(
        hProv,                    // handle of the CSP
        CALG_SHA1,                // hash algorithm to use
        0,                        // hash key
        0,                        // reserved
        &amp;hHash))                  // address of hash object handle
    {
        _TRACE(&quot;Error in CryptCreateHash 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    if (!CryptHashData(
        hHash,                    // handle of the hash object
        (BYTE*)keyBytes.c_str(),                    // password to hash
        keyBytes.size(),            // number of bytes of data to add
        0))                       // flags
    {
        _TRACE(&quot;Error in CryptHashData 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    // key creation based on
    // http://mirror.leaseweb.com/NetBSD/NetBSD-release-5-0/src/dist/wpa/src/crypto/crypto_cryptoapi.c
    struct {
        BLOBHEADER hdr;
        DWORD len;
        BYTE key[1024]; // TODO might want to dynamically allocate this, Should Be Fine though
    } key_blob;

    key_blob.hdr.bType = PLAINTEXTKEYBLOB;
    key_blob.hdr.bVersion = CUR_BLOB_VERSION;
    key_blob.hdr.reserved = 0;
    /*
    * Note: RC2 is not really used, but that can be used to
    * import HMAC keys of up to 16 byte long.
    * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
    * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
    */
    key_blob.hdr.aiKeyAlg = CALG_RC2;
    key_blob.len = keyBytes.size();
    ZeroMemory(key_blob.key, sizeof(key_blob.key));

    _ASSERTE(keyBytes.size() &lt;= SIZEOF(key_blob.key));
    CopyMemory(key_blob.key, keyBytes.c_str(), min(keyBytes.size(), SIZEOF(key_blob.key)));

    if (!CryptImportKey(
        hProv,
        (BYTE *)&amp;key_blob,
        sizeof(key_blob),
        0,
        CRYPT_IPSEC_HMAC_KEY,
        &amp;hKey))
    {
        _TRACE(&quot;Error in CryptImportKey 0x%08x \n&quot;, GetLastError());
        goto ErrorExit;
    }

    //--------------------------------------------------------------------
    // Create an HMAC by performing the following steps:
    //    1. Call CryptCreateHash to create a hash object and retrieve
    //       a handle to it.
    //    2. Call CryptSetHashParam to set the instance of the HMAC_INFO
    //       structure into the hash object.
    //    3. Call CryptHashData to compute a hash of the message.
    //    4. Call CryptGetHashParam to retrieve the size, in bytes, of
    //       the hash.
    //    5. Call malloc to allocate memory for the hash.
    //    6. Call CryptGetHashParam again to retrieve the HMAC hash.

    if (!CryptCreateHash(
        hProv,                    // handle of the CSP.
        CALG_HMAC,                // HMAC hash algorithm ID
        hKey,                     // key for the hash (see above)
        0,                        // reserved
        &amp;hHmacHash))              // address of the hash handle
    {
        _TRACE(&quot;Error in CryptCreateHash 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    if (!CryptSetHashParam(
        hHmacHash,                // handle of the HMAC hash object
        HP_HMAC_INFO,             // setting an HMAC_INFO object
        (BYTE*)&amp;HmacInfo,         // the HMAC_INFO object
        0))                       // reserved
    {
        _TRACE(&quot;Error in CryptSetHashParam 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    if (!CryptHashData(
        hHmacHash,                // handle of the HMAC hash object
        (BYTE*)data.c_str(),                    // message to hash
        data.size(),            // number of bytes of data to add
        0))                       // flags
    {
        _TRACE(&quot;Error in CryptHashData 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    //--------------------------------------------------------------------
    // Call CryptGetHashParam twice. Call it the first time to retrieve
    // the size, in bytes, of the hash. Allocate memory. Then call
    // CryptGetHashParam again to retrieve the hash value.

    if (!CryptGetHashParam(
        hHmacHash,                // handle of the HMAC hash object
        HP_HASHVAL,               // query on the hash value
        NULL,                     // filled on second call
        &amp;dwDataLen,               // length, in bytes, of the hash
        0))
    {
        _TRACE(&quot;Error in CryptGetHashParam 0x%08x \n&quot;,
            GetLastError());
        goto ErrorExit;
    }

    pbHash = (BYTE*)malloc(dwDataLen);
    if(NULL == pbHash)
    {
        _TRACE(&quot;unable to allocate memory\n&quot;);
        goto ErrorExit;
    }

    if (!CryptGetHashParam(
        hHmacHash,                 // handle of the HMAC hash object
        HP_HASHVAL,                // query on the hash value
        pbHash,                    // pointer to the HMAC hash value
        &amp;dwDataLen,                // length, in bytes, of the hash
        0))
    {
        _TRACE(&quot;Error in CryptGetHashParam 0x%08x \n&quot;, GetLastError());
        goto ErrorExit;
    }

    for(DWORD i = 0 ; i &lt; dwDataLen ; i++)
    {
        hash.push_back((char)pbHash[i]);
    }

    // Free resources.
    // lol goto
ErrorExit:
    if(hHmacHash)
        CryptDestroyHash(hHmacHash);
    if(hKey)
        CryptDestroyKey(hKey);
    if(hHash)
        CryptDestroyHash(hHash);
    if(hProv)
        CryptReleaseContext(hProv, 0);
    if(pbHash)
        free(pbHash);

    return hash;
}</pre></p>
<p>Note in particular the use of <code>CryptImportKey</code> to use the key  data we provide, instead of using <code>CryptDeriveKey</code> to create one as  is done in the MSDN example.</p>
<p>Phew!  The hard stuff is all done.  As mentioned earlier, the signed  hash is Base64 encoded, then URL encoded, and passed back to <code>BuildSignedOAuthParameters</code> which adds it to the list of OAuth parameters, and returns the final  signed list.</p>
<p>All we need to do now is pass the signed list of OAuth parameters,  and the original URL to <code>OAuthWebRequestSubmit</code> to actually make  the HTTP connection, and get the reply.</p>
<p><pre class="brush: cpp;">wstring OAuthWebRequestSubmit(
                              const OAuthParameters&amp; parameters,
                              const wstring&amp; url
                              )
{
    _TRACE(&quot;OAuthWebRequestSubmit(%s)&quot;, url.c_str());

    wstring oauthHeader = L&quot;Authorization: OAuth &quot;;

    for(OAuthParameters::const_iterator it = parameters.begin();
        it != parameters.end();
        ++it)
    {
        _TRACE(&quot;%s = %s&quot;, it-&gt;first.c_str(), it-&gt;second.c_str());

        if(it != parameters.begin())
        {
            oauthHeader += L&quot;,&quot;;
        }

        wstring pair;
        pair += it-&gt;first + L&quot;=\&quot;&quot; + it-&gt;second + L&quot;\&quot;&quot;;
        oauthHeader += pair;
    }
    oauthHeader += L&quot;\r\n&quot;;

    _TRACE(&quot;%s&quot;, oauthHeader.c_str());

    wchar_t host[1024*4] = {};
    wchar_t path[1024*4] = {};

    URL_COMPONENTS components = { sizeof(URL_COMPONENTS) };

    components.lpszHostName = host;
    components.dwHostNameLength = SIZEOF(host);

    components.lpszUrlPath = path;
    components.dwUrlPathLength = SIZEOF(path);

    wstring normalUrl = url;

    BOOL crackUrlOk = InternetCrackUrl(url.c_str(), url.size(), 0, &amp;components);
    _ASSERTE(crackUrlOk);

    wstring result;

    // TODO you'd probably want to InternetOpen only once at app initialization
    HINTERNET hINet = InternetOpen(L&quot;tc2/1.0&quot;,
        INTERNET_OPEN_TYPE_PRECONFIG,
        NULL,
        NULL,
        0 );
    _ASSERTE( hINet != NULL );
    if ( hINet != NULL )
    {
        // TODO add support for HTTPS requests
        HINTERNET hConnection = InternetConnect(
            hINet,
            host,
            components.nPort,
            NULL,
            NULL,
            INTERNET_SERVICE_HTTP,
            0, 0 );
        _ASSERTE(hConnection != NULL);
        if ( hConnection != NULL)
        {
            // TODO add support for handling POST requests
            HINTERNET hData = HttpOpenRequest( hConnection,
                L&quot;GET&quot;,
                path,
                NULL,
                NULL,
                NULL,
                INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_RELOAD,
                0 );
            _ASSERTE(hData != NULL);
            if ( hData != NULL )
            {
                BOOL addHeadersOk = HttpAddRequestHeaders(hData,
                    oauthHeader.c_str(),
                    oauthHeader.size(),
                    0);
                _ASSERTE(addHeadersOk);

                BOOL sendOk = HttpSendRequest( hData, NULL, 0, NULL, 0);
                _ASSERTE(sendOk);

                BYTE buffer[1024*32] = {};
                DWORD dwRead = 0;
                while(
                    InternetReadFile( hData, buffer, SIZEOF(buffer) - 1, &amp;dwRead ) &amp;&amp;
                    dwRead &gt; 0
                    )
                {
                    buffer[dwRead] = 0;
                    result += UTF8ToWide((char*)buffer);
                }

                _TRACE(&quot;%s&quot;, result.c_str());

                InternetCloseHandle(hData);
            }
            InternetCloseHandle(hConnection);
        }
        InternetCloseHandle(hINet);
    }

    return result;
}</pre></p>
<p>Notice that the OAuth parameters are all provided as part of a custom  header named &#8220;Authorization: &#8220;.  The query parameters, while they were  included in the OAuth signing process, are not sent as part of the OAuth  custom header, they are sent as usual in the path of the &#8220;GET&#8221; request  (or in the body of the request if using &#8220;POST&#8221;).</p>
<p>The result is read into a buffer, and then returned.  The result will  be truncated at 32KB because I was lazy.  You&#8217;ll want to allocate it  dynamically.  The example code also doesn&#8217;t deal with any of the  possible HTTP responses, or other WinInet error codes.</p>
<h3>The End</h3>
<p>And that&#8217;s all there is to it!  Ok, it was a bit longer than I  expected.  The response you get back from the web request, obviously  depends on what URL you requested.  You might get back a <em>Request  Token</em>, or an <em>Access Token</em>, the user&#8217;s feed, or possibly an  error code or other result.</p>
<p>The <a href="http://dev.twitter.com/doc">Twitter API Documentation</a> awaits.</p>
<p><strong>Update:</strong> <a href="http://codebrook.wordpress.com/2010/09/01/twitter-oauth-in-c-for-win32-part-3-updating-twitter-status/">Part 3</a> covers POST requests and updating your twitter status.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/codebrook.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/codebrook.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/codebrook.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/codebrook.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/codebrook.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/codebrook.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/codebrook.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/codebrook.wordpress.com/77/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=77&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fd55ea5acd8b687070cc70baffc960e6?s=96&#38;d=identicon&#38;r=PG" medium="image">
			<media:title type="html">brookmiles</media:title>
		</media:content>
	</item>
		<item>
		<title>Twitter OAuth in C++ for Win32</title>
		<link>http://codebrook.wordpress.com/2010/07/08/twitter-oauth-in-cpp-for-win32/</link>
		<comments>http://codebrook.wordpress.com/2010/07/08/twitter-oauth-in-cpp-for-win32/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 03:19:14 +0000</pubDate>
		<dc:creator>Brook Miles</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[win32]]></category>

		<guid isPermaLink="false">http://codebrook.wordpress.com/?p=43</guid>
		<description><![CDATA[The Problem There seems to be lackluster support for Twitter in the C++ community.  I haven&#8217;t yet seen a single Twitter client for Windows written in C++ that was&#8230; acceptable. Accessing the Twitter API using Basic Authentication is pretty straightforward, &#8230; <a href="http://codebrook.wordpress.com/2010/07/08/twitter-oauth-in-cpp-for-win32/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=43&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h1>The Problem</h1>
<p>There seems to be lackluster support for Twitter in the C++ community.  I haven&#8217;t yet seen a single Twitter client for Windows  written in C++ that was&#8230; acceptable.</p>
<p>Accessing the Twitter API using Basic Authentication is pretty straightforward, however <a href="http://countdowntooauth.com/">Basic Authentication is going to be turned off</a> on <strong>August 16th, 2010</strong> (last I checked), and after that will require all applications to use <a title="Twitter OAuth FAQ" href="http://dev.twitter.com/pages/oauth_faq"> OAuth</a>.</p>
<p>Having looked into what it would take to implement OAuth, I&#8217;m not  surprised that few people have jumped at the opportunity to do so.   I had to scrounge around the net for several hours in order to piece  together the necessary information and code required to implement bare  bones OAuth functionality in C++, it&#8217;s fairly involved, and not at all  well documented.</p>
<h2>Existing Libraries</h2>
<p>There are currently only two C++ Twitter libraries listed on Twitter&#8217;s <a href="http://dev.twitter.com/pages/libraries">library list</a>, <a href="http://twitlib.googlecode.com/">QTwitLib</a>, and <a href="http://code.google.com/p/twitcurl/">Twitcurl</a>.  Neither appears to be under active development, they&#8217;re both GPL (which I&#8217;m not a big fan of), QTwitLib uses Qt (which I&#8217;m not a big fan of), and neither support OAuth anyway.</p>
<p>There is only one C++ OAuth library, <a href="http://liboauth.sourceforge.net/">liboauth</a>, listed on Twitter&#8217;s <a href="http://dev.twitter.com/pages/oauth_libraries">OAuth library list</a>, and it requires <a href="http://www.openssl.org/">OpenSSL</a> or Mozilla&#8217;s <a href="http://www.mozilla.org/projects/security/pki/nss/">NSS</a>.  OpenSSL requires Perl and NASM to be installed to build, and while I haven&#8217;t looked at NSS much, it doesn&#8217;t appear to be sync-and-go either.  At least liboauth is available under an MIT License, so this is something I might return to later.  It might be possible to remove HTTPS support and drop the dependencies without too much headache.</p>
<h1>The Solution</h1>
<p>So the perfectly rational (and conveniently most interesting) solution, is to try and write up some OAuth code from scratch&#8230; or from bits and pieces anyway.  Be warned, this isn&#8217;t going to be pretty.</p>
<p><span id="more-43"></span></p>
<h2>Register Your App</h2>
<p>The project should work out of the box, as I&#8217;ve included test keys registered to me that will work just fine, however if you&#8217;re going to alter the program at all, it would be better to register your own application that way I won&#8217;t get all the credit/blame, it&#8217;s quick and easy.</p>
<p>Log into Twitter&#8217;s website and hit their <a href="http://twitter.com/oauth_clients/new">Register An Application</a> page.  Choose a name for your app (you can change it later), and it can&#8217;t include the word &#8220;twitter&#8221;.  Select &#8220;Client&#8221; not &#8220;Browser&#8221;, choose &#8220;Read &amp; Write&#8221; (if you want to be able to post), and you can leave &#8220;Use Twitter for login&#8221; unchecked.</p>
<p>Once your application is created, make a note of the Consumer Key and Consumer Secret, these can be found under the Application Detail link from the application edit page.  These values uniquely identify your program to Twitter.</p>
<h2>Download The Code</h2>
<p>The <a title="codebrook-twitter-oauth project files" href="https://code.google.com/p/codebrook-twitter-oauth/">example project and source files</a> are available on Google Code.<a title="Example Project" href="http://code.google.com/p/twitter-oauth-example/"></a></p>
<p>The code is C++ for Win32, with a Visual Studio 2008 project file.</p>
<h2>Use The Code</h2>
<p>The code I&#8217;ve provided is not great and only superficially tested, please do not actually use it for anything, although you&#8217;re free to do so at your own risk.  I wrote it mostly in a single 8 hour stretch on a Friday night (yay Dr. Pepper), all the while googling for docs and samples on OAuth, and trying to figure out how to calculate an HMAC-SH1 hash.  That being said, it does work more or less.</p>
<p>Take your Consumer Key and Consumer Secret you got when you <a href="http://dev.twitter.com/apps">registered your app</a>, and plug them into the similarly named variables at the top of <code>tc2.cpp</code>:</p>
<p><pre class="brush: cpp; light: true;">wstring ConsumerKey = L&quot;abc&quot;;
wstring ConsumerSecret = L&quot;ABC&quot;;</pre></p>
<p>At this point you should be able to compile and run the program.  I didn&#8217;t originally intend for it to have a user interface at all, so I recommend running it in Debug mode under a debugger, as helpful trace information is displayed in the debug output window.</p>
<ol>
<li>When you run the application, it will attempt to connect to twitter, launch the Twitter authorization page in your web browser, and then prompt you on the console to enter the PIN that will be provided to you on the Twitter website.</li>
<li>Go to your browser (it may not come to the foreground automatically) and find the authorization page that may have opened in a new tab.  If your browser didn&#8217;t load the authorization page at all, look in the console window for &#8220;Launching http://twitter.com&#8230;.&#8221; and copy and paste the entire URL into your browser.</li>
<li>On the authorization page, Allow your application access to your Twitter account, after which you will be provided the PIN.</li>
<li>Type the pin into the console app and hit Enter.  The app will display the authorization information, and then request your user timeline, dumping it in XML on the console.</li>
</ol>
<p>Now that you&#8217;ve gone through this process once, the program will have saved your authorization to a file called <code>tc2_saved.txt</code> in the current directory (probably the project directory).  The next time you run the program, instead of re-authorizing with Twitter, it will simply re-load access token that was saved last time, and access your user time-line directly.</p>
<p>If you want to re-run the authorization flow, just delete <code>tc2_saved.txt</code>.</p>
<p><strong>Anyone that has access to the contents of the saved authorization file can post as you on Twitter.</strong> This also goes for debug traces or other output that includes any access tokens and secrets.</p>
<h2>High Level Flow</h2>
<p>Stepping through the code will be the best way to figure it out, the app isn&#8217;t that big so it won&#8217;t take too long, but I&#8217;ll try to give a general overview of what&#8217;s going on.</p>
<p><strong>OAuthWebRequest</strong> is the workhorse of the example application, every request we make to the Twitter API is through this function.</p>
<ol>
<li>We call <strong>OAuthWebRequest</strong> on http://twitter.com/<strong>oauth/request_token</strong>, providing only our <em>Consumer Key</em> and <em>Consumer Secret</em>.  The reply from request_token gives us a temporary <em>Request Token</em> consisting of &#8220;oauth_token&#8221; and &#8220;oauth_token_secret&#8221;.</li>
<li>We launch a web browser to http://twitter.com/<strong>oauth/authorize?oauth_token=ABC123</strong> and pass in the value of &#8220;oauth_token&#8221;.  The user authorizes the app and they are given a PIN number which they enter into our app.</li>
<li>We call <strong>OAuthWebRequest</strong> on http://twitter.com/<strong>oauth/access_token</strong> providing our temporary <em>Request Token</em> plus the PIN number we got from the user, and we get back our permanent <em>Access Token</em> values, &#8220;oauth_token&#8221; and &#8220;oauth_token_secret&#8221;.  We save our <em>Access Token</em> to disk for future use.</li>
<li>We can now call <strong>OAuthWebRequest</strong> whenever we want to access the Twitter API as the authorized user by using the saved <em>Access Token</em>.  In the example, we just request the user&#8217;s main timeline at http://twitter.com/<strong>statuses/user_timeline.xml</strong> and then dump it to the screen.<strong><br />
</strong></li>
</ol>
<p>However most of the &#8220;OAuth stuff&#8221; happens in <strong>BuildSignedOAuthParameters</strong> which generates all of the  additional information that makes an OAuth  request what it is, and not just  another HTTP call.</p>
<p>I&#8217;ll leave things at that for now, and may go over the code in more thorough details in a follow up post, or on the Google Code project wiki.</p>
<p><strong>Update:</strong> Continue to <a href="http://codebrook.wordpress.com/2010/07/14/twitter-oauth-in-c-for-win32-part-2/">Part 2</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/codebrook.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/codebrook.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/codebrook.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/codebrook.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/codebrook.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/codebrook.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/codebrook.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/codebrook.wordpress.com/43/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=43&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://codebrook.wordpress.com/2010/07/08/twitter-oauth-in-cpp-for-win32/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fd55ea5acd8b687070cc70baffc960e6?s=96&#38;d=identicon&#38;r=PG" medium="image">
			<media:title type="html">brookmiles</media:title>
		</media:content>
	</item>
		<item>
		<title>Why are Twitter Clients all AIR or .NET?</title>
		<link>http://codebrook.wordpress.com/2010/07/05/why-are-twitter-clients-all-air-or-net/</link>
		<comments>http://codebrook.wordpress.com/2010/07/05/why-are-twitter-clients-all-air-or-net/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 03:06:35 +0000</pubDate>
		<dc:creator>Brook Miles</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[air]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://codebrook.wordpress.com/?p=55</guid>
		<description><![CDATA[I currently use twhirl, because it&#8217;s the only Twitter client I&#8217;ve found for Windows so far that I can stand.  It&#8217;s simple, unintrusive, single column, and just generally looks decent and works well.  There are a few problems though&#8230; 1) &#8230; <a href="http://codebrook.wordpress.com/2010/07/05/why-are-twitter-clients-all-air-or-net/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=55&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I currently use <a href="http://www.twhirl.org/">twhirl</a>, because it&#8217;s the only Twitter client I&#8217;ve found for Windows so far that I can stand.  It&#8217;s simple,  unintrusive,  single column, and just generally looks decent <span style="text-decoration:line-through;">and  works well</span>.  There are a few problems though&#8230;</p>
<p>1) It&#8217;s written in Adobe AIR.  Task Manager reveals that twhirl is  second only to Outlook in using up my precious, precious RAM.</p>
<div class="wp-caption aligncenter" style="width: 338px"><a href="http://codebrook.files.wordpress.com/2010/07/20100704-170202.png"><img title="Twhirl Memory Use" src="http://codebrook.files.wordpress.com/2010/07/20100704-170202.png?w=328&#038;h=215" alt="Task Manager Screenshot" width="328" height="215" /></a><p class="wp-caption-text">AIR <img src='http://s0.wp.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p></div>
<p>I  might overlook this if I were running it on my main PC with 4GB (the  future is now!), but I run email, IRC, messaging clients, etc. on my  laptop which has only 1GB.</p>
<p>Which reminds me of <a href="http://destroytwitter.com/">DestroyTwitter</a> which boasts, among other things, of having &#8220;an <strong>unbelievably  small</strong> footprint&#8221;.  How does memory usage of as low as 25MB sound?   Pretty believable, and a bit high for something that only has to display  a few lines of text and some icons.</p>
<div class="wp-caption aligncenter" style="width: 256px"><a href="http://codebrook.files.wordpress.com/2010/07/20100704-172656.png"><img title="Powerful and Lightweight" src="http://codebrook.files.wordpress.com/2010/07/20100704-172656.png?w=246&#038;h=113" alt="Destroy Twitter Website" width="246" height="113" /></a><p class="wp-caption-text">That&#039;s unpossible!</p></div>
<p>2)  It&#8217;s out of date, doesn&#8217;t support  the new ReTweet  functionality for  example, and doesn&#8217;t appear to be under active development, as Seesmic  has moved on to <a href="http://seesmic.com/seesmic_desktop/">Seesmic Desktop</a>.   Recently I&#8217;ve been discovering other bugs, that I just didn&#8217;t notice  before or because the Twitter API is changing in subtle ways that twhirl  isn&#8217;t liking.</p>
<p>3) And the final nail in the coffin, as far as I know, there are no  plans to add OAuth support to twhirl.  Which is going to become a problem on August 16th, when Twitter disables basic authentication and requires all clients to use OAuth.</p>
<p>I think it&#8217;s about time the C++ community took a hint from apps like uTorrent, and started developing lightweight native Twitter clients for Windows.</p>
<p><strong>Update:</strong> Oops, I had said DestroyTwitter is .NET, it&#8217;s actually AIR too.  A few other clients, like <a href="http://www.thirteen23.com/experiences/desktop/blu/">Blu</a> and <a href="http://seesmic.com/seesmic_desktop/windows/features/">Seesmic for Windows</a> are .NET.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/codebrook.wordpress.com/55/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/codebrook.wordpress.com/55/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/codebrook.wordpress.com/55/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/codebrook.wordpress.com/55/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/codebrook.wordpress.com/55/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/codebrook.wordpress.com/55/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/codebrook.wordpress.com/55/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/codebrook.wordpress.com/55/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=55&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://codebrook.wordpress.com/2010/07/05/why-are-twitter-clients-all-air-or-net/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fd55ea5acd8b687070cc70baffc960e6?s=96&#38;d=identicon&#38;r=PG" medium="image">
			<media:title type="html">brookmiles</media:title>
		</media:content>

		<media:content url="http://codebrook.files.wordpress.com/2010/07/20100704-170202.png" medium="image">
			<media:title type="html">Twhirl Memory Use</media:title>
		</media:content>

		<media:content url="http://codebrook.files.wordpress.com/2010/07/20100704-172656.png" medium="image">
			<media:title type="html">Powerful and Lightweight</media:title>
		</media:content>
	</item>
		<item>
		<title>Pocket IRC is now free</title>
		<link>http://codebrook.wordpress.com/2010/06/24/pocket-irc-is-now-free/</link>
		<comments>http://codebrook.wordpress.com/2010/06/24/pocket-irc-is-now-free/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 04:19:17 +0000</pubDate>
		<dc:creator>Brook Miles</dc:creator>
				<category><![CDATA[IRC]]></category>
		<category><![CDATA[Windows Mobile]]></category>
		<category><![CDATA[internet relay chat]]></category>
		<category><![CDATA[irc]]></category>
		<category><![CDATA[pocket pc]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[windows mobile]]></category>

		<guid isPermaLink="false">http://codebrook.wordpress.com/?p=9</guid>
		<description><![CDATA[Pocket IRC my IRC client for Pocket PC and Windows Mobile devices.  Version 1.3 has been released removing registration requirements and is now available for free, previously $14.95 USD. This release doesn&#8217;t add a lot of new functionality, but it &#8230; <a href="http://codebrook.wordpress.com/2010/06/24/pocket-irc-is-now-free/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=9&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div id="attachment_24" class="wp-caption alignright" style="width: 235px"><a href="http://codebrook.files.wordpress.com/2010/06/bs-20100624-202315.png"><img class="size-medium wp-image-24 " title="Pocket IRC screenshot in VGA on a Dell Axim X51v" src="http://codebrook.files.wordpress.com/2010/06/bs-20100624-202315.png?w=225&#038;h=300" alt="Pocket IRC screenshot in VGA on a Dell Axim X51v" width="225" height="300" /></a><p class="wp-caption-text">Pocket IRC on Windows Mobile 5</p></div>
<p><a href="http://pocketirc.com">Pocket IRC</a> my IRC client for Pocket PC and Windows Mobile devices.  Version 1.3 has been released removing registration requirements and is now available for free, previously $14.95 USD.</p>
<p>This release doesn&#8217;t add a lot of new functionality, but it had significant re-factoring internally a couple of years ago, and not a whole lot of testing since then, so fingers crossed.</p>
<p>The free release is a stepping stone to open sourcing the code.  I haven&#8217;t decided yet where or how I&#8217;ll be releasing the source, so in the meantime I figured I might as well make it free.  Likely it will be a public read-only SVN repository, maybe on Google Code, and probably under an MIT or similar license.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/codebrook.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/codebrook.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/codebrook.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/codebrook.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/codebrook.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/codebrook.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/codebrook.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/codebrook.wordpress.com/9/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=codebrook.wordpress.com&amp;blog=14343736&amp;post=9&amp;subd=codebrook&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://codebrook.wordpress.com/2010/06/24/pocket-irc-is-now-free/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/fd55ea5acd8b687070cc70baffc960e6?s=96&#38;d=identicon&#38;r=PG" medium="image">
			<media:title type="html">brookmiles</media:title>
		</media:content>

		<media:content url="http://codebrook.files.wordpress.com/2010/06/bs-20100624-202315.png?w=225" medium="image">
			<media:title type="html">Pocket IRC screenshot in VGA on a Dell Axim X51v</media:title>
		</media:content>
	</item>
	</channel>
</rss>
