pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Use Meson summary() function.
2021-07-27, Elliott Sales de Andrade
cb640ea0f315
Use Meson summary() function.
Now that we require at least 0.52, we can use Meson's builtin summary printing to display the results of configuration.
Testing Done:
Configured with defaults, and with pixmaps disabled to trigger the warning: https://asciinema.org/a/mV2oxOoVCJNdmrPwgqqUJ3mkU?t=17
Reviewed at https://reviews.imfreedom.org/r/848/
/*
* Purple - XMPP debugging tool
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*
*/
#include
<glib/gi18n-lib.h>
#include
<gdk/gdkkeysyms.h>
#include
<purple.h>
#include
<pidgin.h>
#define PLUGIN_ID "gtk-xmpp"
#define PLUGIN_DOMAIN (g_quark_from_static_string(PLUGIN_ID))
typedef
struct
{
PurpleConnection
*
gc
;
GtkWidget
*
window
;
GtkWidget
*
hbox
;
GtkWidget
*
dropdown
;
GtkTextBuffer
*
buffer
;
struct
{
GtkTextTag
*
info
;
GtkTextTag
*
incoming
;
GtkTextTag
*
outgoing
;
GtkTextTag
*
bracket
;
GtkTextTag
*
tag
;
GtkTextTag
*
attr
;
GtkTextTag
*
value
;
GtkTextTag
*
xmlns
;
}
tags
;
GtkWidget
*
entry
;
GtkTextBuffer
*
entry_buffer
;
GtkWidget
*
sw
;
int
count
;
GList
*
accounts
;
struct
{
GtkPopover
*
popover
;
GtkEntry
*
to
;
GtkComboBoxText
*
type
;
}
iq
;
struct
{
GtkPopover
*
popover
;
GtkEntry
*
to
;
GtkComboBoxText
*
type
;
GtkComboBoxText
*
show
;
GtkEntry
*
status
;
GtkEntry
*
priority
;
}
presence
;
struct
{
GtkPopover
*
popover
;
GtkEntry
*
to
;
GtkComboBoxText
*
type
;
GtkEntry
*
body
;
GtkEntry
*
subject
;
GtkEntry
*
thread
;
}
message
;
}
XmppConsole
;
XmppConsole
*
console
=
NULL
;
static
void
*
xmpp_console_handle
=
NULL
;
static
const
gchar
*
xmpp_prpls
[]
=
{
"prpl-jabber"
,
"prpl-gtalk"
,
NULL
};
static
gboolean
xmppconsole_is_xmpp_account
(
PurpleAccount
*
account
)
{
const
gchar
*
prpl_name
;
int
i
;
prpl_name
=
purple_account_get_protocol_id
(
account
);
i
=
0
;
while
(
xmpp_prpls
[
i
]
!=
NULL
)
{
if
(
purple_strequal
(
xmpp_prpls
[
i
],
prpl_name
))
return
TRUE
;
i
++
;
}
return
FALSE
;
}
static
void
purple_xmlnode_append_to_buffer
(
PurpleXmlNode
*
node
,
gint
indent_level
,
GtkTextIter
*
iter
,
GtkTextTag
*
tag
)
{
PurpleXmlNode
*
c
;
gboolean
need_end
=
FALSE
,
pretty
=
TRUE
;
gint
i
;
g_return_if_fail
(
node
!=
NULL
);
for
(
i
=
0
;
i
<
indent_level
;
i
++
)
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"
\t
"
,
1
,
tag
,
NULL
);
}
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"<"
,
1
,
tag
,
console
->
tags
.
bracket
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
node
->
name
,
-1
,
tag
,
console
->
tags
.
tag
,
NULL
);
if
(
node
->
xmlns
)
{
if
((
!
node
->
parent
||
!
node
->
parent
->
xmlns
||
!
purple_strequal
(
node
->
xmlns
,
node
->
parent
->
xmlns
))
&&
!
purple_strequal
(
node
->
xmlns
,
"jabber:client"
))
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
" "
,
1
,
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"xmlns"
,
5
,
tag
,
console
->
tags
.
attr
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"='"
,
2
,
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
node
->
xmlns
,
-1
,
tag
,
console
->
tags
.
xmlns
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"'"
,
1
,
tag
,
NULL
);
}
}
for
(
c
=
node
->
child
;
c
;
c
=
c
->
next
)
{
if
(
c
->
type
==
PURPLE_XMLNODE_TYPE_ATTRIB
)
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
" "
,
1
,
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
c
->
name
,
-1
,
tag
,
console
->
tags
.
attr
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"='"
,
2
,
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
c
->
data
,
-1
,
tag
,
console
->
tags
.
value
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"'"
,
1
,
tag
,
NULL
);
}
else
if
(
c
->
type
==
PURPLE_XMLNODE_TYPE_TAG
||
c
->
type
==
PURPLE_XMLNODE_TYPE_DATA
)
{
if
(
c
->
type
==
PURPLE_XMLNODE_TYPE_DATA
)
pretty
=
FALSE
;
need_end
=
TRUE
;
}
}
if
(
need_end
)
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
">"
,
1
,
tag
,
console
->
tags
.
bracket
,
NULL
);
if
(
pretty
)
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"
\n
"
,
1
,
tag
,
NULL
);
}
for
(
c
=
node
->
child
;
c
;
c
=
c
->
next
)
{
if
(
c
->
type
==
PURPLE_XMLNODE_TYPE_TAG
)
{
purple_xmlnode_append_to_buffer
(
c
,
indent_level
+
1
,
iter
,
tag
);
}
else
if
(
c
->
type
==
PURPLE_XMLNODE_TYPE_DATA
&&
c
->
data_sz
>
0
)
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
c
->
data
,
c
->
data_sz
,
tag
,
NULL
);
}
}
if
(
pretty
)
{
for
(
i
=
0
;
i
<
indent_level
;
i
++
)
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"
\t
"
,
1
,
tag
,
NULL
);
}
}
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"<"
,
1
,
tag
,
console
->
tags
.
bracket
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"/"
,
1
,
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
node
->
name
,
-1
,
tag
,
console
->
tags
.
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
">"
,
1
,
tag
,
console
->
tags
.
bracket
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"
\n
"
,
1
,
tag
,
NULL
);
}
else
{
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"/"
,
1
,
tag
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
">"
,
1
,
tag
,
console
->
tags
.
bracket
,
NULL
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
iter
,
"
\n
"
,
1
,
tag
,
NULL
);
}
}
static
void
purple_xmlnode_received_cb
(
PurpleConnection
*
gc
,
PurpleXmlNode
**
packet
,
gpointer
null
)
{
GtkTextIter
iter
;
if
(
!
console
||
console
->
gc
!=
gc
)
return
;
gtk_text_buffer_get_end_iter
(
console
->
buffer
,
&
iter
);
purple_xmlnode_append_to_buffer
(
*
packet
,
0
,
&
iter
,
console
->
tags
.
incoming
);
}
static
void
purple_xmlnode_sent_cb
(
PurpleConnection
*
gc
,
char
**
packet
,
gpointer
null
)
{
GtkTextIter
iter
;
PurpleXmlNode
*
node
;
if
(
!
console
||
console
->
gc
!=
gc
)
return
;
node
=
purple_xmlnode_from_str
(
*
packet
,
-1
);
if
(
!
node
)
return
;
gtk_text_buffer_get_end_iter
(
console
->
buffer
,
&
iter
);
purple_xmlnode_append_to_buffer
(
node
,
0
,
&
iter
,
console
->
tags
.
outgoing
);
purple_xmlnode_free
(
node
);
}
static
gboolean
message_send_cb
(
GtkWidget
*
widget
,
GdkEventKey
*
event
,
gpointer
p
)
{
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
;
gchar
*
text
;
GtkTextIter
start
,
end
;
if
(
event
->
keyval
!=
GDK_KEY_KP_Enter
&&
event
->
keyval
!=
GDK_KEY_Return
)
return
FALSE
;
gc
=
console
->
gc
;
if
(
gc
)
protocol
=
purple_connection_get_protocol
(
gc
);
gtk_text_buffer_get_bounds
(
console
->
entry_buffer
,
&
start
,
&
end
);
text
=
gtk_text_buffer_get_text
(
console
->
entry_buffer
,
&
start
,
&
end
,
FALSE
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
purple_protocol_server_send_raw
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
text
,
strlen
(
text
));
}
g_free
(
text
);
gtk_text_buffer_set_text
(
console
->
entry_buffer
,
""
,
0
);
return
TRUE
;
}
static
void
entry_changed_cb
(
GtkTextBuffer
*
buffer
,
void
*
data
)
{
GtkTextIter
start
,
end
;
char
*
xmlstr
,
*
str
;
GtkTextIter
iter
;
int
wrapped_lines
;
int
lines
;
GdkRectangle
oneline
;
int
height
;
int
pad_top
,
pad_inside
,
pad_bottom
;
PurpleXmlNode
*
node
;
GtkStyleContext
*
style
;
wrapped_lines
=
1
;
gtk_text_buffer_get_start_iter
(
buffer
,
&
iter
);
gtk_text_view_get_iter_location
(
GTK_TEXT_VIEW
(
console
->
entry
),
&
iter
,
&
oneline
);
while
(
gtk_text_view_forward_display_line
(
GTK_TEXT_VIEW
(
console
->
entry
),
&
iter
))
{
wrapped_lines
++
;
}
lines
=
gtk_text_buffer_get_line_count
(
buffer
);
/* Show a maximum of 64 lines */
lines
=
MIN
(
lines
,
6
);
wrapped_lines
=
MIN
(
wrapped_lines
,
6
);
pad_top
=
gtk_text_view_get_pixels_above_lines
(
GTK_TEXT_VIEW
(
console
->
entry
));
pad_bottom
=
gtk_text_view_get_pixels_below_lines
(
GTK_TEXT_VIEW
(
console
->
entry
));
pad_inside
=
gtk_text_view_get_pixels_inside_wrap
(
GTK_TEXT_VIEW
(
console
->
entry
));
height
=
(
oneline
.
height
+
pad_top
+
pad_bottom
)
*
lines
;
height
+=
(
oneline
.
height
+
pad_inside
)
*
(
wrapped_lines
-
lines
);
gtk_widget_set_size_request
(
console
->
sw
,
-1
,
height
+
6
);
gtk_text_buffer_get_bounds
(
buffer
,
&
start
,
&
end
);
str
=
gtk_text_buffer_get_text
(
buffer
,
&
start
,
&
end
,
FALSE
);
if
(
!
str
)
{
return
;
}
xmlstr
=
g_strdup_printf
(
"<xml>%s</xml>"
,
str
);
node
=
purple_xmlnode_from_str
(
xmlstr
,
-1
);
style
=
gtk_widget_get_style_context
(
console
->
entry
);
if
(
node
)
{
gtk_style_context_remove_class
(
style
,
GTK_STYLE_CLASS_ERROR
);
}
else
{
gtk_style_context_add_class
(
style
,
GTK_STYLE_CLASS_ERROR
);
}
g_free
(
str
);
g_free
(
xmlstr
);
if
(
node
)
purple_xmlnode_free
(
node
);
}
static
void
load_text_and_set_caret
(
const
gchar
*
pre_text
,
const
gchar
*
post_text
)
{
GtkTextIter
where
;
GtkTextMark
*
mark
;
gtk_text_buffer_begin_user_action
(
console
->
entry_buffer
);
gtk_text_buffer_set_text
(
console
->
entry_buffer
,
pre_text
,
-1
);
gtk_text_buffer_get_end_iter
(
console
->
entry_buffer
,
&
where
);
mark
=
gtk_text_buffer_create_mark
(
console
->
entry_buffer
,
NULL
,
&
where
,
TRUE
);
gtk_text_buffer_insert
(
console
->
entry_buffer
,
&
where
,
post_text
,
-1
);
gtk_text_buffer_get_iter_at_mark
(
console
->
entry_buffer
,
&
where
,
mark
);
gtk_text_buffer_place_cursor
(
console
->
entry_buffer
,
&
where
);
gtk_text_buffer_delete_mark
(
console
->
entry_buffer
,
mark
);
gtk_text_buffer_end_user_action
(
console
->
entry_buffer
);
}
static
void
popover_closed_cb
(
GtkPopover
*
popover
,
gpointer
data
)
{
GtkToggleToolButton
*
button
=
GTK_TOGGLE_TOOL_BUTTON
(
data
);
gtk_toggle_tool_button_set_active
(
button
,
FALSE
);
}
static
void
toggle_button_toggled_cb
(
GtkToolButton
*
button
,
gpointer
data
)
{
GtkPopover
*
popover
=
GTK_POPOVER
(
data
);
gtk_popover_popup
(
popover
);
}
static
void
iq_clicked_cb
(
GtkWidget
*
w
,
gpointer
data
)
{
XmppConsole
*
console
=
(
XmppConsole
*
)
data
;
const
gchar
*
to
;
char
*
stanza
;
to
=
gtk_entry_get_text
(
console
->
iq
.
to
);
stanza
=
g_strdup_printf
(
"<iq %s%s%s id='console%x' type='%s'>"
,
to
&&
*
to
?
"to='"
:
""
,
to
&&
*
to
?
to
:
""
,
to
&&
*
to
?
"'"
:
""
,
g_random_int
(),
gtk_combo_box_text_get_active_text
(
console
->
iq
.
type
));
load_text_and_set_caret
(
stanza
,
"</iq>"
);
gtk_widget_grab_focus
(
console
->
entry
);
g_free
(
stanza
);
/* Reset everything. */
gtk_entry_set_text
(
console
->
iq
.
to
,
""
);
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
console
->
iq
.
type
),
0
);
gtk_popover_popdown
(
console
->
iq
.
popover
);
}
static
void
presence_clicked_cb
(
GtkWidget
*
w
,
gpointer
data
)
{
XmppConsole
*
console
=
(
XmppConsole
*
)
data
;
const
gchar
*
to
,
*
status
,
*
priority
;
gchar
*
type
,
*
show
;
char
*
stanza
;
to
=
gtk_entry_get_text
(
console
->
presence
.
to
);
type
=
gtk_combo_box_text_get_active_text
(
console
->
presence
.
type
);
if
(
purple_strequal
(
type
,
"default"
))
{
g_free
(
type
);
type
=
g_strdup
(
""
);
}
show
=
gtk_combo_box_text_get_active_text
(
console
->
presence
.
show
);
if
(
purple_strequal
(
show
,
"default"
))
{
g_free
(
show
);
show
=
g_strdup
(
""
);
}
status
=
gtk_entry_get_text
(
console
->
presence
.
status
);
priority
=
gtk_entry_get_text
(
console
->
presence
.
priority
);
if
(
purple_strequal
(
priority
,
"0"
))
priority
=
""
;
stanza
=
g_strdup_printf
(
"<presence %s%s%s id='console%x' %s%s%s>"
"%s%s%s%s%s%s%s%s%s"
,
*
to
?
"to='"
:
""
,
*
to
?
to
:
""
,
*
to
?
"'"
:
""
,
g_random_int
(),
*
type
?
"type='"
:
""
,
*
type
?
type
:
""
,
*
type
?
"'"
:
""
,
*
show
?
"<show>"
:
""
,
*
show
?
show
:
""
,
*
show
?
"</show>"
:
""
,
*
status
?
"<status>"
:
""
,
*
status
?
status
:
""
,
*
status
?
"</status>"
:
""
,
*
priority
?
"<priority>"
:
""
,
*
priority
?
priority
:
""
,
*
priority
?
"</priority>"
:
""
);
load_text_and_set_caret
(
stanza
,
"</presence>"
);
gtk_widget_grab_focus
(
console
->
entry
);
g_free
(
stanza
);
g_free
(
type
);
g_free
(
show
);
/* Reset everything. */
gtk_entry_set_text
(
console
->
presence
.
to
,
""
);
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
console
->
presence
.
type
),
0
);
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
console
->
presence
.
show
),
0
);
gtk_entry_set_text
(
console
->
presence
.
status
,
""
);
gtk_entry_set_text
(
console
->
presence
.
priority
,
"0"
);
gtk_popover_popdown
(
console
->
presence
.
popover
);
}
static
void
message_clicked_cb
(
GtkWidget
*
w
,
gpointer
data
)
{
XmppConsole
*
console
=
(
XmppConsole
*
)
data
;
const
gchar
*
to
,
*
body
,
*
thread
,
*
subject
;
char
*
stanza
;
to
=
gtk_entry_get_text
(
console
->
message
.
to
);
body
=
gtk_entry_get_text
(
console
->
message
.
body
);
thread
=
gtk_entry_get_text
(
console
->
message
.
thread
);
subject
=
gtk_entry_get_text
(
console
->
message
.
subject
);
stanza
=
g_strdup_printf
(
"<message %s%s%s id='console%x' type='%s'>"
"%s%s%s%s%s%s%s%s%s"
,
*
to
?
"to='"
:
""
,
*
to
?
to
:
""
,
*
to
?
"'"
:
""
,
g_random_int
(),
gtk_combo_box_text_get_active_text
(
console
->
message
.
type
),
*
body
?
"<body>"
:
""
,
*
body
?
body
:
""
,
*
body
?
"</body>"
:
""
,
*
subject
?
"<subject>"
:
""
,
*
subject
?
subject
:
""
,
*
subject
?
"</subject>"
:
""
,
*
thread
?
"<thread>"
:
""
,
*
thread
?
thread
:
""
,
*
thread
?
"</thread>"
:
""
);
load_text_and_set_caret
(
stanza
,
"</message>"
);
gtk_widget_grab_focus
(
console
->
entry
);
g_free
(
stanza
);
/* Reset everything. */
gtk_entry_set_text
(
console
->
message
.
to
,
""
);
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
console
->
message
.
type
),
0
);
gtk_entry_set_text
(
console
->
message
.
body
,
""
);
gtk_entry_set_text
(
console
->
message
.
subject
,
"0"
);
gtk_entry_set_text
(
console
->
message
.
thread
,
"0"
);
gtk_popover_popdown
(
console
->
message
.
popover
);
}
static
void
signing_on_cb
(
PurpleConnection
*
gc
)
{
PurpleAccount
*
account
;
if
(
!
console
)
return
;
account
=
purple_connection_get_account
(
gc
);
if
(
!
xmppconsole_is_xmpp_account
(
account
))
return
;
gtk_combo_box_text_append_text
(
GTK_COMBO_BOX_TEXT
(
console
->
dropdown
),
purple_account_get_username
(
account
));
console
->
accounts
=
g_list_append
(
console
->
accounts
,
gc
);
console
->
count
++
;
if
(
console
->
count
==
1
)
{
console
->
gc
=
gc
;
gtk_text_buffer_set_text
(
console
->
buffer
,
""
,
0
);
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
console
->
dropdown
),
0
);
}
else
gtk_widget_show_all
(
console
->
hbox
);
}
static
void
signed_off_cb
(
PurpleConnection
*
gc
)
{
int
i
;
if
(
!
console
)
return
;
i
=
g_list_index
(
console
->
accounts
,
gc
);
if
(
i
==
-1
)
return
;
gtk_combo_box_text_remove
(
GTK_COMBO_BOX_TEXT
(
console
->
dropdown
),
i
);
console
->
accounts
=
g_list_remove
(
console
->
accounts
,
gc
);
console
->
count
--
;
if
(
gc
==
console
->
gc
)
{
GtkTextIter
end
;
gtk_text_buffer_get_end_iter
(
console
->
buffer
,
&
end
);
gtk_text_buffer_insert_with_tags
(
console
->
buffer
,
&
end
,
_
(
"Logged out."
),
-1
,
console
->
tags
.
info
,
NULL
);
console
->
gc
=
NULL
;
}
}
static
void
console_destroy
(
GtkWidget
*
window
,
gpointer
nul
)
{
g_list_free
(
console
->
accounts
);
g_free
(
console
);
console
=
NULL
;
}
static
void
dropdown_changed_cb
(
GtkComboBox
*
widget
,
gpointer
nul
)
{
if
(
!
console
)
return
;
console
->
gc
=
g_list_nth_data
(
console
->
accounts
,
gtk_combo_box_get_active
(
GTK_COMBO_BOX
(
console
->
dropdown
)));
gtk_text_buffer_set_text
(
console
->
buffer
,
""
,
0
);
}
static
void
create_console
(
PurplePluginAction
*
action
)
{
GtkBuilder
*
builder
;
GList
*
connections
;
GtkCssProvider
*
entry_css
;
GtkStyleContext
*
context
;
if
(
console
)
{
gtk_window_present
(
GTK_WINDOW
(
console
->
window
));
return
;
}
console
=
g_new0
(
XmppConsole
,
1
);
builder
=
gtk_builder_new_from_resource
(
"/im/pidgin/Pidgin/Plugin/XMPPConsole/console.ui"
);
gtk_builder_set_translation_domain
(
builder
,
GETTEXT_PACKAGE
);
console
->
window
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"PidginXmppConsole"
));
gtk_builder_add_callback_symbol
(
builder
,
"console_destroy"
,
G_CALLBACK
(
console_destroy
));
console
->
hbox
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"hbox"
));
console
->
dropdown
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"dropdown"
));
for
(
connections
=
purple_connections_get_all
();
connections
;
connections
=
connections
->
next
)
{
PurpleConnection
*
gc
=
connections
->
data
;
if
(
xmppconsole_is_xmpp_account
(
purple_connection_get_account
(
gc
)))
{
console
->
count
++
;
console
->
accounts
=
g_list_append
(
console
->
accounts
,
gc
);
gtk_combo_box_text_append_text
(
GTK_COMBO_BOX_TEXT
(
console
->
dropdown
),
purple_account_get_username
(
purple_connection_get_account
(
gc
)));
if
(
!
console
->
gc
)
console
->
gc
=
gc
;
}
}
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
console
->
dropdown
),
0
);
gtk_builder_add_callback_symbol
(
builder
,
"dropdown_changed_cb"
,
G_CALLBACK
(
dropdown_changed_cb
));
console
->
buffer
=
GTK_TEXT_BUFFER
(
gtk_builder_get_object
(
builder
,
"buffer"
));
console
->
tags
.
info
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.info"
));
console
->
tags
.
incoming
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.incoming"
));
console
->
tags
.
outgoing
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.outgoing"
));
console
->
tags
.
bracket
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.bracket"
));
console
->
tags
.
tag
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.tag"
));
console
->
tags
.
attr
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.attr"
));
console
->
tags
.
value
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.value"
));
console
->
tags
.
xmlns
=
GTK_TEXT_TAG
(
gtk_builder_get_object
(
builder
,
"tags.xmlns"
));
if
(
console
->
count
==
0
)
{
GtkTextIter
start
,
end
;
gtk_text_buffer_set_text
(
console
->
buffer
,
_
(
"Not connected to XMPP"
),
-1
);
gtk_text_buffer_get_bounds
(
console
->
buffer
,
&
start
,
&
end
);
gtk_text_buffer_apply_tag
(
console
->
buffer
,
console
->
tags
.
info
,
&
start
,
&
end
);
}
/* Popover for <iq/> button. */
console
->
iq
.
popover
=
GTK_POPOVER
(
gtk_builder_get_object
(
builder
,
"iq.popover"
));
console
->
iq
.
to
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"iq.to"
));
console
->
iq
.
type
=
GTK_COMBO_BOX_TEXT
(
gtk_builder_get_object
(
builder
,
"iq.type"
));
/* Popover for <presence/> button. */
console
->
presence
.
popover
=
GTK_POPOVER
(
gtk_builder_get_object
(
builder
,
"presence.popover"
));
console
->
presence
.
to
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"presence.to"
));
console
->
presence
.
type
=
GTK_COMBO_BOX_TEXT
(
gtk_builder_get_object
(
builder
,
"presence.type"
));
console
->
presence
.
show
=
GTK_COMBO_BOX_TEXT
(
gtk_builder_get_object
(
builder
,
"presence.show"
));
console
->
presence
.
status
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"presence.status"
));
console
->
presence
.
priority
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"presence.priority"
));
/* Popover for <message/> button. */
console
->
message
.
popover
=
GTK_POPOVER
(
gtk_builder_get_object
(
builder
,
"message.popover"
));
console
->
message
.
to
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"message.to"
));
console
->
message
.
type
=
GTK_COMBO_BOX_TEXT
(
gtk_builder_get_object
(
builder
,
"message.type"
));
console
->
message
.
body
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"message.body"
));
console
->
message
.
subject
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"message.subject"
));
console
->
message
.
thread
=
GTK_ENTRY
(
gtk_builder_get_object
(
builder
,
"message.thread"
));
gtk_builder_add_callback_symbols
(
builder
,
"toggle_button_toggled_cb"
,
G_CALLBACK
(
toggle_button_toggled_cb
),
"popover_closed_cb"
,
G_CALLBACK
(
popover_closed_cb
),
"iq_clicked_cb"
,
G_CALLBACK
(
iq_clicked_cb
),
"presence_clicked_cb"
,
G_CALLBACK
(
presence_clicked_cb
),
"message_clicked_cb"
,
G_CALLBACK
(
message_clicked_cb
),
NULL
);
console
->
entry
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"entry"
));
entry_css
=
gtk_css_provider_new
();
gtk_css_provider_load_from_data
(
entry_css
,
"textview."
GTK_STYLE_CLASS_ERROR
" text {background-color:#ffcece;}"
,
-1
,
NULL
);
context
=
gtk_widget_get_style_context
(
console
->
entry
);
gtk_style_context_add_provider
(
context
,
GTK_STYLE_PROVIDER
(
entry_css
),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
console
->
entry_buffer
=
GTK_TEXT_BUFFER
(
gtk_builder_get_object
(
builder
,
"entry_buffer"
));
gtk_builder_add_callback_symbol
(
builder
,
"message_send_cb"
,
G_CALLBACK
(
message_send_cb
));
console
->
sw
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"sw"
));
gtk_builder_add_callback_symbol
(
builder
,
"entry_changed_cb"
,
G_CALLBACK
(
entry_changed_cb
));
entry_changed_cb
(
console
->
entry_buffer
,
NULL
);
gtk_widget_show_all
(
console
->
window
);
if
(
console
->
count
<
2
)
gtk_widget_hide
(
console
->
hbox
);
gtk_builder_connect_signals
(
builder
,
console
);
g_object_unref
(
builder
);
}
static
GList
*
actions
(
PurplePlugin
*
plugin
)
{
GList
*
l
=
NULL
;
PurplePluginAction
*
act
=
NULL
;
act
=
purple_plugin_action_new
(
_
(
"XMPP Console"
),
create_console
);
l
=
g_list_append
(
l
,
act
);
return
l
;
}
static
GPluginPluginInfo
*
xmpp_console_query
(
GError
**
error
)
{
const
gchar
*
const
authors
[]
=
{
"Sean Egan <seanegan@gmail.com>"
,
NULL
};
return
pidgin_plugin_info_new
(
"id"
,
PLUGIN_ID
,
"name"
,
N_
(
"XMPP Console"
),
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Protocol utility"
),
"summary"
,
N_
(
"Send and receive raw XMPP stanzas."
),
"description"
,
N_
(
"This plugin is useful for debugging XMPP servers "
"or clients."
),
"authors"
,
authors
,
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"actions-cb"
,
actions
,
NULL
);
}
static
gboolean
xmpp_console_load
(
GPluginPlugin
*
plugin
,
GError
**
error
)
{
int
i
;
gboolean
any_registered
=
FALSE
;
xmpp_console_handle
=
plugin
;
i
=
0
;
while
(
xmpp_prpls
[
i
]
!=
NULL
)
{
PurpleProtocol
*
xmpp
;
PurpleProtocolManager
*
manager
;
manager
=
purple_protocol_manager_get_default
();
xmpp
=
purple_protocol_manager_find
(
manager
,
xmpp_prpls
[
i
]);
i
++
;
if
(
!
xmpp
)
continue
;
any_registered
=
TRUE
;
purple_signal_connect
(
xmpp
,
"jabber-receiving-xmlnode"
,
xmpp_console_handle
,
PURPLE_CALLBACK
(
purple_xmlnode_received_cb
),
NULL
);
purple_signal_connect
(
xmpp
,
"jabber-sending-text"
,
xmpp_console_handle
,
PURPLE_CALLBACK
(
purple_xmlnode_sent_cb
),
NULL
);
}
if
(
!
any_registered
)
{
g_set_error_literal
(
error
,
PLUGIN_DOMAIN
,
0
,
_
(
"No XMPP protocol is loaded."
));
return
FALSE
;
}
purple_signal_connect
(
purple_connections_get_handle
(),
"signing-on"
,
plugin
,
PURPLE_CALLBACK
(
signing_on_cb
),
NULL
);
purple_signal_connect
(
purple_connections_get_handle
(),
"signed-off"
,
plugin
,
PURPLE_CALLBACK
(
signed_off_cb
),
NULL
);
return
TRUE
;
}
static
gboolean
xmpp_console_unload
(
GPluginPlugin
*
plugin
,
GError
**
error
)
{
if
(
console
)
gtk_widget_destroy
(
console
->
window
);
return
TRUE
;
}
GPLUGIN_NATIVE_PLUGIN_DECLARE
(
xmpp_console
)