Example #1
0
void PurpleLine::write_message(line::Message &msg, bool replay) {
    std::string text;
    int flags = 0;
    time_t mtime = (time_t)(msg.createdTime / 1000);

    bool sent = (msg.from == profile.mid);

    if (std::find(recent_messages.cbegin(), recent_messages.cend(), msg.id)
        != recent_messages.cend())
    {
        // We already processed this message. User is probably talking with himself.
        return;
    }

    // Hack
    if (msg.from == msg.to)
        push_recent_message(msg.id);

    PurpleConversation *conv = purple_find_conversation_with_account(
        (msg.toType == line::MIDType::USER ? PURPLE_CONV_TYPE_IM : PURPLE_CONV_TYPE_CHAT),
        ((!sent && msg.toType == line::MIDType::USER) ? msg.from.c_str() : msg.to.c_str()),
        acct);

    // If this is a new received IM, create the conversation if it doesn't exist
    if (!conv && !sent && msg.toType == line::MIDType::USER)
        conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, msg.from.c_str());

    // If this is a new conversation, we're not replaying history and history hasn't been fetched
    // yet, queue the message instead of showing it.
    if (conv && !replay) {
        auto *queue = (std::vector<line::Message> *)
            purple_conversation_get_data(conv, "line-message-queue");

        if (queue) {
            queue->push_back(msg);
            return;
        }
    }

    // Replaying messages from history
    // Unfortunately Pidgin displays messages with this flag with odd formatting and no username.
    // Disable for now.
    //if (replay)
    //    flags |= PURPLE_MESSAGE_NO_LOG;

    switch (msg.contentType) {
        case line::ContentType::NONE: // actually text
        case line::ContentType::LOCATION:
            if (msg.__isset.location) {
                line::Location &loc = msg.location;

                text = markup_escape(loc.title)
                    + " | <a href=\"https://maps.google.com/?q=" + url_encode(loc.address)
                    + "&ll=" + std::to_string(loc.latitude)
                    + "," + std::to_string(loc.longitude)
                    + "\">"
                    + (loc.address.size()
                        ? markup_escape(loc.address)
                        : "(no address)")
                    + "</a>";
            } else {
                text = markup_escape(msg.text);
            }
            break;

        case line::ContentType::STICKER:
            {
                std::string id = get_sticker_id(msg);

                if (id == "")  {
                    text = "<em>[Broken sticker]</em>";

                    purple_debug_warning("line", "Got a broken sticker.\n");
                } else {
                    text = id;

                    if (conv
                        && purple_conv_custom_smiley_add(conv, id.c_str(), "id", id.c_str(), TRUE))
                    {
                        http.request(get_sticker_url(msg),
                            [this, id, conv](int status, const guchar *data, gsize len)
                            {
                                if (status == 200 && data && len > 0) {
                                    purple_conv_custom_smiley_write(
                                        conv,
                                        id.c_str(),
                                        data,
                                        len);
                                } else {
                                    purple_debug_warning(
                                        "line",
                                        "Couldn't download sticker. Status: %d\n",
                                        status);
                                }

                                purple_conv_custom_smiley_close(conv, id.c_str());
                            });
                    }
                }
            }
            break;

        case line::ContentType::IMAGE:
        case line::ContentType::VIDEO: // Videos could really benefit from streaming...
            {
                std::string type_std = line::_ContentType_VALUES_TO_NAMES.at(msg.contentType);

                std::string id = "[LINE " + type_std + " " + msg.id + "]";

                text = id;

                if (conv) {
                    text += " <font color=\"#888888\">/open "
                        + conv_attachment_add(conv, msg.contentType, msg.id)
                        + "</font>";
                }

                if (!conv
                    || !purple_conv_custom_smiley_add(conv, id.c_str(), "id", id.c_str(), TRUE))
                {
                    break;
                }

                if (msg.contentPreview.size() > 0) {
                    purple_conv_custom_smiley_write(
                        conv,
                        id.c_str(),
                        (const guchar *)msg.contentPreview.c_str(),
                        msg.contentPreview.size());

                    purple_conv_custom_smiley_close(conv, id.c_str());
                } else {
                    std::string preview_url = msg.contentMetadata.count("PREVIEW_URL")
                        ? msg.contentMetadata["PREVIEW_URL"]
                        : std::string(LINE_OS_URL) + "os/m/" + msg.id + "/preview";

                    http.request(preview_url, HTTPFlag::AUTH | HTTPFlag::LARGE,
                        [this, id, conv](int status, const guchar *data, gsize len)
                        {
                            if (status == 200 && data && len > 0) {
                                purple_conv_custom_smiley_write(
                                    conv,
                                    id.c_str(),
                                    data,
                                    len);
                            } else {
                                purple_debug_warning(
                                    "line",
                                    "Couldn't download image message. Status: %d\n",
                                    status);
                            }

                            purple_conv_custom_smiley_close(conv, id.c_str());
                        });
                }
            }
            break;

        case line::ContentType::AUDIO:
            {
                text = "[Audio message";

                if (msg.contentMetadata.count("AUDLEN")) {
                    int len = 0;

                    try {
                        len = std::stoi(msg.contentMetadata["AUDLEN"]);
                    } catch(...) { /* ignore */ }

                    if (len > 0) {
                        text += " "
                            + std::to_string(len / 1000)
                            + "."
                            + std::to_string((len % 1000) / 100)
                            + "s";
                    }
                }

                text += "]";

                if (conv) {
                    text += " <font color=\"#888888\">/open "
                        + conv_attachment_add(conv, msg.contentType, msg.id)
                        + "</font>";
                }
            }
            break;

        // TODO: other content types

        default:
            text = "<em>[Not implemented: ";
            text += line::_ContentType_VALUES_TO_NAMES.at(msg.contentType);
            text += " message]</em>";
            break;
    }

    if (sent) {
        // Messages sent by user (sync from other devices)

        write_message(conv, msg.from, text, mtime, flags | PURPLE_MESSAGE_SEND);
    } else {
        // Messages received from other users

        flags |= PURPLE_MESSAGE_RECV;

        if (replay) {
            // Write replayed messages instead of serv_got_* to avoid Pidgin's IM sound

            write_message(conv, msg.from, text, mtime, flags);
        } else {
            if (msg.toType == line::MIDType::USER) {
                serv_got_im(
                    conn,
                    msg.from.c_str(),
                    text.c_str(),
                    (PurpleMessageFlags)flags,
                    mtime);
            } else if (msg.toType == line::MIDType::GROUP || msg.toType == line::MIDType::ROOM) {
                serv_got_chat_in(
                    conn,
                    purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)),
                    msg.from.c_str(),
                    (PurpleMessageFlags)flags,
                    text.c_str(),
                    mtime);
            }
        }
    }
}
static void
update_current_playing_data (RBNotificationPlugin *plugin, RhythmDBEntry *entry)
{
	GValue *value;
	const char *stream_title = NULL;
	char *artist = NULL;
	char *album = NULL;
	char *title = NULL;
	GString *secondary;
	RBExtDBKey *key;

	const char *artist_template = NULL;
	const char *album_template = NULL;

	g_free (plugin->current_title);
	g_free (plugin->current_album_and_artist);
	plugin->current_title = NULL;
	plugin->current_album_and_artist = NULL;

	if (entry == NULL) {
		plugin->current_title = g_strdup (_("Not Playing"));
		plugin->current_album_and_artist = g_strdup ("");
		g_free (plugin->notify_art_path);
		plugin->notify_art_path = NULL;
		return;
	}

	secondary = g_string_sized_new (100);

	if (plugin->notify_art_key == NULL ||
	    (rhythmdb_entry_matches_ext_db_key (plugin->db, entry, plugin->notify_art_key) == FALSE)) {
		if (plugin->notify_art_key)
			rb_ext_db_key_free (plugin->notify_art_key);
		plugin->notify_art_key = NULL;
		g_free (plugin->notify_art_path);
		plugin->notify_art_path = NULL;

		/* request album art */
		key = rhythmdb_entry_create_ext_db_key (entry, RHYTHMDB_PROP_ALBUM);
		rb_ext_db_request (plugin->art_store,
				   key,
				   (RBExtDBRequestCallback) art_cb,
				   g_object_ref (plugin),
				   g_object_unref);
		rb_ext_db_key_free (key);
	}

	/* get artist, preferring streaming song details */
	value = rhythmdb_entry_request_extra_metadata (plugin->db,
						       entry,
						       RHYTHMDB_PROP_STREAM_SONG_ARTIST);
	if (value != NULL) {
		artist = markup_escape (g_value_get_string (value));
		g_value_unset (value);
		g_free (value);
	} else {
		artist = markup_escape (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
	}

	/* get album, preferring streaming song details */
	value = rhythmdb_entry_request_extra_metadata (plugin->db,
						       entry,
						       RHYTHMDB_PROP_STREAM_SONG_ALBUM);
	if (value != NULL) {
		album = markup_escape (g_value_get_string (value));
		g_value_unset (value);
		g_free (value);
	} else {
		album = markup_escape (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
	}

	get_artist_album_templates (artist, album, &artist_template, &album_template);

	if (artist != NULL && artist[0] != '\0') {
		g_string_append_printf (secondary, artist_template, artist);
	}
	g_free (artist);

	if (album != NULL && album[0] != '\0') {
		if (secondary->len != 0)
			g_string_append_c (secondary, ' ');

		g_string_append_printf (secondary, album_template, album);
	}
	g_free (album);

	/* get title and possibly stream name.
	 * if we have a streaming song title, the entry's title
	 * property is the stream name.
	 */
	value = rhythmdb_entry_request_extra_metadata (plugin->db,
						       entry,
						       RHYTHMDB_PROP_STREAM_SONG_TITLE);
	if (value != NULL) {
		title = g_value_dup_string (value);
		g_value_unset (value);
		g_free (value);

		stream_title = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE);
	} else {
		title = g_strdup (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE));
	}

	if (stream_title != NULL && stream_title[0] != '\0') {
		char *escaped;

		escaped = markup_escape (stream_title);
		if (secondary->len == 0)
			g_string_append (secondary, escaped);
		else
			g_string_append_printf (secondary, " (%s)", escaped);
		g_free (escaped);
	}

	if (title == NULL) {
		/* Translators: unknown track title */
		title = g_strdup (_("Unknown"));
	}

	plugin->current_title = title;
	plugin->current_album_and_artist = g_string_free (secondary, FALSE);
}