Exemplo n.º 1
0
PurpleStoredImage *
purple_buddy_icons_set_account_icon(PurpleAccount *account,
                                    guchar *icon_data, size_t icon_len)
{
	PurpleStoredImage *old_img;
	PurpleStoredImage *img = NULL;
	char *old_icon;

	if (icon_data != NULL && icon_len > 0)
	{
		img = purple_buddy_icon_data_new(icon_data, icon_len, NULL);
	}

	old_icon = g_strdup(purple_account_get_string(account, "buddy_icon", NULL));
	if (img && purple_buddy_icons_is_caching())
	{
		const char *filename = purple_imgstore_get_filename(img);
		purple_account_set_string(account, "buddy_icon", filename);
		purple_account_set_int(account, "buddy_icon_timestamp", time(NULL));
		ref_filename(filename);
	}
	else
	{
		purple_account_set_string(account, "buddy_icon", NULL);
		purple_account_set_int(account, "buddy_icon_timestamp", 0);
	}
	unref_filename(old_icon);

	old_img = g_hash_table_lookup(pointer_icon_cache, account);

	if (img)
		g_hash_table_insert(pointer_icon_cache, account, img);
	else
		g_hash_table_remove(pointer_icon_cache, account);

	if (purple_account_is_connected(account))
	{
		PurpleConnection *gc;
		PurplePluginProtocolInfo *prpl_info;

		gc = purple_account_get_connection(account);
		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));

		if (prpl_info && prpl_info->set_buddy_icon)
			prpl_info->set_buddy_icon(gc, img);
	}

	if (old_img)
		purple_imgstore_unref(old_img);
	else if (old_icon)
	{
		/* The old icon may not have been loaded into memory.  In that
		 * case, we'll need to uncache the filename.  The filenames
		 * are ref-counted, so this is safe. */
		purple_buddy_icon_data_uncache_file(old_icon);
	}
	g_free(old_icon);

	return img;
}
Exemplo n.º 2
0
static VALUE set_int_setting(VALUE self, VALUE name, VALUE value)
{
  PurpleAccount *account;
  Data_Get_Struct(self, PurpleAccount, account);
  purple_account_set_int(account, StringValueCStr(name), FIX2INT(value));
  return value;
}
Exemplo n.º 3
0
void QuetzalAccount::load(Config cfg)
{
	cfg.beginGroup(QLatin1String("general"));
	QByteArray password = cfg.value(QLatin1String("passwd"), QString(), Config::Crypted).toUtf8();
	if (!password.isEmpty()) {
		purple_account_set_password(m_account, password.constData());
		purple_account_set_remember_password(m_account, true);
	}
	purple_account_set_alias(m_account, cfg.value(QLatin1String("alias"),
												  QString()).toUtf8().constData());
	purple_account_set_user_info(m_account, cfg.value(QLatin1String("userInfo"),
													  QString()).toUtf8().constData());
	QMapIterator<QString, QVariant> it(cfg.value(QLatin1String("quetzal_settings")).toMap());
	while (it.hasNext()) {
		it.next();
		QByteArray key = it.key().toUtf8();
		QVariant::Type type = it.value().type();
		if (type == QVariant::Bool) {
			purple_account_set_bool(m_account, key.constData(), it.value().toBool());
		} else if (type == QVariant::Int || type == QVariant::UInt
				 || type == QVariant::LongLong || type == QVariant::ULongLong) {
			purple_account_set_int(m_account, key.constData(), it.value().toInt());
		} else {
			purple_account_set_string(m_account, key.constData(), it.value().toString().toUtf8());
		}
	}
	cfg.endGroup();
	
	RosterStorage::instance()->load(this);
	
	int size = cfg.beginArray(QLatin1String("chats"));
	QString name = QLatin1String("name");
	QString recent = QLatin1String("recent");
	QString data = QLatin1String("data");
	for (int i = 0; i < size; i++) {
		cfg.setArrayIndex(i);
		QByteArray alias = cfg.value(name, QString()).toUtf8();
		PurpleGroup *group = NULL;
		if (cfg.value(recent, false)) {
			group = purple_find_group("Recent");
			if (!group) {
				group = purple_group_new("Recent");
				purple_blist_add_group(group, NULL);
			}
		}
		GHashTable *comps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
		QMapIterator<QString, QVariant> it(cfg.value(data).toMap());
		while (it.hasNext()) {
			it.next();
			QByteArray key = it.key().toUtf8();
			QByteArray value = it.value().toString().toUtf8();
			g_hash_table_insert(comps, g_strdup(key.constData()), g_strdup(value.constData()));
		}
		PurpleChat *pc = purple_chat_new(m_account, alias.constData(), comps);
		purple_blist_add_chat(pc, NULL, NULL);
	}
	
	_purple_buddy_icons_blist_loaded_cb();
}
Exemplo n.º 4
0
static void
account_update(GtkWidget *widget, GtkOptionMenu *optmenu)
{
	PurpleAccount *account = NULL;

	account = g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(optmenu)))), "account");
	purple_account_set_int(account, "score", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
}
Exemplo n.º 5
0
    PurpleAccount* createPurpleAccount(MojString username, MojString prpl, MojObject prefs)
    {
        PurplePluginProtocolInfo* info = getProtocolInfo(prpl.data());

        // TODO: Strip off possible junk here!
        //       The Username Split API might be useful, as soon as I have
        //       understood it ...
        PurpleAccount* account = purple_account_new(username.data(), prpl.data());

        for(GList* l = info->protocol_options; l != NULL; l = l->next)
        {
            PurpleAccountOption* option = (PurpleAccountOption*)l->data;

            const char* name = purple_account_option_get_setting(option);

            if (!prefs.contains(name))
                continue;

            switch(purple_account_option_get_type(option))
            {
            case PURPLE_PREF_BOOLEAN:
                {
                    bool value;
                    prefs.get(name, value);
                    purple_account_set_bool(account, name, value);
                }
                break;

            case PURPLE_PREF_INT:
                {
                    bool found;
                    int value;
                    prefs.get(name, value, found);
                    purple_account_set_int(account, name, value);
                }
                break;

            case PURPLE_PREF_STRING:
            case PURPLE_PREF_STRING_LIST:
                {
                    bool found;
                    MojString value;
                    prefs.get(name, value, found);
                    purple_account_set_string(account, name, value.data());
                }
                break;

            default:
                continue;
            }
        }

        return account;
    }
Exemplo n.º 6
0
void AccountWindow::IntegerOption::responseHandler(
    CppConsUI::InputDialog& activator,
    CppConsUI::AbstractDialog::ResponseType response)
{
  if (response != AbstractDialog::RESPONSE_OK)
    return;

  const char *text = activator.getText();
  errno = 0;
  long i = strtol(text, NULL, 10);
  if (errno == ERANGE || i > INT_MAX || i < INT_MIN)
    LOG->warning(_("Value is out of range."));
  purple_account_set_int(account, purple_account_option_get_setting(option),
      CLAMP(i, INT_MIN, INT_MAX));

  updateValue();
}
Exemplo n.º 7
0
time_t
purple_buddy_icons_get_account_icon_timestamp(PurpleAccount *account)
{
	time_t ret;

	g_return_val_if_fail(account != NULL, 0);

	ret = purple_account_get_int(account, "buddy_icon_timestamp", 0);

	/* This deals with migration cases. */
	if (ret == 0 && purple_account_get_string(account, "buddy_icon", NULL) != NULL)
	{
		ret = time(NULL);
		purple_account_set_int(account, "buddy_icon_timestamp", ret);
	}

	return ret;
}
Exemplo n.º 8
0
/** we fold the following methods into one set() method:
 * account_set_bool
 * account_set_int
 * account_set_string */
static int account_set(LuaState *L)/*{{{*/
{
    PurpleAccount **account = ms_lua_checkclass(L, "purple.account", 1);
    const char *key         = luaL_checkstring(L, 2);

    switch (lua_type(L, 3)) {
        case LUA_TNUMBER:
            purple_account_set_int(*account, key, lua_tonumber(L, 3));
            break;
        case LUA_TBOOLEAN:
            purple_account_set_bool(*account, key, lua_toboolean(L, 3));
        case LUA_TSTRING:
            purple_account_set_string(*account, key, lua_tostring(L, 3));
        default:
            luaL_error(L, "unsupported type for set()");
            break;
    }
    return 0;
}/*}}}*/
Exemplo n.º 9
0
static void purple_sync_settings( account_t *acc, PurpleAccount *pa )
{
	PurplePlugin *prpl = purple_plugins_find_with_id( pa->protocol_id );
	PurplePluginProtocolInfo *pi = prpl->info->extra_info;
	GList *i;
	
	for( i = pi->protocol_options; i; i = i->next )
	{
		PurpleAccountOption *o = i->data;
		const char *name;
		set_t *s;
		
		name = purple_account_option_get_setting( o );
		s = set_find( &acc->set, name );
		if( s->value == NULL )
			continue;
		
		switch( purple_account_option_get_type( o ) )
		{
		case PURPLE_PREF_STRING:
		case PURPLE_PREF_STRING_LIST:
			purple_account_set_string( pa, name, set_getstr( &acc->set, name ) );
			break;
		
		case PURPLE_PREF_INT:
			purple_account_set_int( pa, name, set_getint( &acc->set, name ) );
			break;
		
		case PURPLE_PREF_BOOLEAN:
			purple_account_set_bool( pa, name, set_getbool( &acc->set, name ) );
			break;
		
		default:
			break;
		}
	}
	
	if( pi->options & OPT_PROTO_MAIL_CHECK )
		purple_account_set_check_mail( pa, set_getbool( &acc->set, "mail_notifications" ) );
}
Exemplo n.º 10
0
static void fb_got_notifications_cb(FacebookAccount *fba, gchar *url_text, gsize len, gpointer userdata)
{
	gchar *salvaged;
	time_t last_fetch_time;
	time_t time_of_message;
	time_t newest_message = 0;
	xmlnode *channel;//VOXOX - CJC - 2009.07.06 
	xmlnode *rss_root;//VOXOX - CJC - 2009.07.06 
	xmlnode *item;//VOXOX - CJC - 2009.07.06 
	xmlnode *link;//VOXOX - CJC - 2009.07.06 
	xmlnode *title;//VOXOX - CJC - 2009.07.06 
	gchar *tmp;
	gchar month_string[4], weekday[4];
	guint year, month, day, hour, minute, second;
	long timezone;
	gchar *subject, *url;

	month_string[3] = weekday[3] = '\0';
	year = month = day = hour = minute = second = 0;

	if (!url_text || !len)
		return;

	last_fetch_time = purple_account_get_int(fba->account, "facebook_notifications_last_fetch", 0);
	/* purple_debug_info("facebook", "last fetch time: %zu\n", last_fetch_time); */

	salvaged = purple_utf8_salvage(url_text);
	rss_root = xmlnode_from_str(salvaged, -1);
	g_free(salvaged);

	if (rss_root == NULL)
	{
		purple_debug_error("facebook", "Could not load RSS file\n");
		return;
	}
	channel = xmlnode_get_child(rss_root, "channel");
	if (channel == NULL)
	{
		purple_debug_warning("facebook", "Invalid RSS feed\n");
		xmlnode_free(rss_root);
		return;
	}
	item = xmlnode_get_child(channel, "item");
	if (item == NULL)
	{
		purple_debug_info("facebook", "No new notifications\n");
	}
	for (; item != NULL; item = xmlnode_get_next_twin(item))
	{
		xmlnode *pubDate = xmlnode_get_child(item, "pubDate");
		if (!pubDate)
			continue;
		tmp = xmlnode_get_data_unescaped(pubDate);
		/* rss times are in Thu, 19 Jun 2008 15:51:25 -1100 format */
		sscanf(tmp, "%3s, %2u %3s %4u %2u:%2u:%2u %5ld", (char*)&weekday, &day, (char*)&month_string, &year, &hour, &minute, &second, &timezone);
		if (g_str_equal(month_string, "Jan")) month = 0;
		else if (g_str_equal(month_string, "Feb")) month = 1;
		else if (g_str_equal(month_string, "Mar")) month = 2;
		else if (g_str_equal(month_string, "Apr")) month = 3;
		else if (g_str_equal(month_string, "May")) month = 4;
		else if (g_str_equal(month_string, "Jun")) month = 5;
		else if (g_str_equal(month_string, "Jul")) month = 6;
		else if (g_str_equal(month_string, "Aug")) month = 7;
		else if (g_str_equal(month_string, "Sep")) month = 8;
		else if (g_str_equal(month_string, "Oct")) month = 9;
		else if (g_str_equal(month_string, "Nov")) month = 10;
		else if (g_str_equal(month_string, "Dec")) month = 11;
		g_free(tmp);

		/* try using pidgin's functions */
		tmp = g_strdup_printf("%04u%02u%02uT%02u%02u%02u%05ld", year, month, day, hour, minute, second, timezone);
		time_of_message = purple_str_to_time(tmp, FALSE, NULL, NULL, NULL);
		g_free(tmp);

		if (time_of_message <= 0)
		{
			/* there's no cross-platform, portable way of converting string to time
			   which doesn't need a new version of glib, so just cheat */
			time_of_message = second + 60*minute + 3600*hour + 86400*day + 2592000*month + 31536000*(year-1970);
		}

		if (time_of_message > newest_message)
		{
			/* we'll keep the newest message to save */
			newest_message = time_of_message;
		}

		if (time_of_message <= last_fetch_time)
		{
			/* fortunatly, rss messages are ordered from newest to oldest */
			/* so if this message is older than the last one, ignore rest */
			break;
		}
		
		link = xmlnode_get_child(item, "link");
		if (link)
		{
			url = xmlnode_get_data_unescaped(link);
		} else {
			url = g_strdup("");
		}
		
		title = xmlnode_get_child(item, "title");
		if (title)
		{
			subject = xmlnode_get_data_unescaped(title);
		} else {
			subject = g_strdup("");
		}
		
		purple_notify_email(fba->pc, subject, NULL, fba->account->username, url, NULL, NULL);
		g_free(subject);
		g_free(url);
	}
	xmlnode_free(rss_root);

	if (newest_message > last_fetch_time)
	{
		/* update the last fetched time if we had newer messages */
		purple_account_set_int(fba->account, "facebook_notifications_last_fetch", newest_message);
	}
}
Exemplo n.º 11
0
static void
pb_got_everything(PushBulletAccount *pba, JsonNode *node, gpointer user_data)
{
	JsonObject *rootobj = json_node_get_object(node);
	JsonArray *devices = json_object_has_member(rootobj, "devices") ? json_object_get_array_member(rootobj, "devices") : NULL;
	JsonArray *pushes = json_object_has_member(rootobj, "pushes") ? json_object_get_array_member(rootobj, "pushes") : NULL;
	JsonArray *contacts = json_object_has_member(rootobj, "contacts") ? json_object_get_array_member(rootobj, "contacts") : NULL;
	JsonArray *chats = json_object_has_member(rootobj, "chats") ? json_object_get_array_member(rootobj, "chats") : NULL;
	JsonArray *texts = json_object_has_member(rootobj, "texts") ? json_object_get_array_member(rootobj, "texts") : NULL;
	gint i;
	guint len;
	PurpleGroup *pbgroup;
	
	pbgroup = purple_find_group("PushBullet");
	if (!pbgroup)
	{
		pbgroup = purple_group_new("PushBullet");
		purple_blist_add_group(pbgroup, NULL);
	}
	
	if (json_object_has_member(rootobj, "error")) {
		JsonObject *error = json_object_get_object_member(rootobj, "error");
		const gchar *type = json_object_get_string_member(error, "type");
		const gchar *message = json_object_get_string_member(error, "message");
		
		//TODO check type
		purple_connection_error_reason(pba->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, message);
		return;
	}
	
	if (devices != NULL) {
		for(i = 0, len = json_array_get_length(devices); i < len; i++) {
			JsonObject *device = json_array_get_object_element(devices, i);
			
			if (pba->main_sms_device == NULL && json_object_get_boolean_member(device, "has_sms")) {
				pba->main_sms_device = g_strdup(json_object_get_string_member(device, "iden"));
				purple_account_set_string(pba->account, "main_sms_device", pba->main_sms_device);
				
				pb_get_phonebook(pba, pba->main_sms_device);
				
				if (!pba->websocket) {
					pb_start_polling(pba);
				}
				
				break; //TODO handle more than one
			}
		}
	}
	
	if (pushes != NULL) {
		gint last_message_timestamp = purple_account_get_int(pba->account, "last_message_timestamp", 0);
		for(i = json_array_get_length(pushes); i > 0; i--) {
			JsonObject *push = json_array_get_object_element(pushes, i - 1);
			const gchar *type = json_object_get_string_member(push, "type");
			gdouble modified;
			time_t timestamp;
			gboolean dismissed;
			
			if (!type)
				continue;
			
			modified = json_object_get_double_member(push, "modified");
			timestamp = (time_t) modified;
			dismissed = json_object_get_boolean_member(push, "dismissed");
			
			if (timestamp <= last_message_timestamp || dismissed) {
				continue;
			}
			
			// {"active":true,"iden":"uffvytgsjApuAUIFRk","created":1.438895081423904e+09,"modified":1.438895081432786e+09,"type":"file","dismissed":false,"guid":"153b70f0-f7a6-4db9-a6f4-28b99fa416f1","direction":"self","sender_iden":"uffvytg","sender_email":"*****@*****.**","sender_email_normalized":"*****@*****.**","sender_name":"Eion Robb","receiver_iden":"uffvytg","receiver_email":"*****@*****.**","receiver_email_normalized":"*****@*****.**","target_device_iden":"uffvytgsjz7O3P0Jl6","source_device_iden":"uffvytgsjAoIRwhIL6","file_name":"IMG_20150807_084618.jpg","file_type":"image/jpeg","file_url":"https://dl.pushbulletusercontent.com/FHOZdyzfvnoYZY0DP6oK1rGKiJpWCPc0/IMG_20150807_084618.jpg","image_width":4128,"image_height":2322,"image_url":"https://lh3.googleusercontent.com/WY5TK7h3mzD32qMcnxtqt-4PrYcWW1uWDHnRW2x1oJK8mnYk2v4HbZrRjIQkiYdxMKQSdNI8GGPqfO6s6tEyuRVLzeA"}
			
			if (purple_strequal(type, "note") || purple_strequal(type, "link") || purple_strequal(type, "file")) {
				const gchar *from = json_object_get_string_member(push, "sender_email_normalized");
				const gchar *body = json_object_get_string_member(push, "body");
				const gchar *direction = json_object_get_string_member(push, "direction");
				gchar *body_html;
				
				if (from == NULL) {
					if (!json_object_has_member(push, "sender_name")) {
						purple_debug_error("pushbullet", "no sender name/email\n");
						continue;
					}
					from = json_object_get_string_member(push, "sender_name");
				}
				
				if (body && *body) {
					body_html = purple_strdup_withhtml(body);
				} else {
					const gchar *title = json_object_get_string_member(push, "title");
					if (title && *title) {
						body_html = purple_strdup_withhtml(title);
					} else {
						body_html = "Message";
					}
				}
				
				if (json_object_has_member(push, "url")) {
					gchar *body_with_link = g_strconcat("<a href=\"", json_object_get_string_member(push, "url"), "\">", body_html, "</a>", NULL);
					g_free(body_html);
					body_html = body_with_link;
					
				} else if (json_object_has_member(push, "image_url")) {
					const gchar *image_url = json_object_get_string_member(push, "image_url");
					PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, pba->account);
					
					if (conv == NULL)
					{
						conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, pba->account, from);
					}
					pb_download_image_to_conv(image_url, conv);
					
				} else if (json_object_has_member(push, "file_url")) {
					gchar *body_with_link;
					const gchar *file_name = json_object_get_string_member(push, "file_name");
					
					if (file_name && *file_name) {
						g_free(body_html);
						body_html = purple_strdup_withhtml(file_name);
					}
					
					body_with_link= g_strconcat("<a href=\"", json_object_get_string_member(push, "file_url"), "\">", json_object_get_string_member(push, "file_name"), "</a>", NULL);
					g_free(body_html);
					body_html = body_with_link;
				}
				
				if (direction[0] != 'o') {
					serv_got_im(pba->pc, from, body_html, PURPLE_MESSAGE_RECV, timestamp);
				} else {
					const gchar *guid = json_object_get_string_member(push, "guid");
					from = json_object_get_string_member(push, "receiver_email_normalized");
					
					if (!guid || !g_hash_table_remove(pba->sent_messages_hash, guid)) {
						PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, pba->account);
						if (conv == NULL)
						{
							conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, pba->account, from);
						}
						purple_conversation_write(conv, from, body_html, PURPLE_MESSAGE_SEND, timestamp);
					}
				}
				
				g_free(body_html);
			}
				
			purple_account_set_int(pba->account, "last_message_timestamp", MAX(purple_account_get_int(pba->account, "last_message_timestamp", 0), timestamp));
		}
	}
	
	if (contacts != NULL) {
		for(i = 0, len = json_array_get_length(contacts); i < len; i++) {
			JsonObject *contact = json_array_get_object_element(contacts, i);
			const gchar *email = json_object_get_string_member(contact, "email_normalized");
			const gchar *name = json_object_get_string_member(contact, "name");
			const gchar *image_url = json_object_get_string_member(contact, "image_url");
			
			PurpleBuddy *buddy = purple_find_buddy(pba->account, email);
			if (buddy == NULL)
			{
				buddy = purple_buddy_new(pba->account, email, name);
				purple_blist_add_buddy(buddy, NULL, pbgroup, NULL);
			}
			purple_prpl_got_user_status(pba->account, email, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
		}
	}
	
	if (chats != NULL) {
		for(i = 0, len = json_array_get_length(chats); i < len; i++) {
			JsonObject *chat = json_array_get_object_element(chats, i);
			JsonObject *contact = json_object_get_object_member(chat, "with");
			const gchar *email = json_object_get_string_member(contact, "email_normalized");
			const gchar *name = json_object_get_string_member(contact, "name");
			const gchar *image_url = json_object_get_string_member(contact, "image_url");
			
			PurpleBuddy *buddy = purple_find_buddy(pba->account, email);
			if (buddy == NULL)
			{
				buddy = purple_buddy_new(pba->account, email, name);
				purple_blist_add_buddy(buddy, NULL, pbgroup, NULL);
			}
			purple_prpl_got_user_status(pba->account, email, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
		}
	}
	
	if (texts != NULL) {
		for(i = 0, len = json_array_get_length(texts); i < len; i++) {
			JsonObject *text = json_array_get_object_element(texts, i);
		}
	}
}
Exemplo n.º 12
0
static void
pb_got_phone_thread(PushBulletAccount *pba, JsonNode *node, gpointer user_data)
{
	PurpleAccount *account = pba->account;
	PurpleConnection *pc = pba->pc;
	JsonObject *rootobj = json_node_get_object(node);
	JsonObject *data = json_object_get_object_member(rootobj, "data");
	JsonArray *thread = json_object_get_array_member(data, "thread");
	gint i;
	guint len;
	gchar *from = user_data;
	PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, account);
	gint purple_last_message_timestamp = purple_account_get_int(account, "last_message_timestamp", 0);
	gint newest_phone_message_id = purple_account_get_int(account, "newest_phone_message_id", 0);
	
	/*
	{"id":"652","type":"sms","timestamp":1440484608,"direction":"outgoing","body":"message","status":"sent"},
	{"id":"5","type":"mms","timestamp":1440484096,"direction":"incoming","recipient_index":0,"body":"","image_urls":["url1234"]}
	*/
	for(i = json_array_get_length(thread); i > 0; i--)
	{
		JsonObject *message = json_array_get_object_element(thread, i - 1);
		gint64 timestamp = json_object_get_int_member(message, "timestamp");
		const gchar *direction = json_object_get_string_member(message, "direction");
		const gchar *body = json_object_get_string_member(message, "body");
		gint id = atoi(json_object_get_string_member(message, "id"));
		
		if (timestamp > purple_last_message_timestamp || id > newest_phone_message_id) {
			gchar *body_html = purple_strdup_withhtml(body);
			if (direction[0] != 'o') {
				serv_got_im(pc, from, body_html, PURPLE_MESSAGE_RECV, timestamp);
			} else {
				const gchar *guid = json_object_get_string_member(message, "guid");
				if (!guid || !g_hash_table_remove(pba->sent_messages_hash, guid)) {
					if (conv == NULL)
					{
						conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, from);
					}
					purple_conversation_write(conv, from, body_html, PURPLE_MESSAGE_SEND, timestamp);
				}
			}
			g_free(body_html);
			
			if (json_object_has_member(message, "image_urls")) {
				JsonArray *image_urls = json_object_get_array_member(message, "image_urls");
				guint j, image_urls_len;
				
				if (conv == NULL)
				{
					conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, from);
				}
				
				for(j = 0, image_urls_len = json_array_get_length(image_urls); j < image_urls_len; j++) {
					const gchar *image_url = json_array_get_string_element(thread, j);
					
					pb_download_image_to_conv(image_url, conv);
				}
			}
			
			purple_account_set_int(account, "last_message_timestamp", MAX(purple_account_get_int(account, "last_message_timestamp", 0), timestamp));
			purple_account_set_int(account, "newest_phone_message_id", MAX(purple_account_get_int(account, "newest_phone_message_id", 0), id));
		}
	}
	
	g_free(from);
}