diff --git a/world/net/http/fetch.c b/world/net/http/fetch.c index 9f39d1e..0502524 100644 --- a/world/net/http/fetch.c +++ b/world/net/http/fetch.c @@ -92,6 +92,11 @@ void connect() { ::connect(thehost, port); } +// some people think these are case sensitive.. let's fix it for them (only works for most cases) +string http_header_capitalize(string name) { + return regreplace(name, "(^.|-.)", (: return upper_case($1); :), 1); +} + varargs int real_logon(int failure) { string scheme; @@ -115,7 +120,7 @@ varargs int real_logon(int failure) { buffer = ""; foreach (string key, string value : rheaders) { - buffer += key + ": " + value + "\r\n"; + buffer += http_header_capitalize(key) + ": " + value + "\r\n"; } // we won't need connection: close w/ http/1.0 diff --git a/world/net/http/oauth.c b/world/net/http/oauth.c index 05ae63d..a8c455c 100644 --- a/world/net/http/oauth.c +++ b/world/net/http/oauth.c @@ -59,6 +59,7 @@ void parse_request_token(string body, mapping headers, int http_status) { url_parse_query(request_params, body); if (strlen(request_params["oauth_token"]) && strlen(request_params["oauth_token_secret"])) { shared_memory("oauth_request_tokens")[request_params["oauth_token"]] = ME; + //P3((">>> adding token: %O to shm: %O\n", request_params["oauth_token"], shared_memory("oauth_request_tokens"))) sendmsg(user, "_notice_oauth_authorize_url", "Open [_url] to perform authorization.", (["_url": authorize_url + "?oauth_token=" + request_params["oauth_token"]])); return; diff --git a/world/net/http/server.c b/world/net/http/server.c index 3bbde54..d83b0eb 100644 --- a/world/net/http/server.c +++ b/world/net/http/server.c @@ -179,8 +179,8 @@ case "/static/": case "/oauth": object oauth; http_ok(version); - //PT((">>> shm: %O\n", shared_memory("oauth_request_tokens"))) - if (query["oauth_verifier"] && (oauth = shared_memory("oauth_request_tokens")[query["oauth_token"]])) { + //PT((">>> looking up token %O in shm: %O\n", query["oauth_token"], shared_memory("oauth_request_tokens"))) + if (oauth = shared_memory("oauth_request_tokens")[query["oauth_token"]]) { //PT((">>> oauth: %O\n", oauth)) oauth->verified(query["oauth_verifier"]); m_delete(shared_memory("oauth_request_tokens"), query["oauth_token"]); diff --git a/world/net/identica/client.c b/world/net/identica/client.c new file mode 100644 index 0000000..c3ddd98 --- /dev/null +++ b/world/net/identica/client.c @@ -0,0 +1,24 @@ +/* identi.ca client, uses the twitter api + * http://status.net/wiki/Twitter-compatible_API + * + * - register app @ http://identi.ca/settings/oauthapps + * - then in local.h #define IDENTICA_KEY & IDENTICA_SECRET + */ + +#include + +inherit NET_PATH "twitter/client"; + +object load(object usr, string key, string secret, string request, string access, string authorize) { + name = "identica"; + display_name = "identi.ca"; + api_base_url = "http://identi.ca/api"; + + unless (consumer_key) consumer_key = IDENTICA_KEY; + unless (consumer_secret) consumer_secret = IDENTICA_SECRET; + unless (request_token_url) request_token_url = api_base_url + "/oauth/request_token"; + unless (access_token_url) access_token_url = api_base_url + "/oauth/access_token"; + unless (authorize_url) authorize_url = api_base_url + "/oauth/authorize"; + + return ::load(usr, key, secret, request, access, authorize); +} diff --git a/world/net/library/signature.c b/world/net/library/signature.c index 40593f7..b4fccca 100644 --- a/world/net/library/signature.c +++ b/world/net/library/signature.c @@ -75,13 +75,18 @@ private volatile mapping _sigs = ([ "_request_pub": ({ "_request_public", 0, "_flag_public" }), "_request_entries": ({ "_request_entries", 0, "_num" }), + "_request_ents": ({ "_request_entries", 0, "_num" }), "_request_entry": ({ "_request_entry", 0, "_id" }), + "_request_ent": ({ "_request_entry", 0, "_id" }), "_request_comment": ({ "_request_comment", 0, "_id", "_text" }), + "_request_com": ({ "_request_comment", 0, "_id", "_text" }), "_request_thread": ({ "_request_thread", 0, "_id", "_title" }), "_request_addentry": ({ "_request_addentry", 0, "_text" }), + "_request_addent": ({ "_request_addentry", 0, "_text" }), "_request_submit": ({ "_request_addentry", 0, "_text" }), "_request_blog": ({ "_request_addentry", 0, "_text" }), "_request_delentry": ({ "_request_delentry", 0, "_id" }), + "_request_delent": ({ "_request_delentry", 0, "_id" }), "_request_unsubmit": ({ "_request_delentry", 0, "_id" }), "_request_unblog": ({ "_request_delentry", 0, "_id" }), #ifdef _flag_enable_module_microblogging @@ -91,6 +96,8 @@ private volatile mapping _sigs = ([ "_request_privacy": ({ "_request_privacy", 0, "_privacy" }), "_request_tw": ({ "_request_twitter", 0, "_switch" }), "_request_twitter": ({ "_request_twitter", 0, "_switch" }), + "_request_ica": ({ "_request_identica", 0, "_switch" }), + "_request_identica": ({ "_request_identica", 0, "_switch" }), #endif #ifdef EXPERIMENTAL // stuff to play around with diff --git a/world/net/person.c b/world/net/person.c index 4d46681..fb70bde 100644 --- a/world/net/person.c +++ b/world/net/person.c @@ -475,7 +475,8 @@ qDescription(source, vars, profile, itsme) { unless (objectp(p) && (p->isPublic() || (source && p->qMember(source))) /*&& p->numEntries() > 0*/) continue; channels += ([ p->qChannel(): p->entries(10)]); } - dv["_channels"] = make_json(channels); + // don't make_json for anonymous queries which are handled locally + dv["_channels"] = source ? make_json(channels) : channels; #endif // PT(("sending: %O\n", dv)) return dv; diff --git a/world/net/place/userthreads.c b/world/net/place/userthreads.c index e62e3d3..744f4fc 100644 --- a/world/net/place/userthreads.c +++ b/world/net/place/userthreads.c @@ -16,7 +16,7 @@ volatile mixed lastTry; volatile string owner; volatile string channel; -volatile object twitter; +volatile object twitter, identica; load(name, keep) { P3((">> userthreads:load(%O, %O)\n", name, keep)) @@ -25,6 +25,7 @@ load(name, keep) { vSet("owners", ([ owner: 0 ])); vSet("privacy", "private"); vSet("twitter", 0); + vSet("identica", 0); vSet("_restrict_invitation", BLAME); vSet("_filter_conversation", BLAME); @@ -55,6 +56,7 @@ enter(source, mc, data, vars) { if (p == source) { p->sChannel(MYNICK); if (v("twitter") && !twitter) twitter = clone_object(NET_PATH "twitter/client")->load(source); + if (v("identica") && !identica) identica = clone_object(NET_PATH "identica/client")->load(source); } return ::enter(source, mc, data, vars); @@ -144,9 +146,29 @@ _request_twitter(source, mc, data, vars, b) { return 1; } +_request_identica(source, mc, data, vars, b) { + string sw = vars["_switch"]; + if (sw == "on" || sw == "enabled" || sw == "1") { + unless (identica) identica = clone_object(NET_PATH "identica/client")->load(source); + vSet("identica", 1); + save(); + } else if (sw == "off" || sw == "disabled" || sw == "0") { + if (identica) identica = 0; + vSet("identica", 0); + save(); + } + DT(else if (sw == "test") identica->home_timeline();) + + sendmsg(source, "_status_identica", "Identi.ca submission is [_status].", (["_status": v("identica") ? "enabled" : "disabled"])); + return 1; +} + + addEntry(text, unick, thread) { - if (::addEntry(text, unick, thread) && v("twitter") && twitter) - twitter->status_update(text); + if (::addEntry(text, unick, thread)) { + if (v("twitter") && twitter) twitter->status_update(text); + if (v("identica") && identica) identica->status_update(text); + } } htMain(int last) { diff --git a/world/net/twitter/client.c b/world/net/twitter/client.c index 1ce8ca4..3c84afb 100644 --- a/world/net/twitter/client.c +++ b/world/net/twitter/client.c @@ -15,12 +15,18 @@ inherit NET_PATH "http/oauth"; +string name = "twitter"; +string display_name = "twitter"; +string api_base_url = "http://api.twitter.com/1"; + +int status_max_len = 140; + object load(object usr, string key, string secret, string request, string access, string authorize) { - consumer_key = TWITTER_KEY; - consumer_secret = TWITTER_SECRET; - request_token_url = "http://twitter.com/oauth/request_token"; - access_token_url = "http://twitter.com/oauth/access_token"; - authorize_url = "http://twitter.com/oauth/authorize"; + unless (consumer_key) consumer_key = TWITTER_KEY; + unless (consumer_secret) consumer_secret = TWITTER_SECRET; + unless (request_token_url) request_token_url = "http://twitter.com/oauth/request_token"; + unless (access_token_url) access_token_url = "http://twitter.com/oauth/access_token"; + unless (authorize_url) authorize_url = "http://twitter.com/oauth/authorize"; return ::load(usr, key, secret, request, access, authorize); } @@ -28,18 +34,19 @@ object load(object usr, string key, string secret, string request, string access void parse_status_update(string body, string headers, int http_status) { P3(("twitter/client:parse_status_update(%O, %O, %O)\n", body, headers, http_status)) if (http_status != R_OK) - sendmsg(user, "_error_twitter_status_update", "Error: failed to post status update on twitter."); + sendmsg(user, "_error_"+name+"_status_update", "Error: failed to post status update on [_name].", (["_name": display_name])); } void status_update(string text) { P3(("twitter/client:status_update()\n")) - if (strlen(text) > 140) text = text[0..136] + "..."; + if (status_max_len && strlen(text) > status_max_len) text = text[0..status_max_len-4] + "..."; object ua = clone_object(NET_PATH "http/fetch"); ua->content(#'parse_status_update, 1, 1); //'); - fetch(ua, "http://api.twitter.com/1/statuses/update.json", "POST", (["status": text])); + fetch(ua, api_base_url + "/statuses/update.json", "POST", (["status": text])); } +#if 1 //not used, just an example void parse_home_timeline(string body, string headers, int http_status) { P3(("twitter/client:parse_home_timeline(%O, %O, %O)\n", body, headers, http_status)) } @@ -48,5 +55,6 @@ void home_timeline() { P3(("twitter/client:home_timeline()\n")) object ua = clone_object(NET_PATH "http/fetch"); ua->content(#'parse_home_timeline, 1, 1); //'); - fetch(ua, "http://api.twitter.com/1/statuses/home_timeline.json"); + fetch(ua, api_base_url + "/statuses/home_timeline.json"); } +#endif diff --git a/world/net/user.c b/world/net/user.c index 5e928cd..4a72fc2 100644 --- a/world/net/user.c +++ b/world/net/user.c @@ -285,9 +285,11 @@ htDescription(anonymous, query, headers, qs, variant, vars) { // # ifdef _flag_enable_module_microblogging - mapping channels; string htchannels; - if (vars["_channels"] && (channels = parse_json(vars["_channels"]))) { + mapping channels; + if (mappingp(vars["_channels"])) channels = vars["_channels"]; + else channels = parse_json(vars["_channels"]); + if (channels) { P3((">>> channels: %O\n", channels)) htchannels = "