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); }