changeset 64:da37857f3033

- separated header things into pidgin-twitter.h - preliminary save icon feature
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Sun, 22 Jun 2008 16:02:44 +0900
parents 760006015519
children 4949d4eb34ec
files pidgin-twitter.c pidgin-twitter.h
diffstat 2 files changed, 168 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin-twitter.c	Sun Jun 22 01:44:48 2008 +0900
+++ b/pidgin-twitter.c	Sun Jun 22 16:02:44 2008 +0900
@@ -18,67 +18,7 @@
  */
 #define PURPLE_PLUGINS 1
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-
-#include "gtkplugin.h"
-#include "util.h"
-#include "debug.h"
-#include "connection.h"
-#include "version.h"
-#include "sound.h"
-#include "gtkconv.h"
-#include "gtkimhtml.h"
-
-#define RECIPIENT        0
-#define SENDER           1
-#define COMMAND          2
-#define PSEUDO           3
-#define MESSAGE          4
-#define USER             5
-#define USER_FIRST_LINE  6
-#define USER_FORMATTED   7
-
-#define PLUGIN_ID	            "gtk-honeyplanet-pidgin_twitter"
-#define PLUGIN_NAME	            "pidgin-twitter"
-
-/* options */
-#define OPT_PIDGINTWITTER 		"/plugins/pidgin_twitter"
-#define OPT_TRANSLATE_RECIPIENT OPT_PIDGINTWITTER "/translate_recipient"
-#define OPT_TRANSLATE_SENDER    OPT_PIDGINTWITTER "/translate_sender"
-#define OPT_PLAYSOUND_RECIPIENT OPT_PIDGINTWITTER "/playsound_recipient"
-#define OPT_PLAYSOUND_SENDER    OPT_PIDGINTWITTER "/playsound_sender"
-#define OPT_SOUNDID_RECIPIENT   OPT_PIDGINTWITTER "/soundid_recipient"
-#define OPT_SOUNDID_SENDER      OPT_PIDGINTWITTER "/soundid_sender"
-#define OPT_ESCAPE_PSEUDO       OPT_PIDGINTWITTER "/escape_pseudo"
-#define OPT_USERLIST_RECIPIENT  OPT_PIDGINTWITTER "/userlist_recipient"
-#define OPT_USERLIST_SENDER     OPT_PIDGINTWITTER "/userlist_sender"
-#define OPT_COUNTER             OPT_PIDGINTWITTER "/counter"
-#define OPT_SUPPRESS_OOPS       OPT_PIDGINTWITTER "/suppress_oops"
-#define OPT_PREVENT_NOTIFICATION OPT_PIDGINTWITTER "/prevent_notification"
-
-/* 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>"
-
-/* patterns */
-#define P_RECIPIENT        "@([A-Za-z0-9_]+)"
-#define P_SENDER           "^(\\r?\\n?)([A-Za-z0-9_]+): "
-#define P_COMMAND          "^(?:\\s*)([dDfFgGlLmMnNtTwW]{1}\\s+[A-Za-z0-9_]+)(?:\\s*\\Z)"
-#define P_PSEUDO           "^\\s*(?:[\"#$%&'()*+,\\-./:;<=>?\\[\\\\\\]_`{|}~]|[^\\s\\x21-\\x7E])*([dDfFgGlLmMnNtTwW]{1})(?:\\Z|\\s+|[^\\x21-\\x7E]+\\Z)"
-#define P_MESSAGE          "^<body>(.*)</body>"
-#define P_USER             "^\\(.+?\\)\\s*([A-Za-z0-9_]+):"
-#define P_USER_FIRST_LINE  "^\\(.+?\\)\\s*.+:\\s*([A-Za-z0-9_]+):"
-#define P_USER_FORMATTED   "^.*?<a .+?>([A-Za-z0-9_]+)</a>:"
-
-/* debug macros */
-#define twitter_debug(fmt, ...)	purple_debug(PURPLE_DEBUG_INFO, PLUGIN_NAME, "%s():%4d:  " fmt, __FUNCTION__, (int)__LINE__, ## __VA_ARGS__);
-#define twitter_error(fmt, ...)	purple_debug(PURPLE_DEBUG_ERROR, PLUGIN_NAME, "%s():%4d:  " fmt, __FUNCTION__, (int)__LINE__, ## __VA_ARGS__);
-
+#include "pidgin-twitter.h"
 
 /* globals */
 static GRegex *regp[8];
@@ -88,36 +28,6 @@
 static GList *requestings = NULL;
 static GList *requested_icon_marks = NULL;
 
-/* prototypes */
-static void escape(gchar **str);
-static gboolean sending_im_cb(PurpleAccount *account, char *recipient, char **buffer, void *data);
-static gboolean eval(const GMatchInfo *match_info, GString *result, gpointer user_data);
-static void translate(gchar **str, int which);
-static void playsound(gchar **str, int which);
-static gboolean writing_im_cb(PurpleAccount *account, char *sender, char **buffer, PurpleConversation *conv, int *flags, void *data);
-static void insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position, gchar *new_text, gint new_text_length, gpointer user_data);
-static void delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos, GtkTextIter *end_pos, gpointer user_data);
-static void detach_from_window(void);
-static void detach_from_gtkconv(PidginConversation *gtkconv, gpointer null);
-static void delete_requested_icon_marks(PidginConversation *gtkconv);
-static void attach_to_window(void);
-static void attach_to_gtkconv(PidginConversation *gtkconv, gpointer null);
-static gboolean is_twitter_account(PurpleAccount *account, const char *name);
-static gboolean is_twitter_conv(PurpleConversation *conv);
-static void conv_created_cb(PurpleConversation *conv, gpointer null);
-static void deleting_conv_cb(PurpleConversation *conv);
-static gboolean receiving_im_cb(PurpleAccount *account, char **sender, char **buffer, PurpleConversation *conv, PurpleMessageFlags *flags, void *data);
-static void insert_requested_icon(gpointer data, gpointer user_data);
-static void downloaded_icon_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message);
-static void request_icon(const char *buffer);
-static void displayed_im_cb(PurpleAccount *account, const char *who, char *message, PurpleConversation *conv, PurpleMessageFlags flags);
-static gboolean load_plugin(PurplePlugin *plugin);
-static gboolean unload_plugin(PurplePlugin *plugin);
-static void counter_prefs_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer data);
-static PurplePluginPrefFrame *get_plugin_pref_frame(PurplePlugin *plugin);
-static void init_plugin(PurplePlugin *plugin);
-
-
 /* this function is a modified clone of purple_markup_strip_html() */
 static char *
 strip_html_markup(const char *str)
@@ -275,9 +185,22 @@
 	return str2;
 }
 
+/* this function has been taken from autoaccept plugin */
+static gboolean
+ensure_path_exists(const char *dir)
+{
+	if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) {
+		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR))
+			return FALSE;
+	}
 
+	return TRUE;
+}
+
+
+/**********************/
 /* our implementation */
-
+/**********************/
 static void
 escape(gchar **str)
 {
@@ -592,7 +515,7 @@
     GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(
         GTK_TEXT_VIEW(conv->imhtml));
     GList *mark_list = g_list_first(requested_icon_marks);
-    
+
     /* delete the marks in the buffer that will be closed. */
     while(mark_list) {
         GtkTextMark *mark = mark_list->data;
@@ -650,7 +573,7 @@
     purple_conversation_set_features(
         gtkconv->active_conv,
         purple_conversation_get_features(gtkconv->active_conv) &
-        ~PURPLE_CONNECTION_HTML); 
+        ~PURPLE_CONNECTION_HTML);
 
     /* check if the counter is enabled */
     if(!purple_prefs_get_bool(OPT_COUNTER))
@@ -795,7 +718,7 @@
                 GtkIMHtml *current_imhtml = GTK_IMHTML(conv->imhtml); 
                 GtkTextBuffer *current_buffer = gtk_text_view_get_buffer(
                      GTK_TEXT_VIEW(current_imhtml));
-    
+
                 if(current_buffer == gtk_text_mark_get_buffer(requested_mark)) {
                      target_imhtml = current_imhtml;
                      target_buffer = current_buffer;
@@ -846,6 +769,9 @@
         return;
     }
 
+    /* xxx scale stored icon to adequate size here. --yaz */
+
+    /* insert icon actually */
     gtk_imhtml_insert_image_at_iter(target_imhtml, icon_id, &inserting_point);
 
     /* mark the entry contains the deleted mark with NULL */
@@ -884,6 +810,25 @@
                                           user_name);
     g_hash_table_insert(icon_id_by_user, user_name, GINT_TO_POINTER(icon_id));
 
+    const gchar *dirname = purple_prefs_get_string(OPT_ICON_DIR);
+
+    /* store retrieved image to a file in icon dir */
+    if(ensure_path_exists(dirname)) {
+        gchar *filename = NULL;
+        FILE *fp = NULL;
+
+        filename = g_build_filename(dirname, user_name, ".gif", NULL);
+
+        fp = fopen(filename, "w");
+        g_free(filename); filename = NULL;
+
+        if(fp) {
+            int len;
+            len = fwrite(url_text, len, 1, fp);
+        }
+        fclose(fp); fp = NULL;
+    }
+
     twitter_debug("Downloading %s's icon has been complete.(icon_id = %d)\n",
         user_name, icon_id);
 
@@ -903,7 +848,6 @@
     PurpleUtilFetchUrlData *fetch_data = NULL;
 
     /* get user's name */
-
     g_regex_match(regp[MESSAGE], buffer, 0, &match_info);
     if(!g_match_info_matches(match_info)) {
         twitter_debug("Message was not matched : %s\n", buffer);
@@ -927,9 +871,33 @@
     g_match_info_free(match_info);
     g_free(message);
 
+    /***********************/
     /* request user's icon */
+    /***********************/
+
+    /* first of all, look local icon cache for the requested icon */
+    gchar *filename = NULL;
+    filename = g_build_filename(
+        purple_prefs_get_string(OPT_ICON_DIR), user_name, ".gif", NULL);
 
-    /* Return if user's icon had already been requested. */
+    if(!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+        g_free(filename);
+        filename = g_build_filename(
+            purple_prefs_get_string(OPT_ICON_DIR), user_name, ".png", NULL);
+    }
+
+    if(g_file_test(filename, G_FILE_TEST_EXISTS)) {
+        purple_imgstore_new_from_file(filename);
+        icon_id = purple_imgstore_add_from_file_with_id();
+        g_hash_table_insert(icon_id_by_user, user_name, GINT_TO_POINTER(icon_id));
+        g_free(user_name);
+        g_free(filename);
+
+        return;
+    }
+
+
+    /* Return if user's icon has been requested already. */
     if(g_list_find_custom(requested_users, user_name, (GCompareFunc)strcmp)) {
         g_free(user_name);
         return;
@@ -1035,7 +1003,7 @@
     regp[USER_FIRST_LINE] = g_regex_new(P_USER_FIRST_LINE, 0, 0, NULL);
     regp[USER_FORMATTED]  = g_regex_new(P_USER_FORMATTED, G_REGEX_RAW, 0, NULL);
 
-    /* hash table for user's icons 
+    /* hash table for user's icons
      * the key is owned by requested_user */
     icon_id_by_user = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
 
@@ -1281,7 +1249,13 @@
 static void
 init_plugin(PurplePlugin *plugin)
 {
+    char *dirname = NULL;
+
     g_type_init();
+    dirname = g_build_filename(purple_user_dir(), "pidgin-twitter/icons", NULL);
+    if(dirname)
+        purple_prefs_add_string(OPT_ICON_DIR, dirname);
+    g_free(dirname);
 
     /* add plugin preferences */
     purple_prefs_add_none(OPT_PIDGINTWITTER);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin-twitter.h	Sun Jun 22 16:02:44 2008 +0900
@@ -0,0 +1,96 @@
+#ifndef _PIDGIN_TWITTER_H_
+#define _PIDGIN_TWITTER_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "gtkplugin.h"
+#include "util.h"
+#include "debug.h"
+#include "connection.h"
+#include "version.h"
+#include "sound.h"
+#include "gtkconv.h"
+#include "gtkimhtml.h"
+
+/* regp id */
+#define RECIPIENT        0
+#define SENDER           1
+#define COMMAND          2
+#define PSEUDO           3
+#define MESSAGE          4
+#define USER             5
+#define USER_FIRST_LINE  6
+#define USER_FORMATTED   7
+
+#define PLUGIN_ID	            "gtk-honeyplanet-pidgin_twitter"
+#define PLUGIN_NAME	            "pidgin-twitter"
+
+/* options */
+#define OPT_PIDGINTWITTER 		"/plugins/pidgin_twitter"
+#define OPT_TRANSLATE_RECIPIENT OPT_PIDGINTWITTER "/translate_recipient"
+#define OPT_TRANSLATE_SENDER    OPT_PIDGINTWITTER "/translate_sender"
+#define OPT_PLAYSOUND_RECIPIENT OPT_PIDGINTWITTER "/playsound_recipient"
+#define OPT_PLAYSOUND_SENDER    OPT_PIDGINTWITTER "/playsound_sender"
+#define OPT_SOUNDID_RECIPIENT   OPT_PIDGINTWITTER "/soundid_recipient"
+#define OPT_SOUNDID_SENDER      OPT_PIDGINTWITTER "/soundid_sender"
+#define OPT_ESCAPE_PSEUDO       OPT_PIDGINTWITTER "/escape_pseudo"
+#define OPT_USERLIST_RECIPIENT  OPT_PIDGINTWITTER "/userlist_recipient"
+#define OPT_USERLIST_SENDER     OPT_PIDGINTWITTER "/userlist_sender"
+#define OPT_COUNTER             OPT_PIDGINTWITTER "/counter"
+#define OPT_SUPPRESS_OOPS       OPT_PIDGINTWITTER "/suppress_oops"
+#define OPT_PREVENT_NOTIFICATION OPT_PIDGINTWITTER "/prevent_notification"
+#define OPT_ICON_DIR            OPT_PIDGINTWITTER "/icon_dir"
+
+/* 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>"
+
+/* patterns */
+#define P_RECIPIENT        "@([A-Za-z0-9_]+)"
+#define P_SENDER           "^(\\r?\\n?)([A-Za-z0-9_]+): "
+#define P_COMMAND          "^(?:\\s*)([dDfFgGlLmMnNtTwW]{1}\\s+[A-Za-z0-9_]+)(?:\\s*\\Z)"
+#define P_PSEUDO           "^\\s*(?:[\"#$%&'()*+,\\-./:;<=>?\\[\\\\\\]_`{|}~]|[^\\s\\x21-\\x7E])*([dDfFgGlLmMnNtTwW]{1})(?:\\Z|\\s+|[^\\x21-\\x7E]+\\Z)"
+#define P_MESSAGE          "^<body>(.*)</body>"
+#define P_USER             "^\\(.+?\\)\\s*([A-Za-z0-9_]+):"
+#define P_USER_FIRST_LINE  "^\\(.+?\\)\\s*.+:\\s*([A-Za-z0-9_]+):"
+#define P_USER_FORMATTED   "^.*?<a .+?>([A-Za-z0-9_]+)</a>:"
+
+/* debug macros */
+#define twitter_debug(fmt, ...)	purple_debug(PURPLE_DEBUG_INFO, PLUGIN_NAME, "%s():%4d:  " fmt, __FUNCTION__, (int)__LINE__, ## __VA_ARGS__);
+#define twitter_error(fmt, ...)	purple_debug(PURPLE_DEBUG_ERROR, PLUGIN_NAME, "%s():%4d:  " fmt, __FUNCTION__, (int)__LINE__, ## __VA_ARGS__);
+
+/* prototypes */
+static void escape(gchar **str);
+static gboolean sending_im_cb(PurpleAccount *account, char *recipient, char **buffer, void *data);
+static gboolean eval(const GMatchInfo *match_info, GString *result, gpointer user_data);
+static void translate(gchar **str, int which);
+static void playsound(gchar **str, int which);
+static gboolean writing_im_cb(PurpleAccount *account, char *sender, char **buffer, PurpleConversation *conv, int *flags, void *data);
+static void insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position, gchar *new_text, gint new_text_length, gpointer user_data);
+static void delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos, GtkTextIter *end_pos, gpointer user_data);
+static void detach_from_window(void);
+static void detach_from_gtkconv(PidginConversation *gtkconv, gpointer null);
+static void delete_requested_icon_marks(PidginConversation *gtkconv);
+static void attach_to_window(void);
+static void attach_to_gtkconv(PidginConversation *gtkconv, gpointer null);
+static gboolean is_twitter_account(PurpleAccount *account, const char *name);
+static gboolean is_twitter_conv(PurpleConversation *conv);
+static void conv_created_cb(PurpleConversation *conv, gpointer null);
+static void deleting_conv_cb(PurpleConversation *conv);
+static gboolean receiving_im_cb(PurpleAccount *account, char **sender, char **buffer, PurpleConversation *conv, PurpleMessageFlags *flags, void *data);
+static void insert_requested_icon(gpointer data, gpointer user_data);
+static void downloaded_icon_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message);
+static void request_icon(const char *buffer);
+static void displayed_im_cb(PurpleAccount *account, const char *who, char *message, PurpleConversation *conv, PurpleMessageFlags flags);
+static gboolean load_plugin(PurplePlugin *plugin);
+static gboolean unload_plugin(PurplePlugin *plugin);
+static void counter_prefs_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer data);
+static PurplePluginPrefFrame *get_plugin_pref_frame(PurplePlugin *plugin);
+static void init_plugin(PurplePlugin *plugin);
+
+#endif