pidgin/purple-plugin-pack

Fix the glib version update in the changelog. We depend on 2.32.0 not 2.23.0.
/*
* libokcupid
*
* libokcupid is the property of its developers. See the COPYRIGHT file
* for more details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "okcupid.h"
#include "okc_messages.h"
#include "okc_connection.h"
typedef struct _OkCupidOutgoingMessage OkCupidOutgoingMessage;
struct _OkCupidOutgoingMessage {
OkCupidAccount *oca;
gchar *who;
time_t time;
gchar *message;
gint msg_id;
guint retry_count;
gint rid;
};
gboolean okc_send_im_fom(OkCupidOutgoingMessage *msg);
void okc_check_inbox_cb(OkCupidAccount *oca, gchar *data, gsize data_len, gpointer user_data);
void okc_buddy_icon_cb(OkCupidAccount *oca, gchar *data, gsize data_len,
gpointer user_data)
{
gchar *buddyname;
PurpleBuddy *buddy;
OkCupidBuddy *obuddy;
gpointer buddy_icon_data;
buddyname = user_data;
purple_debug_info("okcupid",
"buddy icon for buddy %s %" G_GSIZE_FORMAT "\n",
buddyname, data_len);
buddy = purple_find_buddy(oca->account, buddyname);
g_free(buddyname);
if (buddy == NULL || buddy->proto_data == NULL)
return;
obuddy = buddy->proto_data;
buddy_icon_data = g_memdup(data, data_len);
purple_buddy_icons_set_for_user(oca->account, buddy->name,
buddy_icon_data, data_len, obuddy->thumb_url);
}
void got_new_messages(OkCupidAccount *oca, gchar *data,
gsize data_len, gpointer userdata)
{
PurpleConnection *pc = userdata;
/* NULL data will crash on Windows */
if (data == NULL)
data = "(null)";
purple_debug_misc("okcupid", "got new messages: %s\n", data);
/* Process incomming messages here */
gchar *start_of_json = strchr(data, '{');
gchar *end_of_json = strrchr(data, '}');
if (!start_of_json || !end_of_json || start_of_json >= end_of_json)
{
okc_get_new_messages(oca);
return;
}
gchar *json_string = g_strndup(start_of_json, end_of_json-start_of_json+1);
JsonParser *parser;
JsonNode *root;
parser = json_parser_new();
if(!json_parser_load_from_data(parser, json_string, -1, NULL))
{
g_free(json_string);
okc_get_new_messages(oca);
return;
}
g_free(json_string);
root = json_parser_get_root(parser);
JsonObject *objnode;
objnode = json_node_get_object(root);
JsonArray *events = NULL;
JsonArray *people = NULL;
int unread_message_count = 0;
if(json_object_has_member(objnode, "people"))
people = json_node_get_array(json_object_get_member(objnode, "people"));
if(json_object_has_member(objnode, "events"))
events = json_node_get_array(json_object_get_member(objnode, "events"));
if(json_object_has_member(objnode, "num_unread"))
unread_message_count = json_node_get_int(json_object_get_member(objnode, "num_unread"));
// Look through the buddy list for people to add first
if (people != NULL)
{
GList *people_list = json_array_get_elements(people);
GList *current;
for (current = people_list; current; current = g_list_next(current))
{
JsonNode *currentNode = current->data;
JsonObject *person = json_node_get_object(currentNode);
if (!json_node_get_int(json_object_get_member(person, "is_buddy")) &&
!purple_account_get_bool(oca->account, "show_stalkers", TRUE))
{
continue;
}
const gchar *buddy_name = json_node_get_string(json_object_get_member(person, "screenname"));
const gchar *buddy_icon = json_node_get_string(json_object_get_member(person, "thumbnail"));
gint is_online = json_node_get_int(json_object_get_member(person, "im_ok"));
if (!json_object_has_member(person, "im_ok"))
is_online = 1;
PurpleBuddy *pbuddy = purple_find_buddy(oca->account, buddy_name);
if (!pbuddy)
{
//Not everyone we talk to will be on our buddylist
pbuddy = purple_buddy_new(oca->account, buddy_name, NULL);
purple_blist_add_buddy(pbuddy, NULL, NULL, NULL);
}
if (pbuddy != NULL)
{
if (!json_node_get_int(json_object_get_member(person, "is_buddy")))
{
purple_blist_node_set_flags(&(pbuddy->node), PURPLE_BLIST_NODE_FLAG_NO_SAVE);
} else {
purple_blist_node_set_flags(&(pbuddy->node), 0);
}
if (is_online && !PURPLE_BUDDY_IS_ONLINE(pbuddy))
{
purple_prpl_got_user_status(oca->account, buddy_name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
} else if (!is_online && PURPLE_BUDDY_IS_ONLINE(pbuddy))
{
purple_prpl_got_user_status(oca->account, buddy_name, purple_primitive_get_id_from_type(PURPLE_STATUS_OFFLINE), NULL);
}
OkCupidBuddy *obuddy = pbuddy->proto_data;
if (obuddy == NULL)
{
const gchar *buddy_icon_url;
obuddy = g_new0(OkCupidBuddy, 1);
obuddy->buddy = pbuddy;
obuddy->oca = oca;
// load the old buddy icon url from the icon 'checksum'
buddy_icon_url = purple_buddy_icons_get_checksum_for_user(pbuddy);
if (buddy_icon_url != NULL)
obuddy->thumb_url = g_strdup(buddy_icon_url);
pbuddy->proto_data = obuddy;
}
if (!obuddy->thumb_url || !g_str_equal(obuddy->thumb_url, buddy_icon))
{
gchar *host, *path, *path2;
gchar *large_image_url;
g_free(obuddy->thumb_url);
obuddy->thumb_url = g_strdup(buddy_icon);
large_image_url = purple_strreplace(buddy_icon, "/60x60/", "/256x256/");
purple_url_parse(large_image_url, &host, NULL, &path, NULL, NULL);
g_free(large_image_url);
if (path[0] != '/')
path2 = g_strdup_printf("/%s", path);
else
path2 = g_strdup(path);
okc_post_or_get(oca, OKC_METHOD_GET, host, path2, NULL, okc_buddy_icon_cb, g_strdup(buddy_name), FALSE);
g_free(host);
g_free(path);
g_free(path2);
}
if (obuddy->status_cache == NULL && json_object_has_member(person, "age"))
{
gint age = json_node_get_int(json_object_get_member(person, "age"));
const gchar *gender = json_node_get_string(json_object_get_member(person, "gender"));
const gchar *location = json_node_get_string(json_object_get_member(person, "location"));
obuddy->status_cache = g_strdup_printf("%d / %s / %s", age, gender, location );
}
}
}
g_list_free(people_list);
}
//loop through events looking for messages
if (events != NULL)
{
GList *event_list = json_array_get_elements(events);
GList *current;
for (current = event_list; current; current = g_list_next(current))
{
JsonNode *currentNode = current->data;
JsonObject *event = json_node_get_object(currentNode);
const gchar *event_type;
event_type = json_node_get_string(json_object_get_member(event, "type"));
if (g_str_equal(event_type, "im"))
{
//instant message
const gchar *message = json_node_get_string(json_object_get_member(event, "contents"));
gchar *message_html = okc_strdup_withhtml(message);
const gchar *who = NULL;
PurpleMessageFlags flags;
if (json_object_has_member(event, "to"))
{
who = json_node_get_string(json_object_get_member(event, "to"));
flags = PURPLE_MESSAGE_SEND;
} else if (json_object_has_member(event, "from"))
{
who = json_node_get_string(json_object_get_member(event, "from"));
flags = PURPLE_MESSAGE_RECV;
}
if (who && (flags != PURPLE_MESSAGE_SEND || purple_account_get_bool(oca->account, "show_sent_messages", FALSE)))
serv_got_im (pc, who, message_html, flags, time(NULL));
g_free(message_html);
} else if (g_str_equal(event_type, "orbit_user_signoff"))
{
//buddy signed off
const gchar *buddy_name = json_node_get_string(json_object_get_member(event, "from"));
PurpleBuddy *pbuddy = purple_find_buddy(oca->account, buddy_name);
if (pbuddy && PURPLE_BUDDY_IS_ONLINE(pbuddy))
{
purple_prpl_got_user_status(oca->account, buddy_name, purple_primitive_get_id_from_type(PURPLE_STATUS_OFFLINE), NULL);
}
} else if (g_str_equal(event_type, "stalk") && purple_account_get_bool(oca->account, "show_stalkers", TRUE))
{
//someone looked at the profile page (ie 'stalked' the user)
const gchar *buddy_name = json_node_get_string(json_object_get_member(event, "from"));
gchar *stalk_message = g_strdup_printf("%s just viewed your profile", buddy_name);
serv_got_im(oca->pc, buddy_name, stalk_message, PURPLE_MESSAGE_SYSTEM, time(NULL));
g_free(stalk_message);
}
}
g_list_free(event_list);
}
if (unread_message_count != oca->last_message_count && purple_account_get_check_mail(pc->account))
{
oca->last_message_count = unread_message_count;
if (unread_message_count > 0)
{
okc_post_or_get(oca, OKC_METHOD_GET, NULL, "/mailbox?folderid=1&low=1", NULL, okc_check_inbox_cb, NULL, FALSE);
}
}
if (json_object_has_member(objnode, "server_seqid"))
oca->server_seqid = json_node_get_int(json_object_get_member(objnode, "server_seqid"));
if (json_object_has_member(objnode, "server_gmt"))
oca->server_gmt = json_node_get_int(json_object_get_member(objnode, "server_gmt"));
g_object_unref(parser);
/* Continue looping, waiting for more messages */
okc_get_new_messages(oca);
}
gchar *
okc_get_stalkers(OkCupidAccount *oca)
{
GString *stalkers;
GSList *buddies;
GSList *l;
PurpleBuddy *buddy;
buddies = purple_find_buddies(oca->account, NULL);
stalkers = g_string_new(NULL);
for(l = buddies; l; l = l->next)
{
buddy = l->data;
if (buddy->node.flags & PURPLE_BLIST_NODE_FLAG_NO_SAVE)
{
// A temp buddy? They're a stalker!
g_string_append_printf(stalkers, "%s,", buddy->name);
}
}
g_slist_free(buddies);
return g_string_free(stalkers, FALSE);
}
void okc_get_new_messages_now(OkCupidAccount *oca)
{
gchar *fetch_url;
gchar *stalkers;
purple_debug_info("okcupid", "getting new messages now\n");
stalkers = okc_get_stalkers(oca);
fetch_url = g_strdup_printf("/instantevents?rand=0.%u&server_seqid=%u&server_gmt=%u&"
"load_thumbnails=1&buddylist=1&"
"show_offline=1&num_unread=1&im_status=1&"
"usernames=%s",
g_random_int(), oca->server_seqid, oca->server_gmt,
stalkers);
okc_post_or_get(oca, OKC_METHOD_GET, NULL, fetch_url, NULL, got_new_messages, oca->pc, FALSE);
g_free(fetch_url);
g_free(stalkers);
}
gboolean okc_get_new_messages(OkCupidAccount *oca)
{
time_t now;
gchar *fetch_url;
gchar *stalkers;
oca->new_messages_check_timer = 0;
now = time(NULL);
if (oca->last_messages_download_time > now - 3) {
/*
* Wait a bit before fetching more messages, to make sure we
* never hammer their servers.
*
* TODO: This could be smarter. Like, allow 3 requests per
* 10 seconds or something.
*/
oca->new_messages_check_timer = purple_timeout_add_seconds(
3 - (now - oca->last_messages_download_time),
(GSourceFunc)okc_get_new_messages, oca);
return FALSE;
}
purple_debug_info("okcupid", "getting new messages\n");
stalkers = okc_get_stalkers(oca);
fetch_url = g_strdup_printf("/instantevents?rand=0.%u&server_seqid=%u&server_gmt=%u&"
"load_thumbnails=1&do_event_poll=1&buddylist=1&"
"show_offline=1&num_unread=1&im_status=1&"
"do_post_read=1&usernames=%s",
g_random_int(), oca->server_seqid, oca->server_gmt,
stalkers);
okc_post_or_get(oca, OKC_METHOD_GET, NULL, fetch_url, NULL, got_new_messages, oca->pc, TRUE);
oca->last_messages_download_time = now;
g_free(fetch_url);
g_free(stalkers);
return FALSE;
}
void okc_msg_destroy(OkCupidOutgoingMessage *msg)
{
if (msg == NULL)
return;
g_free(msg->who);
g_free(msg->message);
g_free(msg);
}
void okc_send_im_cb(OkCupidAccount *oca, gchar *data, gsize data_len, gpointer user_data)
{
OkCupidOutgoingMessage *msg = user_data;
if (data == NULL || data_len == 0)
{
//No response, resend message
okc_send_im_fom(msg);
return;
}
purple_debug_misc("okcupid", "sent im response: %s\n", data);
/*
Possible responses:
{
"message_sent" : 0,
"reason" : "recip_not_online"
}
{
"message_sent" : 0,
"reason" : "im_self"
}
*/
JsonParser *parser;
JsonNode *root;
parser = json_parser_new();
if(!json_parser_load_from_data(parser, data, data_len, NULL))
{
okc_msg_destroy(msg);
return;
}
root = json_parser_get_root(parser);
JsonObject *response;
response = json_node_get_object(root);
gint message_sent = json_node_get_int(json_object_get_member(response, "status"));
if (message_sent < 100)
{
//Save the message we sent
purple_debug_info("okcupid", "putting message into hashtable: '%s'\n", msg->message);
okc_msg_destroy(msg);
g_object_unref(parser);
return;
}
const gchar *reason = json_node_get_string(json_object_get_member(response, "status_str"));
if (reason != NULL)
{
if (g_str_equal(reason, "recip_not_online"))
{
serv_got_im(oca->pc, msg->who, _("Recipient not online"), PURPLE_MESSAGE_ERROR, time(NULL));
} else if (g_str_equal(reason, "im_self"))
{
serv_got_im(oca->pc, msg->who, _("You cannot send an IM to yourself"), PURPLE_MESSAGE_ERROR, time(NULL));
} else if (g_str_equal(reason, "im_not_ok"))
{
serv_got_im(oca->pc, msg->who, _("Recipient is 'missing'"), PURPLE_MESSAGE_ERROR, time(NULL));
} else if (g_str_equal(reason, "recip_im_off"))
{
serv_got_im(oca->pc, msg->who, _("Recipient turned IM off"), PURPLE_MESSAGE_ERROR, time(NULL));
}
}
okc_msg_destroy(msg);
g_object_unref(parser);
}
gboolean okc_send_im_fom(OkCupidOutgoingMessage *msg)
{
gchar *encoded_message;
gchar *encoded_recipient;
gchar *postdata;
encoded_message = g_strdup(purple_url_encode(msg->message));
encoded_recipient = g_strdup(purple_url_encode(msg->who));
postdata = g_strdup_printf("send=1&attempt=%d&rid=%d&recipient=%s&topic=false&body=%s",
msg->retry_count + 1,
msg->rid,
encoded_recipient,
encoded_message);
g_free(encoded_message);
g_free(encoded_recipient);
okc_post_or_get(msg->oca, OKC_METHOD_POST, NULL, "/instantevents", postdata, okc_send_im_cb, msg, FALSE);
g_free(postdata);
return FALSE;
}
int okc_send_im(PurpleConnection *pc, const gchar *who, const gchar *message, PurpleMessageFlags flags)
{
OkCupidOutgoingMessage *msg;
msg = g_new0(OkCupidOutgoingMessage, 1);
msg->oca = pc->proto_data;
/* convert html to plaintext, removing trailing spaces */
msg->message = purple_markup_strip_html(message);
msg->rid = g_random_int_range(0, 2000000000); /* just fits inside a 32bit int */
msg->who = g_strdup(who);
msg->time = time(NULL);
msg->retry_count = 0;
okc_send_im_fom(msg);
if (purple_account_get_bool(pc->account, "show_sent_messages", FALSE))
{
return 0;
}
return strlen(message);
}
void okc_check_inbox_cb(OkCupidAccount *oca, gchar *data, gsize data_len, gpointer user_data)
{
JsonParser *parser;
JsonNode *root;
JsonObject *mailbox;
JsonArray *messages;
purple_debug_misc("okcupid", "check_inbox_cb\n%s", (data?data:"(null)"));
parser = json_parser_new();
if(!json_parser_load_from_data(parser, data, data_len, NULL))
{
purple_debug_warning("okcupid", "Could not parse mailbox data\n");
return;
}
root = json_parser_get_root(parser);
mailbox = json_node_get_object(root);
if (json_object_has_member(mailbox, "messages"))
{
messages = json_node_get_array(json_object_get_member(mailbox, "messages"));
GList *message_list = json_array_get_elements(messages);
GList *current;
for (current = message_list; current; current = g_list_next(current))
{
JsonNode *currentNode = current->data;
JsonObject *message = json_node_get_object(currentNode);
gboolean is_new = (gboolean) json_node_get_int(json_object_get_member(message, "is_new"));
if (!is_new)
{
continue;
}
const gchar *subject = json_node_get_string(json_object_get_member(message, "subject"));
const gchar *from = json_node_get_string(json_object_get_member(message, "person"));
const gchar *to = oca->account->username;
const gchar *thread_id = json_node_get_string(json_object_get_member(message, "thread_id"));
gchar *url = g_strdup_printf("http://www.okcupid.com/messages?readmsg=true&threadid=%s&folder=1", thread_id);
purple_notify_email(oca->pc, subject, from, to, url, NULL, NULL);
g_free(url);
}
g_list_free(message_list);
}
g_object_unref(parser);
}