Twitter with OAuth Example.\\ see also http://www.soramimi.jp/twicpp/index.html

Dependencies:   mbed HTTPClient NTPClient_NetServices EthernetNetIf

Files at this revision

API Documentation at this revision

Comitter:
soramimi
Date:
Wed Mar 23 19:53:42 2011 +0000
Child:
1:c3f74457cad4
Commit message:

Changed in this revision

EthernetNetIf.lib Show annotated file Show diff for this revision Revisions of this file
HTTPClient.lib Show annotated file Show diff for this revision Revisions of this file
NTPClient.lib Show annotated file Show diff for this revision Revisions of this file
hash.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
oauth.cpp Show annotated file Show diff for this revision Revisions of this file
oauth.h Show annotated file Show diff for this revision Revisions of this file
oauth_http.cpp Show annotated file Show diff for this revision Revisions of this file
sha1.c Show annotated file Show diff for this revision Revisions of this file
sha1.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mamezu/code/EthernetNetIf/#0f6c82fcde82
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPClient.lib	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mamezu/code/HTTPClient/#62fac7f06c8d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient.lib	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/NTPClient/#7c3f1199256a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hash.cpp	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,56 @@
+
+#include "oauth.h" // base64 encode fn's.
+#include "sha1.h"
+
+#include <string.h>
+
+void hmac_sha1(unsigned char const *key, size_t keylen, unsigned char const *in, size_t inlen, unsigned char *resbuf)
+{
+    struct SHA1Context inner;
+    struct SHA1Context outer;
+    unsigned char tmpkey[20];
+    unsigned char digest[20];
+    unsigned char block[64];
+
+    const int IPAD = 0x36;
+    const int OPAD = 0x5c;
+
+    if (keylen > 64) {
+        struct SHA1Context keyhash;
+        SHA1Reset(&keyhash);
+        SHA1Input(&keyhash, key, keylen);
+        SHA1Result(&keyhash, tmpkey);
+        key = tmpkey;
+        keylen = 20;
+    }
+
+    for (size_t i = 0; i < sizeof(block); i++) {
+        block[i] = IPAD ^ (i < keylen ? key[i] : 0);
+    }
+    SHA1Reset(&inner);
+    SHA1Input(&inner, block, 64);
+    SHA1Input(&inner, in, inlen);
+    SHA1Result(&inner, digest);
+
+    for (size_t i = 0; i < sizeof(block); i++) {
+        block[i] = OPAD ^ (i < keylen ? key[i] : 0);
+    }
+    SHA1Reset(&outer);
+    SHA1Input(&outer, block, 64);
+    SHA1Input(&outer, digest, 20);
+    SHA1Result(&outer, resbuf);
+}
+
+
+std::string oauth_sign_hmac_sha1(const char *m, const char *k)
+{
+    return oauth_sign_hmac_sha1_raw(m, strlen(m), k, strlen(k));
+}
+
+std::string oauth_sign_hmac_sha1_raw(const char *m, const size_t ml, const char *k, const size_t kl)
+{
+    unsigned char result[20];
+    hmac_sha1((unsigned char const *)k, kl, (unsigned char const *)m, ml, result);
+    return oauth_encode_base64(result, 20);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,66 @@
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "HTTPClient.h"
+#include "NTPClient.h"
+
+#include "oauth.h"
+
+EthernetNetIf eth(IpAddr(192,168,0,100), //IP Address
+                  IpAddr(255,255,255,0), //Network Mask
+                  IpAddr(192,168,0,1), //Gateway
+                  IpAddr(192,168,0,1)  //DNS
+);
+NTPClient ntp;
+HTTPClient http;
+
+DigitalOut led(LED1);
+
+// IMPORTANT: please change the following keys for your application.
+
+static char const consumer_key[] = "AAAAAAAAAAAAAAAAAAAAAA";
+static char const consumer_secret[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+
+static char const token_key[] = "00000000-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+static char const token_secret[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+
+// get current time and set to system clock
+
+void reset_time()
+{
+    Host server(IpAddr(), 123, "ntp.jst.mfeed.ad.jp");
+    ntp.setTime(server);
+}
+
+// post message to Twitter
+
+void tweet(char const *message)
+{
+
+    std::string uri = "http://api.twitter.com/statuses/update.xml";
+    uri += "?status=";
+    uri += oauth_url_escape(message);
+
+    std::string req_url;
+    std::string postarg;
+
+    req_url = oauth_sign_url2(uri.c_str(), &postarg, OA_HMAC, 0, consumer_key, consumer_secret, token_key, token_secret);
+    oauth_http_post(req_url.c_str(), postarg.c_str());
+}
+
+//
+
+int main()
+{
+    eth.setup();
+
+    reset_time();
+
+    tweet("Hello, world");
+
+    while(1) {
+        led = 1;
+        wait(0.5);
+        led = 0;
+        wait(0.5);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oauth.cpp	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,719 @@
+/*
+ * OAuth string functions in POSIX-C.
+ *
+ * Copyright 2007-2010 Robin Gareus <robin@gareus.org>
+ * 
+ * The base64 functions are by Jan-Henrik Haukeland, <hauk@tildeslash.com>
+ * and un/escape_url() was inspired by libcurl's curl_escape under ISC-license
+ * many thanks to Daniel Stenberg <daniel@haxx.se>.
+ *
+ * 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 HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define WIPE_MEMORY ///< overwrite sensitve data before free()ing it.
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <ctype.h> // isxdigit
+
+#include "oauth.h"
+
+#include <vector>
+#include <algorithm>
+#include <sstream>
+
+/**
+ * Base64 encode one byte
+ */
+char oauth_b64_encode(unsigned char u)
+{
+    if (u < 26)  return 'A' + u;
+    if (u < 52)  return 'a' + (u - 26);
+    if (u < 62)  return '0' + (u - 52);
+    if (u == 62) return '+';
+    return '/';
+}
+
+/**
+ * Decode a single base64 character.
+ */
+unsigned char oauth_b64_decode(char c)
+{
+    if (c >= 'A' && c <= 'Z') return(c - 'A');
+    if (c >= 'a' && c <= 'z') return(c - 'a' + 26);
+    if (c >= '0' && c <= '9') return(c - '0' + 52);
+    if (c == '+')             return 62;
+    return 63;
+}
+
+/**
+ * Return TRUE if 'c' is a valid base64 character, otherwise FALSE
+ */
+bool oauth_b64_is_base64(char c)
+{
+    return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/') || (c == '='));
+}
+
+/**
+ * Base64 encode and return size data in 'src'. The caller must free the
+ * returned string.
+ *
+ * @param size The size of the data in src
+ * @param src The data to be base64 encode
+ * @return encoded string otherwise NULL
+ */
+std::string oauth_encode_base64(const unsigned char *src, int size)
+{
+    int i;
+    std::stringbuf sb;
+
+    if (!src) return NULL;
+    if (!size) size= strlen((char *)src);
+
+    for (i = 0; i < size; i += 3) {
+        unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
+        b1= src[i];
+        if (i + 1 < size) b2 = src[i + 1];
+        if (i + 2 < size) b3 = src[i + 2];
+
+        b4= b1 >> 2;
+        b5= ((b1 & 0x3) << 4) | (b2 >> 4);
+        b6= ((b2 & 0xf) << 2) | (b3 >> 6);
+        b7= b3 & 0x3f;
+
+        sb.sputc(oauth_b64_encode(b4));
+        sb.sputc(oauth_b64_encode(b5));
+
+        if (i + 1 < size) {
+            sb.sputc(oauth_b64_encode(b6));
+        } else {
+            sb.sputc('=');
+        }
+
+        if (i + 2 < size) {
+            sb.sputc(oauth_b64_encode(b7));
+        } else {
+            sb.sputc('=');
+        }
+    }
+    return sb.str();
+}
+
+/**
+ * Decode the base64 encoded string 'src' into the memory pointed to by
+ * 'dest'. 
+ *
+ * @param dest Pointer to memory for holding the decoded string.
+ * Must be large enough to receive the decoded string.
+ * @param src A base64 encoded string.
+ * @return the length of the decoded string if decode
+ * succeeded otherwise 0.
+ */
+std::string oauth_decode_base64(const char *src)
+{
+    if (src && *src) {
+        std::stringbuf sb;
+        //unsigned char *p= dest;
+        int k, l= strlen(src)+1;
+        std::vector<unsigned char> buf(l);
+
+        /* Ignore non base64 chars as per the POSIX standard */
+        for (k = 0, l = 0; src[k]; k++) {
+            if (oauth_b64_is_base64(src[k])) {
+                buf[l++]= src[k];
+            }
+        } 
+
+        for (k = 0; k < l; k += 4) {
+            char c1='A', c2='A', c3='A', c4='A';
+            unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+            c1= buf[k];
+
+            if (k + 1 < l) c2 = buf[k + 1];
+            if (k + 2 < l) c3 = buf[k + 2];
+            if (k + 3 < l) c4 = buf[k + 3];
+
+            b1 = oauth_b64_decode(c1);
+            b2 = oauth_b64_decode(c2);
+            b3 = oauth_b64_decode(c3);
+            b4 = oauth_b64_decode(c4);
+
+            sb.sputc((b1 << 2) | (b2 >> 4));
+
+            if (c3 != '=') sb.sputc(((b2 & 0xf) << 4) | (b3 >> 2));
+            if (c4 != '=') sb.sputc(((b3 & 0x3) << 6) | b4);
+        }
+
+        return sb.str();
+    }
+    return 0;
+}
+
+/**
+ * Escape 'string' according to RFC3986 and
+ * http://oauth.net/core/1.0/#encoding_parameters.
+ *
+ * @param string The data to be encoded
+ * @return encoded string otherwise NULL
+ * The caller must free the returned string.
+ */
+std::string oauth_url_escape(const char *string)
+{
+    unsigned char in; 
+    size_t length;
+
+    if (!string) {
+        return std::string();
+    }
+
+    length = strlen(string);
+
+    std::stringbuf sb;
+
+    while (length--) {
+        in = *string;
+        if (strchr("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_~.-", in)) {
+            sb.sputc(in);
+        } else {
+            char tmp[10];
+            snprintf(tmp, 4, "%%%02X", in);
+            sb.sputc(tmp[0]);
+            sb.sputc(tmp[1]);
+            sb.sputc(tmp[2]);
+        }
+        string++;
+    }
+    return sb.str();
+}
+
+#ifndef ISXDIGIT
+# define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
+#endif
+
+/**
+ * Parse RFC3986 encoded 'string' back to  unescaped version.
+ *
+ * @param string The data to be unescaped
+ * @param olen unless NULL the length of the returned string is stored there.
+ * @return decoded string or NULL
+ * The caller must free the returned string.
+ */
+std::string oauth_url_unescape(const char *string)
+{
+    size_t alloc, strindex=0;
+    unsigned char in;
+    long hex;
+
+    if (!string) return NULL;
+
+    alloc = strlen(string)+1;
+    std::vector<char> ns(alloc);
+
+    while(--alloc > 0) {
+        in = *string;
+        if (('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
+            char hexstr[3]; // '%XX'
+            hexstr[0] = string[1];
+            hexstr[1] = string[2];
+            hexstr[2] = 0;
+            hex = strtol(hexstr, NULL, 16);
+            in = (unsigned char)hex; /* hex is always < 256 */
+            string += 2;
+            alloc -= 2;
+        }
+        ns[strindex++] = in;
+        string++;
+    }
+    ns[strindex]=0;
+    return &ns[0];
+}
+
+/**
+ * returns plaintext signature for the given key.
+ *
+ * the returned string needs to be freed by the caller
+ *
+ * @param m message to be signed
+ * @param k key used for signing
+ * @return signature string
+ */
+std::string oauth_sign_plaintext (const char *m, const char *k)
+{
+    return oauth_url_escape(k);
+}
+
+/**
+ * encode strings and concatenate with '&' separator.
+ * The number of strings to be concatenated must be
+ * given as first argument.
+ * all arguments thereafter must be of type (char *) 
+ *
+ * @param len the number of arguments to follow this parameter
+ * @param ... string to escape and added (may be NULL)
+ *
+ * @return pointer to memory holding the concatenated 
+ * strings - needs to be free(d) by the caller. or NULL
+ * in case we ran out of memory.
+ */
+std::string oauth_catenc(int len, ...)
+{
+    va_list va;
+    std::string str;
+    va_start(va, len);
+    for (int i = 0; i < len; i++) {
+        char *arg = va_arg(va, char *);
+        std::string enc = oauth_url_escape(arg);
+        if (i > 0) str += "&";
+        str += enc;
+    }
+    va_end(va);
+    return str;
+}
+
+/**
+ * splits the given url into a parameter array. 
+ * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
+ *
+ * NOTE: Request-parameters-values may include an ampersand character.
+ * However if unescaped this function will use them as parameter delimiter. 
+ * If you need to make such a request, this function since version 0.3.5 allows
+ * to use the ASCII SOH (0x01) character as alias for '&' (0x26).
+ * (the motivation is convenience: SOH is /untypeable/ and much more 
+ * unlikely to appear than '&' - If you plan to sign fancy URLs you 
+ * should not split a query-string, but rather provide the parameter array
+ * directly to \ref oauth_serialize_url)
+ *
+ * @param url the url or query-string to parse. 
+ * @param argv pointer to a (char *) array where the results are stored.
+ *  The array is re-allocated to match the number of parameters and each 
+ *  parameter-string is allocated with strdup. - The memory needs to be freed
+ *  by the caller.
+ * @param qesc use query parameter escape (vs post-param-escape) - if set
+ *        to 1 all '+' are treated as spaces ' '
+ * 
+ * @return number of parameter(s) in array.
+ */
+void oauth_split_post_paramters(const char *url, std::vector<std::string> *argv, short qesc)
+{
+    int argc=0;
+    char *token, *tmp;
+    if (!argv) return;
+    if (!url) return;
+    std::vector<char> t1(strlen(url) + 1);
+    strcpy(&t1[0], url);
+
+    // '+' represents a space, in a URL query string
+    while ((qesc&1) && (tmp = strchr(&t1[0],'+'))) *tmp = ' ';
+
+    tmp = &t1[0];
+    while ((token = strtok(tmp,"&?"))) {
+        if (!strncasecmp("oauth_signature=", token, 16)) continue;
+        while (!(qesc & 2) && (tmp = strchr(token, '\001'))) *tmp = '&';
+        argv->push_back(oauth_url_unescape(token));
+        if (argc == 0 && strstr(token, ":/")) {
+            // HTTP does not allow empty absolute paths, so the URL 
+            // 'http://example.com' is equivalent to 'http://example.com/' and should
+            // be treated as such for the purposes of OAuth signing (rfc2616, section 3.2.1)
+            // see http://groups.google.com/group/oauth/browse_thread/thread/c44b6f061bfd98c?hl=en
+            char *slash = strstr(token, ":/");
+            while (slash && *(++slash) == '/')  ; // skip slashes eg /xxx:[\/]*/
+#if 0
+            // skip possibly unescaped slashes in the userinfo - they're not allowed by RFC2396 but have been seen.
+            // the hostname/IP may only contain alphanumeric characters - so we're safe there.
+            if (slash && strchr(slash,'@')) slash=strchr(slash, '@'); 
+#endif
+            if (slash && !strchr(slash,'/')) {
+#ifdef DEBUG_OAUTH
+                fprintf(stderr, "\nliboauth: added trailing slash to URL: '%s'\n\n", token);
+#endif
+                argv->push_back(std::string(token) + "/");
+            }
+        }
+        if (argc == 0 && (tmp = strstr((char *)argv->at(argc).c_str(), ":80/"))) {
+            memmove(tmp, tmp + 3, strlen(tmp + 2));
+        }
+        tmp = NULL;
+        argc++;
+    }
+}
+
+void oauth_split_url_parameters(const char *url, std::vector<std::string> *argv)
+{
+    oauth_split_post_paramters(url, argv, 1);
+}
+
+/**
+ * build a url query string from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ *
+ */
+std::string oauth_serialize_url (std::vector<std::string> const &argv, int start)
+{
+    return oauth_serialize_url_sep(argv, start, "&", 0);
+}
+
+/**
+ * encode query parameters from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @param sep separator for parameters (usually "&") 
+ * @param mod - bitwise modifiers: 
+ *   1: skip all values that start with "oauth_"
+ *   2: skip all values that don't start with "oauth_"
+ *   4: add double quotation marks around values (use with sep=", " to generate HTTP Authorization header).
+ * @return url string needs to be freed by the caller.
+ */
+std::string oauth_serialize_url_sep(std::vector<std::string> const &argv, int start, char const *sep, int mod)
+{
+    int i;
+    int first = 0;
+    int seplen = strlen(sep);
+    std::string query;
+    for (i = start; i < (int)argv.size(); i++) {
+        std::string tmp;
+
+        if ((mod & 1) == 1 && (strncmp(argv[i].c_str(), "oauth_", 6) == 0 || strncmp(argv[i].c_str(), "x_oauth_", 8) == 0)) continue;
+        if ((mod & 2) == 2 && (strncmp(argv[i].c_str(), "oauth_", 6) != 0 && strncmp(argv[i].c_str(), "x_oauth_", 8) != 0) && i != 0) continue;
+
+        if (i == start && i == 0 && strstr(argv[i].c_str(), ":/")) {
+            tmp = argv[i];
+        } else {
+            char *p = strchr((char *)argv[i].c_str(), '=');
+            if (p) {
+                tmp = oauth_url_escape(std::string(argv[i].c_str(), (char const *)p).c_str());
+                std::string t2 = oauth_url_escape(p + 1);
+                tmp += "=";
+                if (mod & 4) tmp += "\"";
+                tmp += t2;
+                if (mod & 4) tmp += "\"";
+            } else {
+                // see http://oauth.net/core/1.0/#anchor14
+                // escape parameter names and arguments but not the '='
+                tmp=argv[i];
+                tmp += "=";
+            }
+        }
+        query += ((i == start || first) ? "" : sep);
+        query += tmp;
+        first = 0;
+        if (i == start && i == 0 && strstr((char *)tmp.c_str(), ":/")) {
+            query += "?";
+            first = 1;
+        }
+    }
+    return (query);
+}
+
+/**
+ * build a query parameter string from an array.
+ *
+ * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv). 
+ * It strips the leading host/path, which is usually the first 
+ * element when using oauth_split_url_parameters on an URL.
+ *
+ * @param argc the total number of elements in the array
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ */
+std::string oauth_serialize_url_parameters (std::vector<std::string> const &argv)
+{
+    return oauth_serialize_url(argv, 1);
+}
+
+/**
+ * generate a random string between 15 and 32 chars length
+ * and return a pointer to it. The value needs to be freed by the
+ * caller
+ *
+ * @return zero terminated random string.
+ */
+std::string oauth_gen_nonce()
+{
+    static const char *chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+    const unsigned int max = 26 + 26 + 10 + 1; //strlen(chars);
+    char tmp[50];
+    int i, len;
+
+    srand((unsigned int)time(0));
+    len = 15 + rand() % 16;
+    for (i = 0; i < len; i++) {
+        tmp[i] = chars[rand() % max];
+    }
+    tmp[i]='\0';
+    return &tmp[0];
+}
+
+/**
+ * string compare function for oauth parameters.
+ *
+ * used with qsort. needed to normalize request parameters.
+ * see http://oauth.net/core/1.0/#anchor14
+ */
+int oauth_cmpstringp(const void *p1, const void *p2)
+{
+    char const *e1;
+    char const *e2;
+    e1 = strchr((char *)p1, '=');
+    e2 = strchr((char *)p2, '=');
+    if (e1 && e2) {
+        std::string left((char const *)p1, e1);
+        std::string right((char const *)p2, e2);
+        return strcmp(left.c_str(), right.c_str());
+    }
+
+    std::string left = oauth_url_escape((char const *)p1);
+    std::string right = oauth_url_escape((char const *)p2);
+    return strcmp(left.c_str(), right.c_str());
+}
+
+bool oauth_cmpstringp_ex(std::string const &left, std::string const &right)
+{
+    return oauth_cmpstringp(left.c_str(), right.c_str()) < 0;
+}
+
+/**
+ * search array for parameter key.
+ * @param argv length of array to search
+ * @param argc parameter array to search
+ * @param key key of parameter to check.
+ *
+ * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise.
+ */
+bool oauth_param_exists(std::vector<std::string> const &argv, char const *key)
+{
+    int i;
+    size_t l = strlen(key);
+    for (i = 0; i < (int)argv.size(); i++) {
+        if (!strncmp(argv[i].c_str(), key, l) && argv[i][l] == '=') {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ *
+ */
+void oauth_add_protocol(
+    std::vector<std::string> *argvp, 
+    OAuthMethod method, 
+    const char *c_key, //< consumer key - posted plain text
+    const char *t_key //< token key - posted plain text in URL
+)
+{
+    char oarg[1024];
+
+    // add OAuth specific arguments
+    if (!oauth_param_exists(*argvp,"oauth_nonce")) {
+        std::string tmp = oauth_gen_nonce();
+        snprintf(oarg, 1024, "oauth_nonce=%s", tmp.c_str());
+        argvp->push_back(oarg);
+    }
+
+    if (!oauth_param_exists(*argvp,"oauth_timestamp")) {
+        long t = time(0);
+        snprintf(oarg, 1024, "oauth_timestamp=%u", t);
+        argvp->push_back(oarg);
+    }
+
+    if (t_key) {
+        snprintf(oarg, 1024, "oauth_token=%s", t_key);
+        argvp->push_back(oarg);
+    }
+
+    snprintf(oarg, 1024, "oauth_consumer_key=%s", c_key);
+    argvp->push_back(oarg);
+
+    snprintf(oarg, 1024, "oauth_signature_method=%s", method==0?"HMAC-SHA1":method==1?"RSA-SHA1":"PLAINTEXT");
+    argvp->push_back(oarg);
+
+    if (!oauth_param_exists(*argvp,"oauth_version")) {
+        snprintf(oarg, 1024, "oauth_version=1.0");
+        argvp->push_back(oarg);
+    }
+
+#if 0 // oauth_version 1.0 Rev A
+    if (!oauth_param_exists(argv,argc,"oauth_callback")) {
+        snprintf(oarg, 1024, "oauth_callback=oob");
+        argvp->push_back(oarg);
+    }
+#endif
+
+}
+
+std::string oauth_sign_url(
+    const char *url,
+    std::string *postargs, 
+    OAuthMethod method, 
+    const char *c_key, //< consumer key - posted plain text
+    const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+    const char *t_key, //< token key - posted plain text in URL
+    const char *t_secret //< token secret - used as 2st part of secret-key
+)
+{
+    return oauth_sign_url2(url, postargs, method, NULL, c_key, c_secret, t_key, t_secret);
+} 
+
+std::string oauth_sign_url2(
+    const char *url,
+    std::string *postargs, 
+    OAuthMethod method, 
+    const char *http_method, //< HTTP request method
+    const char *c_key, //< consumer key - posted plain text
+    const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+    const char *t_key, //< token key - posted plain text in URL
+    const char *t_secret //< token secret - used as 2st part of secret-key
+)
+{
+    //char **argv = NULL;
+    std::vector<std::string> argv;
+    std::string rv;
+
+    if (postargs) {
+        oauth_split_post_paramters(url, &argv, 0);
+    } else {
+        oauth_split_url_parameters(url, &argv);
+    }
+
+    rv = oauth_sign_array2(&argv, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
+
+    return(rv);
+}
+
+std::string oauth_sign_array(
+    std::vector<std::string> *argvp,
+    std::string *postargs,
+    OAuthMethod method, 
+    const char *c_key, //< consumer key - posted plain text
+    const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+    const char *t_key, //< token key - posted plain text in URL
+    const char *t_secret //< token secret - used as 2st part of secret-key
+)
+{
+    return oauth_sign_array2(
+        argvp, 
+        postargs, method,
+        NULL,
+        c_key, c_secret,
+        t_key, t_secret
+        );
+}
+
+void oauth_sign_array2_process(
+    std::vector<std::string> *argvp,
+    std::string *postargs,
+    OAuthMethod method, 
+    const char *http_method, //< HTTP request method
+    const char *c_key, //< consumer key - posted plain text
+    const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+    const char *t_key, //< token key - posted plain text in URL
+    const char *t_secret //< token secret - used as 2st part of secret-key
+)
+{
+    char oarg[1024];
+    std::string query;
+    std::string sign;
+    std::string http_request_method;
+
+    if (!http_method) {
+        http_request_method = postargs ? "POST" : "GET";
+    } else {
+        std::vector<char> tmp(strlen(http_method) + 1);
+        int i;
+        for (i = 0; http_method[i]; i++) {
+            tmp[i] = toupper(http_method[i]);
+        }
+        tmp[i] = 0;
+        http_request_method = &tmp[0];
+    }
+
+    // add required OAuth protocol parameters
+    oauth_add_protocol(argvp, method, c_key, t_key);
+
+    // sort parameters
+    //qsort(&(*argvp)[1], (*argcp)-1, sizeof(char *), oauth_cmpstringp);
+    std::sort(argvp->begin() + 1, argvp->end(), oauth_cmpstringp_ex);
+
+    // serialize URL - base-url 
+    query= oauth_serialize_url_parameters(*argvp);
+
+    // generate signature
+    std::string okey = oauth_catenc(2, c_secret, t_secret);
+    std::string odat = oauth_catenc(3, http_request_method.c_str(), (*argvp)[0].c_str(), query.c_str()); // base-string
+#ifdef DEBUG_OAUTH
+    fprintf (stderr, "\nliboauth: data to sign='%s'\n\n", odat.c_str());
+    fprintf (stderr, "\nliboauth: key='%s'\n\n", okey.c_str());
+#endif
+    switch(method) {
+    //case OA_RSA:
+    //    sign = oauth_sign_rsa_sha1(odat.c_str(), okey.c_str()); // XXX okey needs to be RSA key!
+    //    break;
+    case OA_PLAINTEXT:
+        sign = oauth_sign_plaintext(odat.c_str(), okey.c_str()).c_str();
+        break;
+    default:
+        sign = oauth_sign_hmac_sha1(odat.c_str(), okey.c_str());
+        break;
+    }
+
+    // append signature to query args.
+    snprintf(oarg, 1024, "oauth_signature=%s",sign.c_str());
+    argvp->push_back(oarg);
+}
+
+std::string oauth_sign_array2(
+    std::vector<std::string> *argvp,
+    std::string *postargs,
+    OAuthMethod method, 
+    const char *http_method, //< HTTP request method
+    const char *c_key, //< consumer key - posted plain text
+    const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+    const char *t_key, //< token key - posted plain text in URL
+    const char *t_secret //< token secret - used as 2st part of secret-key
+)
+{
+
+    std::string result;
+    oauth_sign_array2_process(argvp, postargs, method, http_method, c_key, c_secret, t_key, t_secret);
+
+    // build URL params
+    result = oauth_serialize_url(*argvp, (postargs?1:0));
+
+    if (postargs) { 
+        *postargs = result;
+        result = argvp->at(0);
+    }
+
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oauth.h	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,476 @@
+/**
+ *  @brief OAuth.net implementation in POSIX-C.
+ *  @file oauth.h
+ *  @author Robin Gareus <robin@gareus.org>
+ *
+ * Copyright 2007-2010 Robin Gareus <robin@gareus.org>
+ *
+ * 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.
+ *
+ */
+#ifndef _OAUTH_H
+#define _OAUTH_H      1 
+
+#include <vector>
+#include <string>
+
+#include <stdlib.h>
+
+#ifndef DOXYGEN_IGNORE
+// liboauth version
+#define LIBOAUTH_VERSION "0.8.9"
+#define LIBOAUTH_VERSION_MAJOR  0
+#define LIBOAUTH_VERSION_MINOR  8
+#define LIBOAUTH_VERSION_MICRO  9
+
+//interface revision number
+//http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+#define LIBOAUTH_CUR  7
+#define LIBOAUTH_REV  0
+#define LIBOAUTH_AGE  7
+#endif
+
+#ifdef __GNUC__
+#    define OA_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y)
+#else
+#    define OA_GCC_VERSION_AT_LEAST(x,y) 0
+#endif
+
+#ifndef attribute_deprecated
+#if OA_GCC_VERSION_AT_LEAST(3,1)
+#    define attribute_deprecated __attribute__((deprecated))
+#else
+#    define attribute_deprecated
+#endif
+#endif
+
+/** \enum OAuthMethod
+ * signature method to used for signing the request.
+ */ 
+typedef enum { 
+    OA_HMAC=0, ///< use HMAC-SHA1 request signing method
+    OA_RSA, ///< use RSA signature 
+    OA_PLAINTEXT ///< use plain text signature (for testing only)
+  } OAuthMethod;
+
+/**
+ * Base64 encode and return size data in 'src'. The caller must free the
+ * returned string.
+ *
+ * @param size The size of the data in src
+ * @param src The data to be base64 encode
+ * @return encoded string otherwise NULL
+ */
+std::string oauth_encode_base64(const unsigned char *src, int size);
+
+/**
+ * Decode the base64 encoded string 'src' into the memory pointed to by
+ * 'dest'. 
+ *
+ * @param dest Pointer to memory for holding the decoded string.
+ * Must be large enough to receive the decoded string.
+ * @param src A base64 encoded string.
+ * @return the length of the decoded string if decode
+ * succeeded otherwise 0.
+ */
+std::string oauth_decode_base64(const char *src);
+
+/**
+ * Escape 'string' according to RFC3986 and
+ * http://oauth.net/core/1.0/#encoding_parameters.
+ *
+ * @param string The data to be encoded
+ * @return encoded string otherwise NULL
+ * The caller must free the returned string.
+ */
+std::string oauth_url_escape(const char *string);
+
+/**
+ * Parse RFC3986 encoded 'string' back to  unescaped version.
+ *
+ * @param string The data to be unescaped
+ * @param olen unless NULL the length of the returned string is stored there.
+ * @return decoded string or NULL
+ * The caller must free the returned string.
+ */
+std::string oauth_url_unescape(const char *string);
+ 
+
+/**
+ * returns base64 encoded HMAC-SHA1 signature for
+ * given message and key.
+ * both data and key need to be urlencoded.
+ *
+ * the returned string needs to be freed by the caller
+ *
+ * @param m message to be signed
+ * @param k key used for signing
+ * @return signature string.
+ */
+std::string oauth_sign_hmac_sha1 (const char *m, const char *k);
+
+/**
+ * same as \ref oauth_sign_hmac_sha1 but allows
+ * to specify length of message and key (in case they contain null chars).
+ *
+ * @param m message to be signed
+ * @param ml length of message
+ * @param k key used for signing
+ * @param kl length of key
+ * @return signature string.
+ */
+std::string oauth_sign_hmac_sha1_raw(const char *m, const size_t ml, const char *k, const size_t kl);
+
+/**
+ * returns plaintext signature for the given key.
+ *
+ * the returned string needs to be freed by the caller
+ *
+ * @param m message to be signed
+ * @param k key used for signing
+ * @return signature string
+ */
+std::string oauth_sign_plaintext(const char *m, const char *k);
+
+/**
+ * returns RSA-SHA1 signature for given data.
+ * the returned signature needs to be freed by the caller.
+ *
+ * @param m message to be signed
+ * @param k private-key PKCS and Base64-encoded 
+ * @return base64 encoded signature string.
+ */
+//std::string oauth_sign_rsa_sha1 (const char *m, const char *k);
+
+/**
+ * verify RSA-SHA1 signature.
+ *
+ * returns the output of EVP_VerifyFinal() for a given message,
+ * cert/pubkey and signature.
+ *
+ * @param m message to be verified
+ * @param c public-key or x509 certificate
+ * @param s base64 encoded signature
+ * @return 1 for a correct signature, 0 for failure and -1 if some other error occurred
+ */
+int oauth_verify_rsa_sha1(const char *m, const char *c, const char *s);
+
+/**
+ * url-escape strings and concatenate with '&' separator.
+ * The number of strings to be concatenated must be
+ * given as first argument.
+ * all arguments thereafter must be of type (char *) 
+ *
+ * @param len the number of arguments to follow this parameter
+ *
+ * @return pointer to memory holding the concatenated 
+ * strings - needs to be free(d) by the caller. or NULL
+ * in case we ran out of memory.
+ */
+std::string oauth_catenc(int len, ...);
+
+/**
+ * splits the given url into a parameter array. 
+ * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
+ * (see \ref oauth_split_post_paramters for a more generic version)
+ *
+ * @param url the url or query-string to parse; may be NULL
+ * @param argv pointer to a (char *) array where the results are stored.
+ *  The array is re-allocated to match the number of parameters and each 
+ *  parameter-string is allocated with strdup. - The memory needs to be freed
+ *  by the caller.
+ * 
+ * @return number of parameter(s) in array.
+ */
+void oauth_split_url_parameters(const char *url, char ***argv);
+
+/**
+ * splits the given url into a parameter array. 
+ * (see \ref oauth_serialize_url and \ref oauth_serialize_url_parameters for the reverse)
+ *
+ * @param url the url or query-string to parse. 
+ * @param argv pointer to a (char *) array where the results are stored.
+ *  The array is re-allocated to match the number of parameters and each 
+ *  parameter-string is allocated with strdup. - The memory needs to be freed
+ *  by the caller.
+ * @param qesc use query parameter escape (vs post-param-escape) - if set
+ *        to 1 all '+' are treated as spaces ' '
+ * 
+ * @return number of parameter(s) in array.
+ */
+void oauth_split_post_paramters(const char *url, char ***argv, short qesc);
+
+/**
+ * build a url query string from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ *
+ */
+std::string oauth_serialize_url (std::vector<std::string> const &argv, int start);
+
+/**
+ * encode query parameters from an array.
+ *
+ * @param argc the total number of elements in the array
+ * @param start element in the array at which to start concatenating.
+ * @param argv parameter-array to concatenate.
+ * @param sep separator for parameters (usually "&") 
+ * @param mod - bitwise modifiers: 
+ *   1: skip all values that start with "oauth_"
+ *   2: skip all values that don't start with "oauth_"
+ *   4: double quotation marks are added around values (use with sep ", " for HTTP Authorization header).
+ * @return url string needs to be freed by the caller.
+ */
+std::string oauth_serialize_url_sep (std::vector<std::string> const &argv, int start, char const *sep, int mod);
+
+/**
+ * build a query parameter string from an array.
+ *
+ * This function is a shortcut for \ref oauth_serialize_url (argc, 1, argv). 
+ * It strips the leading host/path, which is usually the first 
+ * element when using oauth_split_url_parameters on an URL.
+ *
+ * @param argc the total number of elements in the array
+ * @param argv parameter-array to concatenate.
+ * @return url string needs to be freed by the caller.
+ */
+std::string oauth_serialize_url_parameters (std::vector<std::string> const &argv);
+ 
+/**
+ * generate a random string between 15 and 32 chars length
+ * and return a pointer to it. The value needs to be freed by the
+ * caller
+ *
+ * @return zero terminated random string.
+ */
+std::string oauth_gen_nonce();
+
+/**
+ * string compare function for oauth parameters.
+ *
+ * used with qsort. needed to normalize request parameters.
+ * see http://oauth.net/core/1.0/#anchor14
+ */
+int oauth_cmpstringp(const void *p1, const void *p2);
+
+
+/**
+ * search array for parameter key.
+ * @param argv length of array to search
+ * @param argc parameter array to search
+ * @param key key of parameter to check.
+ *
+ * @return FALSE (0) if array does not contain a parameter with given key, TRUE (1) otherwise.
+ */
+bool oauth_param_exists(std::vector<std::string> const &argv, char const *key);
+
+/**
+ * free array args
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values to be free()d
+ */
+void oauth_free_array(int *argcp, std::vector<std::string> *argvp);
+
+/**
+ * calculate OAuth-signature for a given HTTP request URL, parameters and oauth-tokens.
+ *
+ * if 'postargs' is NULL a "GET" request is signed and the 
+ * signed URL is returned. Else this fn will modify 'postargs' 
+ * to point to memory that contains the signed POST-variables 
+ * and returns the base URL.
+ *
+ * both, the return value and (if given) 'postargs' need to be freed
+ * by the caller.
+ *
+ * @param url The request URL to be signed. append all GET or POST 
+ * query-parameters separated by either '?' or '&' to this parameter.
+ *
+ * @param postargs This parameter points to an area where the return value
+ * is stored. If 'postargs' is NULL, no value is stored.
+ *
+ * @param method specify the signature method to use. It is of type 
+ * \ref OAuthMethod and most likely \ref OA_HMAC.
+ *
+ * @param http_method The HTTP request method to use (ie "GET", "PUT",..)
+ * If NULL is given as 'http_method' this defaults to "GET" when 
+ * 'postargs' is also NULL and when postargs is not NULL "POST" is used.
+ *
+ * @param c_key consumer key
+ * @param c_secret consumer secret
+ * @param t_key token key
+ * @param t_secret token secret
+ *
+ * @return the signed url or NULL if an error occurred.
+ *
+ */
+std::string oauth_sign_url2 (const char *url, std::string *postargs, 
+  OAuthMethod method, 
+  const char *http_method, //< HTTP request method
+  const char *c_key, //< consumer key - posted plain text
+  const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+  const char *t_key, //< token key - posted plain text in URL
+  const char *t_secret //< token secret - used as 2st part of secret-key
+  );
+
+/**
+ * @deprecated Use oauth_sign_url2() instead.
+ */
+std::string oauth_sign_url (const char *url, std::string *postargs, 
+  OAuthMethod method, 
+  const char *c_key, //< consumer key - posted plain text
+  const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+  const char *t_key, //< token key - posted plain text in URL
+  const char *t_secret //< token secret - used as 2st part of secret-key
+  ) attribute_deprecated;
+
+
+/**
+ * the back-end behind by /ref oauth_sign_array2.
+ * however it does not serialize the signed URL again.
+ * The user needs to call /ref oauth_serialize_url (oA)
+ * and /ref oauth_free_array to do so.
+ *
+ * This allows to split parts of the URL to be used for
+ * OAuth HTTP Authorization header:
+ * see http://oauth.net/core/1.0a/#consumer_req_param
+ * the oauthtest2 example code does so.
+ * 
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values  
+ * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" ..
+ *  the array is modified: fi. oauth_ parameters are added)
+ *  These arrays can be generated with /ref oauth_split_url_parameters
+ *  or /ref oauth_split_post_paramters.
+ *
+ * @param postargs This parameter points to an area where the return value
+ * is stored. If 'postargs' is NULL, no value is stored.
+ *
+ * @param method specify the signature method to use. It is of type 
+ * \ref OAuthMethod and most likely \ref OA_HMAC.
+ *
+ * @param http_method The HTTP request method to use (ie "GET", "PUT",..)
+ * If NULL is given as 'http_method' this defaults to "GET" when 
+ * 'postargs' is also NULL and when postargs is not NULL "POST" is used.
+ *
+ * @param c_key consumer key
+ * @param c_secret consumer secret
+ * @param t_key token key
+ * @param t_secret token secret
+ *
+ * @return void
+ *
+ */
+void oauth_sign_array2_process (std::vector<std::string> *argvp,
+  std::string *postargs,
+  OAuthMethod method, 
+  const char *http_method, //< HTTP request method
+  const char *c_key, //< consumer key - posted plain text
+  const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+  const char *t_key, //< token key - posted plain text in URL
+  const char *t_secret //< token secret - used as 2st part of secret-key
+  );
+
+/**
+ * same as /ref oauth_sign_url
+ * with the url already split into parameter array 
+ *
+ * @param argcp pointer to array length int
+ * @param argvp pointer to array values  
+ * (argv[0]="http://example.org:80/" argv[1]="first=QueryParamater" ..
+ *  the array is modified: fi. oauth_ parameters are added)
+ *  These arrays can be generated with /ref oauth_split_url_parameters
+ *  or /ref oauth_split_post_paramters.
+ *
+ * @param postargs This parameter points to an area where the return value
+ * is stored. If 'postargs' is NULL, no value is stored.
+ *
+ * @param method specify the signature method to use. It is of type 
+ * \ref OAuthMethod and most likely \ref OA_HMAC.
+ *
+ * @param http_method The HTTP request method to use (ie "GET", "PUT",..)
+ * If NULL is given as 'http_method' this defaults to "GET" when 
+ * 'postargs' is also NULL and when postargs is not NULL "POST" is used.
+ *
+ * @param c_key consumer key
+ * @param c_secret consumer secret
+ * @param t_key token key
+ * @param t_secret token secret
+ *
+ * @return the signed url or NULL if an error occurred.
+ */
+std::string oauth_sign_array2 (std::vector<std::string> *argvp,
+  std::string *postargs,
+  OAuthMethod method, 
+  const char *http_method, //< HTTP request method
+  const char *c_key, //< consumer key - posted plain text
+  const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+  const char *t_key, //< token key - posted plain text in URL
+  const char *t_secret //< token secret - used as 2st part of secret-key
+  );
+
+/**
+ * @deprecated Use oauth_sign_array2() instead.
+ */
+char *oauth_sign_array(
+    std::vector<std::string> *argvp,
+    char **postargs,
+    OAuthMethod method, 
+    const char *c_key, //< consumer key - posted plain text
+    const char *c_secret, //< consumer secret - used as 1st part of secret-key 
+    const char *t_key, //< token key - posted plain text in URL
+    const char *t_secret //< token secret - used as 2st part of secret-key
+    ) attribute_deprecated;
+
+/**
+ * do a HTTP POST request, wait for it to finish 
+ * and return the content of the reply.
+ * (requires libcurl or a command-line HTTP client)
+ *
+ * If compiled <b>without</b> libcurl this function calls
+ * a command-line executable defined in the environment variable
+ * OAUTH_HTTP_CMD - it defaults to 
+ * <tt>curl -sA 'liboauth-agent/0.1' -d '%%p' '%%u'</tt>
+ * where %%p is replaced with the postargs and %%u is replaced with 
+ * the URL. 
+ *
+ * bash & wget example:
+ * <tt>export OAUTH_HTTP_CMD="wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "</tt>
+ *
+ * NOTE: This function uses the curl's default HTTP-POST Content-Type:
+ * application/x-www-form-urlencoded which is the only option allowed
+ * by oauth core 1.0 spec. Experimental code can use the Environment variable
+ * to transmit custom HTTP headers or parameters.
+ *
+ * WARNING: this is a tentative function. it's convenient and handy for testing
+ * or developing OAuth code. But don't rely on this function
+ * to become a stable part of this API. It does not do 
+ * much error checking for one thing..
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @return replied content from HTTP server. needs to be freed by caller.
+ */
+std::string oauth_http_post(const char *u, const char *p);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oauth_http.cpp	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,61 @@
+/*
+ * OAuth http functions in POSIX-C.
+ *
+ * Copyright 2007, 2008, 2009, 2010 Robin Gareus <robin@gareus.org>
+ *
+ * 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 HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "oauth.h"
+
+#include <HTTPClient.h>
+
+/* wrapper functions */
+
+/**
+ * do a HTTP POST request, wait for it to finish 
+ * and return the content of the reply.
+ * (requires libcurl or a command-line HTTP client)
+ *
+ * more documentation in oauth.h
+ *
+ * @param u url to query
+ * @param p postargs to send along with the HTTP request.
+ * @return  In case of an error NULL is returned; otherwise a pointer to the
+ * replied content from HTTP server. latter needs to be freed by caller.
+ */
+std::string oauth_http_post(const char *u, const char *p)
+{
+    HTTPClient http;
+    HTTPText req("application/x-www-form-urlencoded");
+    HTTPText res;
+    req.set(p);
+    http.post(u, req, &res);
+    return res.get();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1.c	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,385 @@
+/*
+ *  sha1.c
+ *
+ *  Description:
+ *      This file implements the Secure Hashing Algorithm 1 as
+ *      defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ *      The SHA-1, produces a 160-bit message digest for a given
+ *      data stream.  It should take about 2**n steps to find a
+ *      message with the same digest as a given message and
+ *      2**(n/2) to find any two messages with the same digest,
+ *      when n is the digest size in bits.  Therefore, this
+ *      algorithm can serve as a means of providing a
+ *      "fingerprint" for a message.
+ *
+ *  Portability Issues:
+ *      SHA-1 is defined in terms of 32-bit "words".  This code
+ *      uses <stdint.h> (included via "sha1.h" to define 32 and 8
+ *      bit unsigned integer types.  If your C compiler does not
+ *      support 32 bit unsigned integers, this code is not
+ *      appropriate.
+ *
+ *  Caveats:
+ *      SHA-1 is designed to work with messages less than 2^64 bits
+ *      long.  Although SHA-1 allows a message digest to be generated
+ *      for messages of any number of bits less than 2^64, this
+ *      implementation only works with messages with a length that is
+ *      a multiple of the size of an 8-bit character.
+ *
+ */
+
+#include "sha1.h"
+
+
+/*
+ *  Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+                (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage(SHA1Context *);
+void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ *  SHA1Reset
+ *
+ *  Description:
+ *      This function will initialize the SHA1Context in preparation
+ *      for computing a new SHA1 message digest.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to reset.
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int SHA1Reset(SHA1Context *context)
+{
+    if (!context)
+    {
+        return shaNull;
+    }
+
+    context->Length_Low             = 0;
+    context->Length_High            = 0;
+    context->Message_Block_Index    = 0;
+
+    context->Intermediate_Hash[0]   = 0x67452301;
+    context->Intermediate_Hash[1]   = 0xEFCDAB89;
+    context->Intermediate_Hash[2]   = 0x98BADCFE;
+    context->Intermediate_Hash[3]   = 0x10325476;
+    context->Intermediate_Hash[4]   = 0xC3D2E1F0;
+
+    context->Computed   = 0;
+    context->Corrupted  = 0;
+
+    return shaSuccess;
+}
+
+/*
+ *  SHA1Result
+ *
+ *  Description:
+ *      This function will return the 160-bit message digest into the
+ *      Message_Digest array  provided by the caller.
+ *      NOTE: The first octet of hash is stored in the 0th element,
+ *            the last octet of hash in the 19th element.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to use to calculate the SHA-1 hash.
+ *      Message_Digest: [out]
+ *          Where the digest is returned.
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+                uint8_t Message_Digest[SHA1HashSize])
+{
+    int i;
+
+    if (!context || !Message_Digest)
+    {
+        return shaNull;
+    }
+
+    if (context->Corrupted)
+    {
+        return context->Corrupted;
+    }
+
+    if (!context->Computed)
+    {
+        SHA1PadMessage(context);
+        for(i=0; i<64; ++i)
+        {
+            /* message may be sensitive, clear it out */
+            context->Message_Block[i] = 0;
+        }
+        context->Length_Low = 0;    /* and clear length */
+        context->Length_High = 0;
+        context->Computed = 1;
+    }
+
+    for(i = 0; i < SHA1HashSize; ++i)
+    {
+        Message_Digest[i] = context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
+    }
+
+    return shaSuccess;
+}
+
+/*
+ *  SHA1Input
+ *
+ *  Description:
+ *      This function accepts an array of octets as the next portion
+ *      of the message.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The SHA context to update
+ *      message_array: [in]
+ *          An array of characters representing the next portion of
+ *          the message.
+ *      length: [in]
+ *          The length of the message in message_array
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int SHA1Input(    SHA1Context    *context,
+                  const uint8_t  *message_array,
+                  unsigned       length)
+{
+    if (!length)
+    {
+        return shaSuccess;
+    }
+
+    if (!context || !message_array)
+    {
+        return shaNull;
+    }
+
+    if (context->Computed)
+    {
+        context->Corrupted = shaStateError;
+        return shaStateError;
+    }
+
+    if (context->Corrupted)
+    {
+         return context->Corrupted;
+    }
+    while(length-- && !context->Corrupted)
+    {
+    context->Message_Block[context->Message_Block_Index++] =
+                    (*message_array & 0xFF);
+
+    context->Length_Low += 8;
+    if (context->Length_Low == 0)
+    {
+        context->Length_High++;
+        if (context->Length_High == 0)
+        {
+            /* Message is too long */
+            context->Corrupted = 1;
+        }
+    }
+
+    if (context->Message_Block_Index == 64)
+    {
+        SHA1ProcessMessageBlock(context);
+    }
+
+    message_array++;
+    }
+
+    return shaSuccess;
+}
+
+/*
+ *  SHA1ProcessMessageBlock
+ *
+ *  Description:
+ *      This function will process the next 512 bits of the message
+ *      stored in the Message_Block array.
+ *
+ *  Parameters:
+ *      None.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *      Many of the variable names in this code, especially the
+ *      single character names, were used because those were the
+ *      names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+    const uint32_t K[] =    {       /* Constants defined in SHA-1   */
+                            0x5A827999,
+                            0x6ED9EBA1,
+                            0x8F1BBCDC,
+                            0xCA62C1D6
+                            };
+    int           t;                 /* Loop counter                */
+    uint32_t      temp;              /* Temporary word value        */
+    uint32_t      W[80];             /* Word sequence               */
+    uint32_t      A, B, C, D, E;     /* Word buffers                */
+
+    /*
+     *  Initialize the first 16 words in the array W
+     */
+    for(t = 0; t < 16; t++)
+    {
+        W[t] = context->Message_Block[t * 4] << 24;
+        W[t] |= context->Message_Block[t * 4 + 1] << 16;
+        W[t] |= context->Message_Block[t * 4 + 2] << 8;
+        W[t] |= context->Message_Block[t * 4 + 3];
+    }
+
+    for(t = 16; t < 80; t++)
+    {
+       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = context->Intermediate_Hash[0];
+    B = context->Intermediate_Hash[1];
+    C = context->Intermediate_Hash[2];
+    D = context->Intermediate_Hash[3];
+    E = context->Intermediate_Hash[4];
+
+    for(t = 0; t < 20; t++)
+    {
+        temp =  SHA1CircularShift(5,A) +
+                ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for(t = 20; t < 40; t++)
+    {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for(t = 40; t < 60; t++)
+    {
+        temp = SHA1CircularShift(5,A) +
+               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for(t = 60; t < 80; t++)
+    {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    context->Intermediate_Hash[0] += A;
+    context->Intermediate_Hash[1] += B;
+    context->Intermediate_Hash[2] += C;
+    context->Intermediate_Hash[3] += D;
+    context->Intermediate_Hash[4] += E;
+
+    context->Message_Block_Index = 0;
+}
+
+
+/*
+ *  SHA1PadMessage
+ *
+ *  Description:
+ *      According to the standard, the message must be padded to an even
+ *      512 bits.  The first padding bit must be a '1'.  The last 64
+ *      bits represent the length of the original message.  All bits in
+ *      between should be 0.  This function will pad the message
+ *      according to those rules by filling the Message_Block array
+ *      accordingly.  It will also call the ProcessMessageBlock function
+ *      provided appropriately.  When it returns, it can be assumed that
+ *      the message digest has been computed.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to pad
+ *      ProcessMessageBlock: [in]
+ *          The appropriate SHA*ProcessMessageBlock function
+ *  Returns:
+ *      Nothing.
+ *
+ */
+
+void SHA1PadMessage(SHA1Context *context)
+{
+    /*
+     *  Check to see if the current message block is too small to hold
+     *  the initial padding bits and length.  If so, we will pad the
+     *  block, process it, and then continue padding into a second
+     *  block.
+     */
+    if (context->Message_Block_Index > 55)
+    {
+        context->Message_Block[context->Message_Block_Index++] = 0x80;
+        while(context->Message_Block_Index < 64)
+        {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+
+        SHA1ProcessMessageBlock(context);
+
+        while(context->Message_Block_Index < 56)
+        {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+    }
+    else
+    {
+        context->Message_Block[context->Message_Block_Index++] = 0x80;
+        while(context->Message_Block_Index < 56)
+        {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+    }
+
+    /*
+     *  Store the message length as the last 8 octets
+     */
+    context->Message_Block[56] = context->Length_High >> 24;
+    context->Message_Block[57] = context->Length_High >> 16;
+    context->Message_Block[58] = context->Length_High >> 8;
+    context->Message_Block[59] = context->Length_High;
+    context->Message_Block[60] = context->Length_Low >> 24;
+    context->Message_Block[61] = context->Length_Low >> 16;
+    context->Message_Block[62] = context->Length_Low >> 8;
+    context->Message_Block[63] = context->Length_Low;
+
+    SHA1ProcessMessageBlock(context);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1.h	Wed Mar 23 19:53:42 2011 +0000
@@ -0,0 +1,85 @@
+/*
+ *  sha1.h
+ *
+ *  Description:
+ *      This is the header file for code which implements the Secure
+ *      Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ *      April 17, 1995.
+ *
+ *      Many of the variable names in this code, especially the
+ *      single character names, were used because those were the names
+ *      used in the publication.
+ *
+ *      Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#include <stdint.h>
+typedef unsigned long uint32_t;
+typedef int int_least16_t;
+typedef unsigned char uint8_t;
+
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ *    name              meaning
+ *  uint32_t         unsigned 32 bit integer
+ *  uint8_t          unsigned 8 bit integer (i.e., unsigned char)
+ *  int_least16_t    integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+    shaSuccess = 0,
+    shaNull,            /* Null pointer parameter */
+    shaInputTooLong,    /* input data too long */
+    shaStateError       /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ *  This structure will hold context information for the SHA-1
+ *  hashing operation
+ */
+typedef struct SHA1Context
+{
+    uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest  */
+
+    uint32_t Length_Low;            /* Message length in bits      */
+    uint32_t Length_High;           /* Message length in bits      */
+
+                               /* Index into message block array   */
+    int_least16_t Message_Block_Index;
+    uint8_t Message_Block[64];      /* 512-bit message blocks      */
+
+    int Computed;               /* Is the digest computed?         */
+    int Corrupted;             /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ *  Function Prototypes
+ */
+
+int SHA1Reset(  SHA1Context *);
+int SHA1Input(  SHA1Context *,
+                const uint8_t *,
+                unsigned int);
+int SHA1Result( SHA1Context *,
+                uint8_t Message_Digest[SHA1HashSize]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif