Mercurial > pidgin-twitter
view twitter_api.c @ 364:cbdf0b35d31b default tip
Added tag 0.9.2.1 for changeset 85e109dee063
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Fri, 13 May 2011 00:02:49 +0900 |
parents | c6392a86839b |
children |
line wrap: on
line source
#include "pidgin-twitter.h" static GList *postedlist = NULL; static GList *statuseslist = NULL; /* prototypes */ static void parse_user(xmlNode *user, status_t *st); static void read_timestamp(const char *str, struct tm *res); static void parse_status(xmlNode *status, status_t *st); static void free_status(status_t *st); static gboolean is_posted_message(status_t *status, guint64 lastid); static void get_status_with_api_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message); static void post_status_with_api_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message); /* oauth */ #define TYPE_GET 0 #define TYPE_POST 1 char *c_key = "wrD3WGIh2P31d3fIjRkfcw"; char *c_sec = "ZEhViGY8P5IPjwgV8EVOkdjHhShRAZ9yhlYw0ZDXU"; char *SAMPLE_NONCE = "0123456789abcdefghijk"; typedef struct oauth_request { char *url; char *c_key; char *c_sec; char *a_key; char *a_sec; char *verifier; char *status; PurpleConversation *conv; guint64 msgid; int count; int type; gboolean notoken; } oauth_request_t; char *make_oauth_get(oauth_request_t *oauth_req); char *make_oauth_post(oauth_request_t *auth_req); static void oauth_setup_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message); #ifdef _WIN32 extern gboolean blink_state; extern gboolean blink_modified; #endif extern guint64 reply_to_msgid; extern PurpleAccount *account_for_twitter; /* oauth functions */ void oauth_access_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) { char *f = NULL, *e = NULL; oauth_request_t *oauth_req = (oauth_request_t *)user_data; /* separate key and secret */ f = strstr(url_text, "oauth_token="); if(!f) return; e = strstr(f, "&"); if(!e) return; g_free(oauth_req->a_key); oauth_req->a_key = g_strndup(f+12, e-f-12); f = strstr(e+1, "oauth_token_secret="); if(!f) return; e = strstr(f, "&"); if(!e) return; g_free(oauth_req->a_sec); oauth_req->a_sec = g_strndup(f+19, e-f-19); /* write a_key and a_sec to prefs */ purple_prefs_set_string(OPT_AKEY_TWITTER, oauth_req->a_key); purple_prefs_set_string(OPT_ASEC_TWITTER, oauth_req->a_sec); /* invoke fetch xxx */ g_usleep(3*1000000); /* wait for server configuration */ get_status_with_api((gpointer)oauth_req->conv); /* all done */ g_free(oauth_req->url); g_free(oauth_req->c_key); g_free(oauth_req->c_sec); g_free(oauth_req->a_key); g_free(oauth_req->a_sec); g_free(oauth_req); } void pin_dialog_ok_cb(gpointer data, char *pin) { char *oauth = NULL; char *request = NULL; oauth_request_t *oauth_req = (oauth_request_t *)data; /* request URL:http://twitter.com/oauth/access_token? oauth_consumer_key=wrD3WGIh2P31d3fIjRkfcw& oauth_nonce=QUzhkt0AO3tjNrR& oauth_signature_method=HMAC-SHA1& oauth_timestamp=1282450223& oauth_token=VL126k8KRNXid7Q7ZHYHh05PuASunVaPzyzrozf14& oauth_verifier=9772286& oauth_version=1.0& oauth_signature=OyBsxqWdsvLkV4LBnN8tMBnImVY%3D */ /* access token*/ g_free(oauth_req->url); oauth_req->url = g_strdup(ACCESS_TOKEN_URL); oauth_req->verifier = g_strdup(pin); oauth_req->type = TYPE_GET; oauth_req->notoken = FALSE; twitter_debug("a_key=%s\n", oauth_req->a_key); oauth = make_oauth_get(oauth_req); request = g_strdup_printf("%s?%s", ACCESS_TOKEN_URL, oauth); twitter_debug("request=%s\n", request); purple_util_fetch_url_request(request, TRUE, NULL, TRUE, NULL, TRUE, oauth_access_cb, data); g_free(oauth); g_free(request); } static void oauth_setup_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) { char *f = NULL, *e = NULL; oauth_request_t *oauth_req = (oauth_request_t *)user_data; PurpleConversation *conv = oauth_req->conv; PurpleAccount *account = purple_conversation_get_account(conv); PurpleConnection *conn = purple_conversation_get_gc(conv); g_return_if_fail(url_text != NULL); twitter_debug("len=%d\n", (int)len); twitter_debug("url_text=%s\n", url_text); /* HTTP-reply: oauth_token=zKILrNcVPGRtUE6Rlh1KU6upYNJWW51mzt7btZx5Ac& oauth_token_secret=EMD3u1piAKPsQnq44Its9f8WmIReYnUFcJIgd3niu4& oauth_callback_confirmed=true */ /* separate key and secret */ f = strstr(url_text, "oauth_token="); if(!f) return; e = strstr(f, "&"); if(!e) return; g_free(oauth_req->a_key); oauth_req->a_key = g_strndup(f+12, e-f-12); f = strstr(e+1, "oauth_token_secret="); if(!f) return; e = strstr(f, "&"); if(!e) return; g_free(oauth_req->a_sec); oauth_req->a_sec = g_strndup(f+19, e-f-19); /* redirect to twitter's authorization url */ char *uri = g_strdup_printf("%s?oauth_token=%s", AUTHORIZE_URL, oauth_req->a_key); twitter_debug("auth uri=%s\n", uri); purple_notify_uri(conn, uri); /* show dialog to wait PIN */ purple_request_input(conn, "PIN", "Enter PIN", "Press allow button in the browser, then enter the PIN to complete process.", "", FALSE, FALSE, NULL, "OK", G_CALLBACK(pin_dialog_ok_cb), "Cancel", NULL, account, NULL, NULL, user_data); g_free(uri); } void oauth_setup(gpointer data) { char *oauth = NULL; char *request = NULL; oauth_request_t *oauth_req = g_new0(oauth_request_t, 1); /* persistent */ /* http://twitter.com/oauth/request_token? oauth_consumer_key=wrD3WGIh2P31d3fIjRkfcw& oauth_nonce=HCUxu1D3qN4Nklr9QVAymve40PtJyU& oauth_signature_method=HMAC-SHA1& oauth_timestamp=1282446611&oauth_version=1.0& oauth_signature=A%2BZIiUVsQv5ZR8u%2F2oLmUFX1eHE%3D */ oauth_req->url = strdup(REQUEST_TOKEN_URL); oauth_req->c_key = strdup(c_key); oauth_req->c_sec = strdup(c_sec); oauth_req->a_key = NULL; oauth_req->a_sec = NULL; oauth_req->type = TYPE_GET; oauth_req->notoken = TRUE; oauth_req->conv = (PurpleConversation *)data; /* request token*/ oauth = make_oauth_get(oauth_req); request = g_strdup_printf("%s?%s", REQUEST_TOKEN_URL, oauth); twitter_debug("request=%s\n", request); purple_util_fetch_url_request(request, TRUE, NULL, TRUE, NULL, TRUE, oauth_setup_cb, oauth_req); } char * hmac_sha1(char *text, char *key) { PurpleCipherContext *context = NULL; size_t len; guchar digest[255]; char *signature = NULL; twitter_debug("text=%s\n", text); twitter_debug("key=%s\n", key); context = purple_cipher_context_new_by_name("hmac", NULL); if(!context) return NULL; purple_cipher_context_set_option(context, "hash", "sha1"); purple_cipher_context_set_key(context, (guchar *)key); purple_cipher_context_append(context, (guchar *)text, strlen(text)); if(purple_cipher_context_digest(context, sizeof(digest), digest, &len)) { signature = purple_base64_encode(digest, len); twitter_debug("hmac1 signature=%s\n", signature); } else { twitter_debug("digest signature failed\n"); } purple_cipher_context_destroy(context); return signature; } char * make_oauth_get(oauth_request_t *req) { gchar *tmp = NULL; char *signature = NULL; time_t current_time = time(NULL); char *params = NULL; char *oauth; char *count_str = NULL; char *token_str = NULL; char *verifier_str = NULL; if(req->count) count_str = g_strdup_printf("count=%d&", req->count); else count_str = g_strdup(""); if(req->notoken) { twitter_debug("notoken\n"); token_str = g_strdup(""); } else token_str = g_strdup_printf("oauth_token=%s&", req->a_key?req->a_key:req->c_key); if(req->verifier) verifier_str = g_strdup_printf("oauth_verifier=%s&", req->verifier); else verifier_str = g_strdup(""); params = g_strdup_printf("%soauth_consumer_key=%s&oauth_nonce=%s&oauth_signature_method=HMAC-SHA1&oauth_timestamp=%d&%s%soauth_version=1.0", count_str, req->c_key, SAMPLE_NONCE, (int)current_time, token_str, verifier_str); g_free(count_str); g_free(token_str); g_free(verifier_str); const char *url_encoded = g_uri_escape_string(req->url, "", FALSE); const char *params_encoded = g_uri_escape_string(params, "", FALSE); tmp = g_strdup_printf("GET&%s&%s", url_encoded, params_encoded); char *key = g_strdup_printf("%s&%s", req->c_sec, req->a_sec?req->a_sec:""); signature = hmac_sha1(tmp, key); g_free(key); const char *signature_encoded = g_uri_escape_string(signature, "", FALSE); oauth = g_strdup_printf("%s&oauth_signature=%s", params, signature_encoded); g_free(tmp); g_free(signature); g_free(params); twitter_debug("oauth_block=%s\n", oauth); return oauth; } char * make_oauth_post(oauth_request_t *req) { gchar *tmp = NULL; char *signature = NULL; time_t current_time = time(NULL); char *params = NULL; char *oauth; char *status_str = NULL; char *msgid_str = NULL; if(req->status) status_str = g_strdup_printf("&status=%s", req->status); else status_str = g_strdup(""); if(req->msgid) msgid_str = g_strdup_printf("in_reply_to_status_id=%llu&", (long long unsigned int)req->msgid); else msgid_str = g_strdup(""); params = g_strdup_printf("%soauth_consumer_key=%s&oauth_nonce=%s&oauth_signature_method=HMAC-SHA1&oauth_timestamp=%d&oauth_token=%s&oauth_version=1.0%s", msgid_str, req->c_key, SAMPLE_NONCE, (int)current_time, req->a_key, status_str); g_free(status_str); g_free(msgid_str); const char *url_encoded = g_uri_escape_string(req->url, "", FALSE); const char *params_encoded = g_uri_escape_string(params, "", FALSE); tmp = g_strdup_printf("POST&%s&%s", url_encoded, params_encoded); char *key = g_strdup_printf("%s&%s", req->c_sec, req->a_sec); signature = hmac_sha1(tmp, key); g_free(key); const char *signature_encoded = g_uri_escape_string(signature, "", FALSE); oauth = g_strdup_printf("%s&oauth_signature=%s", params, signature_encoded); g_free(tmp); g_free(signature); g_free(params); twitter_debug("oauth_block=%s\n", oauth); return oauth; } /**************************/ /* API base get functions */ /**************************/ /* xml parser */ static void parse_user(xmlNode *user, status_t *st) { xmlNode *nptr; for(nptr = user->children; nptr != NULL; nptr = nptr->next) { if(nptr->type == XML_ELEMENT_NODE) { if(!xmlStrcmp(nptr->name, (xmlChar *)"screen_name")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->screen_name = g_strdup(str); twitter_debug("screen_name=%s\n", st->screen_name); xmlFree(str); } else if(!xmlStrcmp(nptr->name, (xmlChar *)"profile_image_url")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->profile_image_url = g_strdup(str); xmlFree(str); } } } } static gchar *day_of_week_name[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; static gchar *month_name[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; static void read_timestamp(const char *str, struct tm *res) { char day_of_week[4]; char month[4]; char time_offset[6]; int day, hour, minute, second, year; int i; if(str == NULL || res == NULL) return; sscanf(str, "%s %s %d %d:%d:%d %s %d", day_of_week, month, &day, &hour, &minute, &second, time_offset, &year); for(i=0; i<7; i++) { if(!strcmp(day_of_week_name[i], day_of_week)) { res->tm_wday = i; } } for(i=0; i<12; i++) { if(!strcmp(month_name[i], month)) { res->tm_mon = i; } } res->tm_mday = day; res->tm_hour = hour; res->tm_min = minute; res->tm_sec = second; res->tm_year = year - 1900; #ifndef _WIN32 int offset = atoi(time_offset); res->tm_gmtoff = -1 * (60 * 60 * offset / 100); #endif } static void parse_status(xmlNode *status, status_t *st) { xmlNode *nptr; for(nptr = status->children; nptr != NULL; nptr = nptr->next) { if(nptr->type == XML_ELEMENT_NODE) { if(!xmlStrcmp(nptr->name, (xmlChar *)"created_at")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->created_at = g_strdup(str); /* read time stamp */ struct tm res; memset(&res, 0x00, sizeof(struct tm)); read_timestamp(str, &res); tzset(); #ifdef _WIN32 st->time = mktime(&res) - timezone; #else st->time = mktime(&res) + res.tm_gmtoff; #endif xmlFree(str); } else if(!xmlStrcmp(nptr->name, (xmlChar *)"id")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->id = atoll(str); twitter_debug("id=%llu\n", (long long unsigned int)st->id); xmlFree(str); } else if(!xmlStrcmp(nptr->name, (xmlChar *)"text")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->text = g_strdup(str); xmlFree(str); } else if(!xmlStrcmp(nptr->name, (xmlChar *)"user")) { parse_user(nptr, st); } else if(!xmlStrcmp(nptr->name, (xmlChar *)"in_reply_to_status_id")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->in_reply_to_status_id = atoll(str); twitter_debug("in_reply_to_status_id=%llu\n", (long long unsigned int)st->in_reply_to_status_id); xmlFree(str); } else if(!xmlStrcmp(nptr->name, (xmlChar *)"in_reply_to_screen_name")) { gchar *str = (gchar *)xmlNodeGetContent(nptr); st->in_reply_to_screen_name = g_strdup(str); twitter_debug("in_reply_to_screen_name=%s\n", st->in_reply_to_screen_name); xmlFree(str); } } } } static void free_status(status_t *st) { g_free(st->created_at); g_free(st->text); g_free(st->screen_name); g_free(st->profile_image_url); g_free(st->in_reply_to_screen_name); } static gboolean is_posted_message(status_t *status, guint64 lastid) { GList *pp = g_list_first(postedlist); gboolean rv = FALSE; while(pp) { GList *next; status_t *posted = (status_t *)pp->data; next = g_list_next(pp); if(posted->id == status->id) { rv = TRUE; } if(posted->id <= lastid) { free_status(posted); g_free(pp->data); postedlist = g_list_delete_link(postedlist, pp); } pp = next; } return rv; } static void get_status_with_api_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) { xmlDocPtr doc; xmlNode *nptr, *nptr2; static guint64 lastid = 0; PurpleConversation *conv; GList *stp; const gchar *start; g_return_if_fail(url_text != NULL); conv = (PurpleConversation *)user_data; if(!conv) return; /* skip to the beginning of xml */ start = strstr(url_text, "<?xml"); doc = xmlRecoverMemory(start, len - (start - url_text)); if(doc == NULL) return; #ifdef _WIN32 /* suppress notification of incoming messages. */ if(purple_prefs_get_bool(OPT_PREVENT_NOTIFICATION)) { if(!blink_modified) { blink_modified = TRUE; blink_state = purple_prefs_get_bool(OPT_PIDGIN_BLINK_IM); purple_prefs_set_bool(OPT_PIDGIN_BLINK_IM, FALSE); } } #endif for(nptr = doc->children; nptr != NULL; nptr = nptr->next) { if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, (xmlChar *)"statuses")) { for(nptr2 = nptr->children; nptr2 != NULL; nptr2 = nptr2->next) { if(nptr2->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr2->name, (xmlChar *)"status")) { status_t *st = g_new0(status_t, 1); statuseslist = g_list_prepend(statuseslist, st); parse_status(nptr2, st); } } } } xmlFreeDoc(doc); xmlCleanupParser(); /* process statuseslist */ stp = g_list_first(statuseslist); while(stp) { GList *next; status_t *st = (status_t *)stp->data; next = g_list_next(stp); if(st->id > lastid && !is_posted_message(st, lastid)) { gchar *msg = NULL; gchar *sender = NULL; sender = g_strdup("twitter@twitter.com"); PurpleMessageFlags flag = PURPLE_MESSAGE_RECV; msg = g_strdup_printf("%s: %s pttag=%llu:%llu:%s", st->screen_name, st->text, (long long unsigned int)st->id, (long long unsigned int)st->in_reply_to_status_id, st->in_reply_to_screen_name ? st->in_reply_to_screen_name : ""); /* apply filter */ if(purple_prefs_get_bool(OPT_FILTER)) { apply_filter(&sender, &msg, &flag, twitter_service); } if(sender && msg) { purple_conv_im_write(conv->u.im, sender, msg, flag, st->time); } lastid = st->id; g_free(sender); g_free(msg); } free_status(st); g_free(stp->data); statuseslist = g_list_delete_link(statuseslist, stp); stp = next; } } /* status fetching function. it will be called periodically. */ gboolean get_status_with_api(gpointer data) { twitter_debug("called\n"); /* fetch friends time line */ char *request, *header; gint count = purple_prefs_get_int(OPT_RETRIEVE_COUNT); char *oauth; const char *a_key = NULL; const char *a_sec = NULL; static gboolean setup = FALSE; oauth_request_t oauth_req; a_key = purple_prefs_get_string(OPT_AKEY_TWITTER); a_sec = purple_prefs_get_string(OPT_ASEC_TWITTER); if(!a_key || !a_sec) { if(!setup) { oauth_setup(data); setup = TRUE; } return TRUE; } if(count < TWITTER_DEFAULT_RETRIEVE_COUNT) count = TWITTER_DEFAULT_RETRIEVE_COUNT; /* if disabled, just return */ if(!purple_prefs_get_bool(OPT_API_BASE_POST)) return TRUE; /* oauth */ char *url0 = g_strdup_printf(TWITTER_API_BASE_URL "/1/statuses/home_timeline.xml"); oauth_req.url = url0; oauth_req.c_key = c_key; oauth_req.c_sec = c_sec; oauth_req.a_key = (char *)a_key; oauth_req.a_sec = (char *)a_sec; oauth_req.verifier = NULL; oauth_req.status = NULL; oauth_req.type = TYPE_GET; oauth_req.count = count; oauth_req.msgid = 0; oauth_req.notoken = FALSE; oauth = make_oauth_get(&oauth_req); g_free(url0); /* header */ header = g_strdup_printf(TWITTER_STATUS_GET, oauth); request = g_strconcat(header, "\r\n", NULL); twitter_debug("request=%s\n", request); /* invoke fetch */ purple_util_fetch_url_request(TWITTER_API_BASE_URL, FALSE, NULL, TRUE, request, TRUE, get_status_with_api_cb, data); g_free(header); g_free(request); g_free(oauth); return TRUE; } /****************************/ /* API based post functions */ /****************************/ static void post_status_with_api_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) { twitter_message_t *tm = (twitter_message_t *)user_data; gchar *msg = NULL; char *p1 = NULL, *p2 = NULL; int error = 1; PurpleConversation *conv; conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, "twitter@twitter.com", tm->account); if (!conv) { twitter_debug("failed to get conversation\n"); goto fin; } if (error_message) { /* connection failed or something */ msg = g_strdup_printf("Local error: %s", error_message); } else { int code = -1; if ((strncmp(url_text, "HTTP/1.0", strlen("HTTP/1.0")) == 0 || strncmp(url_text, "HTTP/1.1", strlen("HTTP/1.1")) == 0)) { p1 = strchr(url_text, ' '); if (p1) { p1++; p2 = strchr(p1, ' '); if (p2) p2++; else p2 = NULL; } } code = atoi(p1); if (code == 200) { error = 0; } else { switch (code) { case 400: msg = g_strdup("Invalid request. Too many updates?"); break; case 401: msg = g_strdup("Authorization failed."); break; case 403: msg = g_strdup("Your update has been refused by Twitter server " "for some reason."); break; case 404: msg = g_strdup("Requested URI is not found."); break; case 500: msg = g_strdup("Server error."); break; case 502: msg = g_strdup("Twitter is down or under maintenance."); break; case 503: msg = g_strdup("Twitter is extremely crowded. " "Try again later."); break; default: msg = g_strdup_printf("Unknown error. (%d %s)", code, p2 ? p2 : ""); break; } } } if (!error) { /* cache message ID that posted via API */ gchar *start = NULL; xmlDocPtr doc; xmlNode *nptr; status_t *st; gchar *m; start = strstr(url_text, "<?xml"); if(!start) goto fin; doc = xmlRecoverMemory(start, len - (start - url_text)); if(doc == NULL) return; /* enqueue posted message to postedlist */ for(nptr = doc->children; nptr != NULL; nptr = nptr->next) { if(nptr->type == XML_ELEMENT_NODE && !xmlStrcmp(nptr->name, (xmlChar *)"status")) { st = g_new0(status_t, 1); postedlist = g_list_prepend(postedlist, st); parse_status(nptr, st); } } xmlFreeDoc(doc); xmlCleanupParser(); m = g_strdup_printf("%s pttag=%llu:%llu:%s", tm->status, (long long unsigned int)st->id, (long long unsigned int)st->in_reply_to_status_id, st->in_reply_to_screen_name ? st->in_reply_to_screen_name : ""); purple_conv_im_write(conv->u.im, purple_account_get_username(tm->account), m, PURPLE_MESSAGE_SEND, tm->time); g_free(m); } else { gchar *m; m = g_strdup_printf("%s<BR>%s", msg, tm->status); /* FIXME: too strong. it should be more smart */ purple_conv_im_write(conv->u.im, purple_account_get_username(tm->account), m, PURPLE_MESSAGE_ERROR, time(NULL)); g_free(m); } fin: if (msg) g_free(msg); if (tm) { if (tm->status) g_free(tm->status); g_free(tm); } } void post_status_with_api(PurpleAccount *account, char **buffer) { char *request, *header; const char *url_encoded = g_uri_escape_string(*buffer, "", FALSE); char *oauth; twitter_message_t *tm; const char *a_key = NULL; const char *a_sec = NULL; oauth_request_t oauth_req; a_key = purple_prefs_get_string(OPT_AKEY_TWITTER); a_sec = purple_prefs_get_string(OPT_ASEC_TWITTER); if(!a_key || !a_sec) { return; } tm = g_new(twitter_message_t, 1); tm->account = account; tm->status = g_strdup(*buffer); tm->time = time(NULL); /* oauth */ char *url0 = g_strdup_printf(TWITTER_API_BASE_URL "/1/statuses/update.xml"); oauth_req.url = url0; oauth_req.c_key = c_key; oauth_req.c_sec = c_sec; oauth_req.a_key = (char *)purple_prefs_get_string(OPT_AKEY_TWITTER); oauth_req.a_sec = (char *)purple_prefs_get_string(OPT_ASEC_TWITTER); oauth_req.verifier = NULL; oauth_req.status = (char *)url_encoded; oauth_req.type = TYPE_POST; oauth_req.count = 0; oauth_req.msgid = reply_to_msgid; oauth_req.notoken = FALSE; oauth = make_oauth_post(&oauth_req); g_free(url0); reply_to_msgid = 0; header = g_strdup_printf(TWITTER_STATUS_POST, (int)strlen(oauth)); request = g_strconcat(header, "\r\n", oauth, "\r\n", NULL); twitter_debug("request=%s\n", request); purple_util_fetch_url_request(TWITTER_BASE_URL, FALSE, NULL, TRUE, request, TRUE, post_status_with_api_cb, tm); g_free(header); g_free(oauth); g_free(request); } static void fav_with_api_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) { /* dummy */ } void fav_with_api(guint64 id) { char *header, *request; char *oauth; const char *a_key = NULL; const char *a_sec = NULL; oauth_request_t oauth_req; a_key = purple_prefs_get_string(OPT_AKEY_TWITTER); a_sec = purple_prefs_get_string(OPT_ASEC_TWITTER); if(!a_key || !a_sec) { return; } /* oauth */ char *url0 = g_strdup_printf(TWITTER_API_BASE_URL "/1/favorites/create/%llu.xml", (long long unsigned int)id); oauth_req.url = url0; oauth_req.c_key = c_key; oauth_req.c_sec = c_sec; oauth_req.a_key = (char *)a_key; oauth_req.a_sec = (char *)a_sec; oauth_req.verifier = NULL; oauth_req.status = NULL; oauth_req.type = TYPE_POST; oauth_req.count = 0; oauth_req.msgid = 0; oauth_req.notoken = FALSE; oauth = make_oauth_post(&oauth_req); g_free(url0); header = g_strdup_printf(TWITTER_FAV_POST, (long long unsigned int)id, (int)strlen(oauth)); request = g_strconcat(header, "\r\n", oauth, NULL); twitter_debug("request=%s\n", request); purple_util_fetch_url_request(TWITTER_BASE_URL, FALSE, NULL, TRUE, request, TRUE, fav_with_api_cb, NULL); g_free(header); g_free(oauth); g_free(request); } static void retweet_with_api_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) { /* dummy */ } void retweet_with_api(guint64 id) { char *header, *request; char *oauth; const char *a_key = NULL; const char *a_sec = NULL; oauth_request_t oauth_req; a_key = purple_prefs_get_string(OPT_AKEY_TWITTER); a_sec = purple_prefs_get_string(OPT_ASEC_TWITTER); if(!a_key || !a_sec) { return; } if(id == 0) { twitter_debug("invalid message id\n"); return; } /* oauth */ char *url0 = g_strdup_printf(TWITTER_API_BASE_URL "/1/statuses/retweet%llu.xml", (long long unsigned int)id); oauth_req.url = url0; oauth_req.c_key = c_key; oauth_req.c_sec = c_sec; oauth_req.a_key = (char *)a_key; oauth_req.a_sec = (char *)a_sec; oauth_req.verifier = NULL; oauth_req.status = NULL; oauth_req.type = TYPE_POST; oauth_req.count = 0; oauth_req.msgid = 0; oauth_req.notoken = FALSE; oauth = make_oauth_post(&oauth_req); g_free(url0); header = g_strdup_printf(TWITTER_RETWEET_POST, (long long unsigned int)id, (int)strlen(oauth)); request = g_strconcat(header, "\r\n", oauth, NULL); twitter_debug("request=%s\n", request); purple_util_fetch_url_request(TWITTER_API_BASE_URL, FALSE, NULL, TRUE, request, TRUE, retweet_with_api_cb, NULL); g_free(header); g_free(oauth); g_free(request); } void signed_on_cb(PurpleConnection *gc) { PurpleAccount *account; PurpleBuddy *buddy; PurpleConversation *gconv; const char name[] = "twitter@twitter.com"; if(!purple_prefs_get_bool(OPT_API_BASE_POST)) { twitter_debug("per prefs\n"); return; } account = purple_connection_get_account(gc); if(!account) { twitter_debug("no account\n"); return; } buddy = purple_find_buddy(account, name); if(!buddy) { twitter_debug("no buddy\n"); return; } account_for_twitter = account; gconv = purple_find_conversation_with_account( PURPLE_CONV_TYPE_IM, name, account); if(!gconv) { gconv = purple_conversation_new( PURPLE_CONV_TYPE_IM, account, name); twitter_debug("new conv\n"); } }