# HG changeset patch # User Konosuke Watanabe # Date 1214410962 -32400 # Node ID af4f31bce4612f0ad09400b3e1321a41e887b939 # Parent 76fc004cd32752d55a16369248af7b9df74685ca Support API base message posting diff -r 76fc004cd327 -r af4f31bce461 pidgin-twitter.c --- a/pidgin-twitter.c Wed Jun 25 11:53:21 2008 +0900 +++ b/pidgin-twitter.c Thu Jun 26 01:22:42 2008 +0900 @@ -256,6 +256,175 @@ *str = plain; } +#define TWITTER_STATUS_POST "POST /statuses/update.xml HTTP/1.0\r\n" \ + "Host: twitter.com\r\n" \ + "User-Agent: Pidgin-Twitter\r\n" \ + "Authorization: Basic %s\r\n" \ + "Content-Length: %d\r\n\r\n" + +#define TWITTER_STATUS_FORMAT "status=%s" +#define TWITTER_STATUS_TERMINATOR "\r\n\r\n" + +#define TWITTER_BASE_URL "http://twitter.com" + +typedef struct twitter_message { + PurpleAccount *account; + char *status; + time_t time; +} twitter_message_t; + +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 = (struct twitter_message *)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) { + purple_conv_im_write(conv->u.im, + purple_account_get_username(tm->account), + tm->status, PURPLE_MESSAGE_SEND, tm->time); + } else { + gchar *m; + m = g_strdup_printf("%s
%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); + } + +} + +static void +post_status_with_api(PurpleAccount *account, char **buffer) +{ + char *request, *status, *header; + const char *url_encoded = purple_url_encode(*buffer); + char *basic_auth, *basic_auth_encoded; + + twitter_message_t *tm; + + const char *screen_name = purple_prefs_get_string(OPT_SCREEN_NAME); + const char *password = purple_prefs_get_string(OPT_PASSWORD); + + twitter_debug("tm.account: %s\n", + purple_account_get_username(account)); + + if (!screen_name || !password || !screen_name[0] || !password[0]) { + twitter_debug("screen_name or password is empty\n"); + return; + } + + tm = g_new(twitter_message_t, 1); + tm->account = account; + tm->status = g_strdup(*buffer); + tm->time = time(NULL); + + basic_auth = g_strdup_printf("%s:%s", screen_name, password); + basic_auth_encoded = purple_base64_encode((unsigned char *)basic_auth, + strlen(basic_auth)); + g_free(basic_auth); + + status = g_strdup_printf(TWITTER_STATUS_FORMAT, url_encoded); + + header = g_strdup_printf(TWITTER_STATUS_POST, basic_auth_encoded, + strlen(status)); + + request = g_strconcat(header, status, TWITTER_STATUS_TERMINATOR, NULL); + + purple_util_fetch_url_request(TWITTER_BASE_URL, FALSE, + NULL, TRUE, request, TRUE, + post_status_with_api_cb, tm); + + g_free(header); + g_free(basic_auth_encoded); + g_free(status); + g_free(request); + +} + static gboolean sending_im_cb(PurpleAccount *account, char *recipient, char **buffer, void *data) @@ -276,6 +445,15 @@ escape(buffer); } + /* update status with Twitter API instead of IM protocol */ + if (purple_prefs_get_bool(OPT_API_BASE_POST)) { + if (buffer && *buffer) { + post_status_with_api(account, buffer); + (*buffer)[0] = '\0'; + } + return FALSE; + } + /* try to suppress oops message */ utflen = g_utf8_strlen(*buffer, -1); bytes = strlen(*buffer); @@ -385,7 +563,8 @@ twitter_debug("called\n"); /* check if the message is from twitter */ - if(!is_twitter_account(account, sender)) + if(!is_twitter_conv(conv)) + /* if(!is_twitter_account(account, sender)) */ return FALSE; /* strip all markups */ @@ -938,6 +1117,7 @@ int icon_id; if(!is_twitter_conv(conv)) { + twitter_debug("not twitter conv\n"); return; } @@ -980,6 +1160,8 @@ gtk_imhtml_insert_image_at_iter(imhtml, icon_id, &inserting_point); g_free(user_name); user_name = NULL; + + twitter_debug("reach end of function\n"); } static gboolean @@ -1220,6 +1402,26 @@ "Prevent notifications of incoming messages"); purple_plugin_pref_frame_add(frame, pref); + + /* API based post */ + + pref = purple_plugin_pref_new_with_label("API Based Post"); + purple_plugin_pref_frame_add(frame, pref); + + pref = purple_plugin_pref_new_with_name_and_label(OPT_API_BASE_POST, + "Post Status with API"); + purple_plugin_pref_frame_add(frame, pref); + + pref = purple_plugin_pref_new_with_name_and_label(OPT_SCREEN_NAME, + "Screen Name"); + purple_plugin_pref_frame_add(frame, pref); + + pref = purple_plugin_pref_new_with_name_and_label(OPT_PASSWORD, + "Password"); + purple_plugin_pref_set_masked(pref, TRUE); + + purple_plugin_pref_frame_add(frame, pref); + return frame; } @@ -1280,6 +1482,10 @@ purple_prefs_add_bool(OPT_SUPPRESS_OOPS, TRUE); purple_prefs_add_bool(OPT_PREVENT_NOTIFICATION, FALSE); + + purple_prefs_add_bool(OPT_API_BASE_POST, FALSE); + purple_prefs_add_string(OPT_SCREEN_NAME, EMPTY); + purple_prefs_add_string(OPT_PASSWORD, EMPTY); } PURPLE_INIT_PLUGIN(pidgin_twitter, init_plugin, info) diff -r 76fc004cd327 -r af4f31bce461 pidgin-twitter.h --- a/pidgin-twitter.h Wed Jun 25 11:53:21 2008 +0900 +++ b/pidgin-twitter.h Thu Jun 26 01:22:42 2008 +0900 @@ -43,12 +43,16 @@ #define OPT_SUPPRESS_OOPS OPT_PIDGINTWITTER "/suppress_oops" #define OPT_PREVENT_NOTIFICATION OPT_PIDGINTWITTER "/prevent_notification" #define OPT_ICON_DIR OPT_PIDGINTWITTER "/icon_dir" +#define OPT_API_BASE_POST OPT_PIDGINTWITTER "/api_base_post" +#define OPT_SCREEN_NAME OPT_PIDGINTWITTER "/screen_name" +#define OPT_PASSWORD OPT_PIDGINTWITTER "/password" /* formats and templates */ #define RECIPIENT_FORMAT "@%s" #define SENDER_FORMAT "%s%s: " #define DEFAULT_LIST "(list of users: separated with ' ,:;')" #define OOPS_MESSAGE "Oops! Your update was over 140 characters. We sent the short version to your friends (they can view the entire update on the web).
" +#define EMPTY "" /* patterns */ #define P_RECIPIENT "@([A-Za-z0-9_]+)"