view pidgin-twitter.h @ 174:002538feba6e multiaccounts

trying to change from some global preferences to preferences per conversation
author mikanbako <maoutwo@gmail.com>
date Sat, 02 Aug 2008 11:31:37 +0900
parents 45da59a32019
children 7affa10c1f0e
line wrap: on
line source

#ifndef _PIDGIN_TWITTER_H_
#define _PIDGIN_TWITTER_H_

#define _BSD_SOURCE
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <sys/stat.h>
#include <time.h>
#include <locale.h>

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libxml/xmlreader.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 */
enum {
    RECIPIENT = 0,
    SENDER,
    COMMAND,
    PSEUDO,
    USER,
    USER_FIRST_LINE,
    USER_FORMATTED,
    CHANNEL,
    IMAGE_IDENTICA,
    IMAGE_TWITTER
};

/* service id */
enum {
    unknown_service = -1,
    twitter_service,
    wassr_service,
    identica_service
};

/* container to hold icon data */
typedef struct _icon_data {
    GdkPixbuf *pixbuf;      /* icon pixmap */
    gboolean requested;     /* TRUE if download icon has been requested */
    GList *request_list;    /* marker list */
    PurpleUtilFetchUrlData *fetch_data; /* icon fetch data */
    const gchar *img_type;  /* image type */
    gint use_count;         /* usage count */
    time_t mtime;           /* mtime of file */
} icon_data;

/* used by got_icon_cb */
typedef struct _got_icon_data {
    gchar *user_name;
    gint service;
} got_icon_data;

/* used by eval */
typedef struct _eval_data {
    gint which;
    gint service;
} eval_data;

/* container for api based retrieve */
typedef struct _status {
    gchar *created_at;
    gchar *text;
    gchar *screen_name;
    gchar *profile_image_url;
    time_t time;
    guint id;
} status_t;

/* container for api based post */
typedef struct twitter_message {
    PurpleAccount *account;
    char *status;
    time_t time;
} twitter_message_t;

#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_TRANSLATE_CHANNEL   OPT_PIDGINTWITTER "/translate_channel"
#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"
#define OPT_API_BASE_POST       OPT_PIDGINTWITTER "/api_base_post"
#define OPT_SCREEN_NAME_TWITTER OPT_PIDGINTWITTER "/screen_name_twitter"
#define OPT_SCREEN_NAME_WASSR   OPT_PIDGINTWITTER "/screen_name_wassr"
#define OPT_SCREEN_NAME_IDENTICA OPT_PIDGINTWITTER "/screen_name_identica"
#define OPT_PASSWORD_TWITTER    OPT_PIDGINTWITTER "/password_twitter"
#define OPT_SHOW_ICON           OPT_PIDGINTWITTER "/show_icon"
#define OPT_ICON_SIZE           OPT_PIDGINTWITTER "/icon_size"
#define OPT_UPDATE_ICON         OPT_PIDGINTWITTER "/update_icon"
#define OPT_ICON_MAX_COUNT      OPT_PIDGINTWITTER "/icon_max_count"
#define OPT_ICON_MAX_DAYS       OPT_PIDGINTWITTER "/icon_max_days"
#define OPT_API_BASE_GET_INTERVAL OPT_PIDGINTWITTER "/api_base_get_interval"
#define OPT_LOG_OUTPUT          OPT_PIDGINTWITTER "/log_output"

/* options depend on service account */
#define OPT_SCREEN_NAME         OPT_PIDGINTWITTER "/screen_name"
#define OPT_API_BASE_PASSWORD      OPT_PIDGINTWITTER "/api_base_password"

/* conversation's name */
#define CONV_NAME_TWITTER "twitter@twitter.com"

/* formats and templates */
#define RECIPIENT_FORMAT_TWITTER "@<a href='http://twitter.com/%s'>%s</a>"
#define SENDER_FORMAT_TWITTER   "%s<a href='http://twitter.com/%s'>%s</a>: "
#define RECIPIENT_FORMAT_WASSR  "@<a href='http://wassr.jp/user/%s'>%s</a>"
#define SENDER_FORMAT_WASSR     "%s<a href='http://wassr.jp/user/%s'>%s</a>: "
#define RECIPIENT_FORMAT_IDENTICA "@<a href='http://identi.ca/%s'>%s</a>"
#define SENDER_FORMAT_IDENTICA  "%s<a href='http://identi.ca/%s'>%s</a>: "
#define CHANNEL_FORMAT_WASSR    "%s<a href='http://wassr.jp/channel/%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                   ""

/* labels of account preference button */
#define ACCOUNT_PREF_BUTTON_NORMAL   "Account Preference"
#define ACCOUNT_PREF_BUTTON_NOTICE   "(*)Account Preference"

/* patterns */
#define P_RECIPIENT         "@([A-Za-z0-9_]+)"
#define P_SENDER            "^(\\r?\\n?)\\s*([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_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>:"
#define P_CHANNEL           "^(.*?<a .+?>[A-Za-z0-9_]+</a>: \\r?\\n?#)([A-Za-z0-9_]+) "
#define P_IMAGE_IDENTICA    "<img src=\"(http://avatar.identi.ca/[A-Za-z0-9-.]+)\" class=\"avatar profile\" width=\"96\" height=\"96\" alt=\"[A-Za-z0-0_]+\"/>"
#define P_IMAGE_TWITTER     "<a href=\"/account/profile_image/.+?\"><img .+? id=\"profile-image\".*src=\"(http://.+)\" .+?/>"

/* twitter API specific macros */
#define TWITTER_BASE_URL "http://twitter.com"
#define TWITTER_STATUS_GET "GET /statuses/friends_timeline.xml HTTP/1.1\r\n" \
    "Host: twitter.com\r\n"                                          \
    "User-Agent: pidgin-twitter\r\n"                                 \
    "Authorization: Basic %s\r\n"
#define TWITTER_STATUS_POST "POST /statuses/update.xml HTTP/1.1\r\n" \
    "Host: twitter.com\r\n"                                          \
    "User-Agent: pidgin-twitter\r\n"                                 \
    "Authorization: Basic %s\r\n"                                    \
    "Content-Length: %d\r\n"
#define TWITTER_STATUS_FORMAT "status=%s&source=pidgintwitter"
#define TWITTER_DEFAULT_INTERVAL (60)
#define TWITTER_DEFAULT_ICON_URL "http://static.twitter.com/images/default_profile_bigger.png"

/* wassr specific macros */
#define WASSR_POST_LEN (255 * 4)
#define IDENTICA_POST_LEN (140)

/* misc macros */
#define DEFAULT_ICON_SIZE (48)
#define DEFAULT_ICON_MAX_COUNT (50)
#define DEFAULT_ICON_MAX_DAYS (7)
#define DAYS_TO_SECONDS(d) ((d) * 86400)

/* debug macros */
#define twitter_debug(fmt, ...)	do { if(purple_prefs_get_bool(OPT_LOG_OUTPUT)) purple_debug(PURPLE_DEBUG_INFO, PLUGIN_NAME, "%s():%4d:  " fmt, __FUNCTION__, (int)__LINE__, ## __VA_ARGS__); } while(0);
#define twitter_error(fmt, ...)	do { if(purple_prefs_get_bool(OPT_LOG_OUTPUT)) purple_debug(PURPLE_DEBUG_ERROR, PLUGIN_NAME, "%s():%4d:  " fmt, __FUNCTION__, (int)__LINE__, ## __VA_ARGS__); } while(0);

/* 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, gint which, gint service);
static void playsound(gchar **str, gint 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_conv(PurpleConversation *conv, gpointer null);
static void delete_requested_icon_marks(PidginConversation *gtkconv, GHashTable *table);
static void attach_to_window(void);
static void attach_to_conv(PurpleConversation *conv, gpointer null);
static void append_account_preference_button(PidginConversation *gtkconv);
static gboolean is_twitter_account(PurpleAccount *account, const char *name);
static gboolean is_twitter_conv(PurpleConversation *conv);
static gboolean is_wassr_account(PurpleAccount *account, const char *name);
static gboolean is_wassr_conv(PurpleConversation *conv);
static gboolean is_identica_account(PurpleAccount *account, const char *name);
static gboolean is_identica_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_icon_at_mark(GtkTextMark *requested_mark, gpointer user_data);
static void insert_requested_icon(const gchar *user_name, gint service);
static void got_icon_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message);
static void request_icon(const char *user_name, gint service, gboolean renew);
static void mark_icon_for_user(GtkTextMark *mark, const gchar *user_name, gint service);
static gboolean displaying_im_cb(PurpleAccount *account, const char *who, char **message, PurpleConversation *conv, PurpleMessageFlags flags, void *data);
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 void init_plugin(PurplePlugin *plugin);
static void remove_marks_func(gpointer key, gpointer value, gpointer user_data);
static void cancel_fetch_func(gpointer key, gpointer value, gpointer user_data);
static gint get_service_type(PurpleConversation *conv);
static GdkPixbuf *make_scaled_pixbuf(const gchar *url_text, gsize len);
static void open_account_preference_window(GtkWidget *called_widged, gpointer gtkconv_ptr);
static void build_screen_name_preference_form(PurpleConversation *conv, GtkWidget *notebook);
static void build_twitter_api_preference_form(PurpleConversation *conv, GtkWidget *notebook);
static void destroyed_pref_button_cb(GtkWidget *pref_button, gpointer dialog);
static void closed_account_preference_window_cb(GtkDialog *dialog, gint response_id, gpointer pref_button);
static void account_preference_text_changed_cb(GtkEditable *editable, gpointer conv_ptr);
static void account_preference_api_base_post_changed(void);
static void account_preference_bool_toggled_cb(GtkToggleButton *togglebutton, gpointer conv_ptr);
static void account_preference_interval_changed(PurpleAccount *account, const char *conv_name);
static void account_preference_spin_changed_cb(GtkSpinButton *spinbutton, gpointer conv_ptr);
static gchar* create_key_with_service_account(const char *conv_name, const char *key);
static void service_account_set_string(PurpleAccount *account, const char *conv_name, const char *key, const char *value);
static const char* service_account_get_string(PurpleAccount *account, const char *conv_name, const char *key, const char *default_value);
static void service_account_set_int(PurpleAccount *account, const char *conv_name, const char *key, gboolean value);
static gboolean service_account_get_int(PurpleAccount *account, const char *conv_name, const char *key, gboolean default_value);
static void service_account_set_bool(PurpleAccount *account, const char *conv_name, const char *key, gboolean value);
static gboolean service_account_get_bool(PurpleAccount *account, const char *conv_name, const char *key, gboolean default_value);

static void parse_user(xmlNode *user, status_t *st);
static void parse_status(xmlNode *status, status_t *st);
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 gboolean get_status_with_api(gpointer data);
static void read_timestamp(const char *str, struct tm *res);

static void strip_markup(gchar **str, gboolean escape);
static gchar *strip_html_markup(const gchar *src);
static GtkWidget *prefs_get_frame(PurplePlugin *plugin);

/* more prototypes */

#endif