Example #1
0
static void
detach_signals(PurpleConversation *conv)
{
	PidginConversation *gtkconv = NULL;
	PidginWindow *gtkwin = NULL;
	GSList *ids = NULL, *l;

	gtkconv = PIDGIN_CONVERSATION(conv);
	if (!gtkconv)
		return;
	gtkwin  = gtkconv->win;

	ids = purple_conversation_get_data(conv, "notify-imhtml-signals");
	for (l = ids; l != NULL; l = l->next)
		g_signal_handler_disconnect(gtkconv->imhtml, GPOINTER_TO_INT(l->data));
	g_slist_free(ids);

	ids = purple_conversation_get_data(conv, "notify-entry-signals");
	for (l = ids; l != NULL; l = l->next)
		g_signal_handler_disconnect(gtkconv->entry, GPOINTER_TO_INT(l->data));
	g_slist_free(ids);

	purple_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(0));

	purple_conversation_set_data(conv, "notify-imhtml-signals", NULL);
	purple_conversation_set_data(conv, "notify-entry-signals", NULL);
}
static void
hide_conv(PidginConversation *gtkconv, gboolean closetimer)
{
	GList *list;

	purple_signal_emit(pidgin_conversations_get_handle(),
			"conversation-hiding", gtkconv);

	for (list = g_list_copy(gtkconv->convs); list; list = g_list_delete_link(list, list)) {
		PurpleConversation *conv = list->data;
		if (closetimer) {
			guint timer = GPOINTER_TO_INT(purple_conversation_get_data(conv, "close-timer"));
			if (timer)
				purple_timeout_remove(timer);
			timer = purple_timeout_add_seconds(CLOSE_CONV_TIMEOUT_SECS, close_already, conv);
			purple_conversation_set_data(conv, "close-timer", GINT_TO_POINTER(timer));
		}
#if 0
		/* I will miss you */
		purple_conversation_set_ui_ops(conv, NULL);
#else
		pidgin_conv_window_remove_gtkconv(gtkconv->win, gtkconv);
		pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv);
#endif
	}
}
Example #3
0
static int
unnotify_cb(GtkWidget *widget, gpointer data, PurpleConversation *conv)
{
	if (GPOINTER_TO_INT(purple_conversation_get_data(conv, "notify-message-count")) != 0)
		unnotify(conv, TRUE);

	return 0;
}
Example #4
0
static void twitter_conv_icon_add_conv(TwitterConvIcon * conv_icon, PurpleConversation * conv)
{
    GList         **conv_conv_icons = purple_conversation_get_data(conv, PLUGIN_ID "-conv-icons");
    g_return_if_fail(conv_conv_icons != NULL);

    if (!g_list_find(conv_icon->convs, conv)) {
        conv_icon->convs = g_list_prepend(conv_icon->convs, conv);
        *conv_conv_icons = g_list_prepend(*conv_conv_icons, conv_icon);
    }
}
Example #5
0
static void twitter_conv_icon_deleting_conversation_cb(PurpleConversation * conv, PurpleAccount * account)
{
    GList         **conv_icons;
    if (purple_conversation_get_account(conv) != account)
        return;

    twitter_conv_icon_remove_conversation_conv_icons(conv);

    conv_icons = purple_conversation_get_data(conv, PLUGIN_ID "-conv-icons");
    g_free(conv_icons);
}
Example #6
0
static void twitter_conv_icon_displayed_chat_cb(PurpleAccount * account, const char *who, char *message, PurpleConversation * conv, PurpleMessageFlags flags, void *account_signal)
{
    GtkIMHtml      *imhtml;
    GtkTextBuffer  *text_buffer;
    GtkTextIter     insertion_point;
    gint            linenumber;
    TwitterConvIcon *conv_icon;
    PurpleConnection *gc;
    TwitterConnectionData *twitter;

    if (account != account_signal)
        return;

    gc = purple_account_get_connection(account);
    if (!gc) {
        return;
    }

    twitter = gc->proto_data;

    purple_debug_info(PLUGIN_ID, "%s\n", G_STRFUNC);

    /* insert icon */
    imhtml = GTK_IMHTML(PIDGIN_CONVERSATION(conv)->imhtml);
    text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml));

    /* get GtkTextIter in the target line */
    linenumber = GPOINTER_TO_INT(purple_conversation_get_data(conv, PLUGIN_ID "-icon-ln"));
    gtk_text_buffer_get_iter_at_line(text_buffer, &insertion_point, linenumber);

    conv_icon = twitter_conv_icon_find(account, who);

    /* if we don't have the icon for this user, put a mark instead and
     * request the icon */
    if (!conv_icon) {
        conv_icon = twitter_conv_icon_new(account, who);
        twitter_conv_icon_add_conv(conv_icon, conv);
        g_hash_table_insert(twitter->icons, g_strdup(purple_normalize(account, who)), conv_icon);
        mark_icon_for_user(gtk_text_buffer_create_mark(text_buffer, NULL, &insertion_point, FALSE), conv_icon);
        return;
    }
    twitter_conv_icon_add_conv(conv_icon, conv);

    /* if we have the icon for this user, insert the icon immediately */
    if (TRUE) {
        if (conv_icon->pixbuf) {
            gtk_text_buffer_insert_pixbuf(text_buffer, &insertion_point, conv_icon->pixbuf);
        } else {
            mark_icon_for_user(gtk_text_buffer_create_mark(text_buffer, NULL, &insertion_point, FALSE), conv_icon);
        }
    }

    purple_debug_info(PLUGIN_ID, "end %s\n", G_STRFUNC);
}
Example #7
0
std::string PurpleLine::conv_attachment_add(PurpleConversation *conv,
    line::ContentType::type type, std::string id)
{
    auto atts = (std::vector<Attachment> *)purple_conversation_get_data(conv, "line-attachments");
    if (!atts) {
        atts = new std::vector<Attachment>();
        purple_conversation_set_data(conv, "line-attachments", atts);
    }

    atts->emplace_back(type, id);

    return std::to_string(atts->size());
}
Example #8
0
PurpleLine::Attachment *PurpleLine::conv_attachment_get(PurpleConversation *conv, std::string token)
{
    int index;

    try {
        index = std::stoi(token);
    } catch (...) {
        return nullptr;
    }

    auto atts = (std::vector<Attachment> *)purple_conversation_get_data(conv, "line-attachments");

    return (atts && index <= (int)atts->size()) ? &(*atts)[index - 1] : nullptr;
}
Example #9
0
static guint
count_messages(PidginWindow *purplewin)
{
	guint count = 0;
	GList *convs = NULL, *l;

	for (convs = purplewin->gtkconvs; convs != NULL; convs = convs->next) {
		PidginConversation *conv = convs->data;
		for (l = conv->convs; l != NULL; l = l->next) {
			count += GPOINTER_TO_INT(purple_conversation_get_data(l->data, "notify-message-count"));
		}
	}

	return count;
}
Example #10
0
void PurpleLine::signal_deleting_conversation(PurpleConversation *conv) {
    if (purple_conversation_get_account(conv) != acct)
        return;

    auto queue = (std::vector<line::Message> *)
        purple_conversation_get_data(conv, "line-message-queue");

    if (queue) {
        purple_conversation_set_data(conv, "line-message-queue", nullptr);
        delete queue;
    }

    int64_t *end_seq_p = (int64_t *)purple_conversation_get_data(conv, "line-end-seq");
    if (end_seq_p) {
        purple_conversation_set_data(conv, "line-end-seq", nullptr);
        delete end_seq_p;
    }

    auto atts = (std::vector<Attachment> *)purple_conversation_get_data(conv, "line-attachments");
    if (atts) {
        purple_conversation_set_data(conv, "line-attachments", nullptr);
        delete atts;
    }
}
Example #11
0
static void twitter_conv_icon_remove_conversation_conv_icons(PurpleConversation * conv)
{
    GList         **conv_icons;
    GList          *l;
    g_return_if_fail(conv != NULL);
    purple_debug_info(PLUGIN_ID, "%s conv %s\n", G_STRFUNC, purple_conversation_get_name(conv));

    conv_icons = purple_conversation_get_data(conv, PLUGIN_ID "-conv-icons");

    if (conv_icons) {
        for (l = *conv_icons; l; l = l->next) {
            TwitterConvIcon *conv_icon = l->data;
            twitter_conv_icon_remove_conv(conv_icon, conv);
        }
        g_list_free(*conv_icons);
        *conv_icons = NULL;
    }
}
Example #12
0
static void
apply_method()
{
	GList *convs;
	PidginWindow *purplewin = NULL;

	for (convs = purple_get_conversations(); convs != NULL;
	     convs = convs->next) {
		PurpleConversation *conv = (PurpleConversation *)convs->data;

		/* remove notifications */
		unnotify(conv, FALSE);

		purplewin = PIDGIN_CONVERSATION(conv)->win;
		if (GPOINTER_TO_INT(purple_conversation_get_data(conv, "notify-message-count")) != 0)
			/* reattach appropriate notifications */
			notify(conv, FALSE);
	}
}
Example #13
0
static gboolean
timestamp_displaying_conv_msg(PurpleAccount *account, const char *who,
			      char **buffer, PurpleConversation *conv,
			      PurpleMessageFlags flags, void *data)
{
	time_t now = time(NULL) / interval * interval;
	time_t then;

	if (!g_list_find(purple_get_conversations(), conv))
		return FALSE;

	then = GPOINTER_TO_INT(purple_conversation_get_data(
		conv, "timestamp-last"));

	if (now - then >= interval) {
		timestamp_display(conv, then, now);
		purple_conversation_set_data(
			conv, "timestamp-last", GINT_TO_POINTER(now));
	}

	return FALSE;
}
Example #14
0
static int
notify(PurpleConversation *conv, gboolean increment)
{
	gint count;
	gboolean has_focus;
	PidginWindow *purplewin = NULL;

	if (conv == NULL || PIDGIN_CONVERSATION(conv) == NULL)
		return 0;

	/* We want to remove the notifications, but not reset the counter */
	unnotify(conv, FALSE);

	purplewin = PIDGIN_CONVERSATION(conv)->win;

	/* If we aren't doing notifications for this type of conversation, return */
	if (((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) &&
	     !purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im")) ||
	    ((purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) &&
	     !purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat")))
		return 0;

	g_object_get(G_OBJECT(purplewin->window),
	             "has-toplevel-focus", &has_focus, NULL);

	if (purple_prefs_get_bool("/plugins/gtk/X11/notify/type_focused") ||
	    !has_focus) {
		if (increment) {
			count = GPOINTER_TO_INT(purple_conversation_get_data(conv, "notify-message-count"));
			count++;
			purple_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(count));
		}

		notify_win(purplewin, conv);
	}

	return 0;
}
int purple_conversation_get_unseen(PurpleConversation *conv)
{
	return GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"));
}
Example #16
0
void PurpleLine::fetch_conversation_history(PurpleConversation *conv, int count, bool requested) {
    PurpleConversationType type = conv->type;
    std::string name(purple_conversation_get_name(conv));

    int64_t end_seq = -1;

    int64_t *end_seq_p = (int64_t *)purple_conversation_get_data(conv, "line-end-seq");
    if (end_seq_p)
        end_seq = *end_seq_p;

    if (end_seq != -1)
        c_out->send_getPreviousMessages(name, end_seq - 1, count);
    else
        c_out->send_getRecentMessages(name, count);

    c_out->send([this, requested, type, name, end_seq]() {
        int64_t new_end_seq = end_seq;

        std::vector<line::Message> recent_msgs;

        if (end_seq != -1)
            c_out->recv_getPreviousMessages(recent_msgs);
        else
            c_out->recv_getRecentMessages(recent_msgs);

        PurpleConversation *conv = purple_find_conversation_with_account(type, name.c_str(), acct);
        if (!conv)
            return; // Conversation died while fetching messages

        auto *queue = (std::vector<line::Message> *)
            purple_conversation_get_data(conv, "line-message-queue");

        purple_conversation_set_data(conv, "line-message-queue", nullptr);

        // Find least seq value from messages for future history queries
        for (line::Message &msg: recent_msgs) {
            if (msg.contentMetadata.count("seq")) {
                try {
                    int64_t seq = std::stoll(msg.contentMetadata["seq"]);

                    if (new_end_seq == -1 || seq < new_end_seq)
                        new_end_seq = seq;
                } catch (...) { /* ignore parse error */ }
            }
        }

        if (queue) {
            // If there's a message queue, remove any already-queued messages in the recent message
            // list to prevent them showing up twice.

            recent_msgs.erase(
                std::remove_if(
                    recent_msgs.begin(),
                    recent_msgs.end(),
                    [&queue](line::Message &rm) {
                        auto r = find_if(
                            queue->begin(),
                            queue->end(),
                            [&rm](line::Message &qm) { return qm.id == rm.id; });

                        return (r != queue->end());
                    }),
                recent_msgs.end());
        }

        if (recent_msgs.size()) {
            purple_conversation_write(
                conv,
                "",
                "<strong>Message history</strong>",
                (PurpleMessageFlags)PURPLE_MESSAGE_RAW,
                time(NULL));

            for (auto msgi = recent_msgs.rbegin(); msgi != recent_msgs.rend(); msgi++)
                write_message(*msgi, true);

            purple_conversation_write(
                conv,
                "",
                "<hr>",
                (PurpleMessageFlags)PURPLE_MESSAGE_RAW,
                time(NULL));
        } else {
            if (requested) {
                // If history was requested by the user and there is none, let the user know

                purple_conversation_write(
                    conv,
                    "",
                    "<strong>No more history</strong>",
                    (PurpleMessageFlags)PURPLE_MESSAGE_RAW,
                    time(NULL));
            }
        }

        // If there's a message queue, play it back now
        if (queue) {
            for (line::Message &msg: *queue)
                write_message(msg, false);

            delete queue;
        }

        int64_t *end_seq_p = (int64_t *)purple_conversation_get_data(conv, "line-end-seq");
        if (end_seq_p)
            delete end_seq_p;

        purple_conversation_set_data(conv, "line-end-seq", new int64_t(new_end_seq));
    });
}
Example #17
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);
            }
        }
    }
}
Example #18
0
void irc_msg_names(struct irc_conn *irc, const char *name, const char *from, char **args)
{
	char *names, *cur, *end, *tmp, *msg;
	PurpleConversation *convo;

	if (!strcmp(name, "366")) {
		convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[1], irc->account);
		if (!convo) {
			purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got a NAMES list for %s, which doesn't exist\n", args[1]);
			g_string_free(irc->names, TRUE);
			irc->names = NULL;
			return;
		}

		names = cur = g_string_free(irc->names, FALSE);
		irc->names = NULL;
		if (purple_conversation_get_data(convo, IRC_NAMES_FLAG)) {
			msg = g_strdup_printf(_("Users on %s: %s"), args[1], names ? names : "");
			if (purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
				purple_conv_chat_write(PURPLE_CONV_CHAT(convo), "", msg, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG, time(NULL));
			else
				purple_conv_im_write(PURPLE_CONV_IM(convo), "", msg, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NO_LOG, time(NULL));
			g_free(msg);
		} else {
			GList *users = NULL;
			GList *flags = NULL;

			while (*cur) {
				PurpleConvChatBuddyFlags f = PURPLE_CBFLAGS_NONE;
				end = strchr(cur, ' ');
				if (!end)
					end = cur + strlen(cur);
				if (*cur == '@') {
					f = PURPLE_CBFLAGS_OP;
					cur++;
				} else if (*cur == '%') {
					f = PURPLE_CBFLAGS_HALFOP;
					cur++;
				} else if(*cur == '+') {
					f = PURPLE_CBFLAGS_VOICE;
					cur++;
				} else if(irc->mode_chars
					  && strchr(irc->mode_chars, *cur)) {
					if (*cur == '~')
						f = PURPLE_CBFLAGS_FOUNDER;
					cur++;
				}
				tmp = g_strndup(cur, end - cur);
				users = g_list_prepend(users, tmp);
				flags = g_list_prepend(flags, GINT_TO_POINTER(f));
				cur = end;
				if (*cur)
					cur++;
			}

			if (users != NULL) {
				GList *l;

				purple_conv_chat_add_users(PURPLE_CONV_CHAT(convo), users, NULL, flags, FALSE);

				for (l = users; l != NULL; l = l->next)
					g_free(l->data);

				g_list_free(users);
				g_list_free(flags);
			}

			purple_conversation_set_data(convo, IRC_NAMES_FLAG,
						   GINT_TO_POINTER(TRUE));
		}
		g_free(names);
	} else {
		if (!irc->names)
			irc->names = g_string_new("");

		if (irc->names->len && irc->names->str[irc->names->len - 1] != ' ')
			irc->names = g_string_append_c(irc->names, ' ');
		irc->names = g_string_append(irc->names, args[3]);
	}
}