changeset 72:af4f31bce461

Support API base message posting
author Konosuke Watanabe <sasugaanija@gmail.com>
date Thu, 26 Jun 2008 01:22:42 +0900
parents 76fc004cd327
children 08bd4abdfd3d
files pidgin-twitter.c pidgin-twitter.h
diffstat 2 files changed, 211 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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<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);
+    }
+
+}
+
+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)
--- 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        "@<a href='http://twitter.com/%s'>%s</a>"
 #define SENDER_FORMAT           "%s<a href='http://twitter.com/%s'>%s</a>: "
 #define DEFAULT_LIST            "(list of users: separated with ' ,:;')"
 #define OOPS_MESSAGE            "<body>Oops! Your update was over 140 characters. We sent the short version to your friends (they can view the entire update on the web).<BR></body>"
+#define EMPTY                   ""
 
 /* patterns */
 #define P_RECIPIENT        "@([A-Za-z0-9_]+)"