added identi.ca support (uses twitter api); spare a json enc/dec when surfing locally

This commit is contained in:
Gabor Adam Toth 2010-02-23 23:42:54 +01:00
parent bcbf2785d8
commit 9421149ffd
9 changed files with 88 additions and 18 deletions

View File

@ -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

View File

@ -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;

View File

@ -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"]);

View File

@ -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 <net.h>
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);
}

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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 =
"<script type='text/javascript'>\n"