pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Merged in default (pull request #649)
2019-11-19, Gary Kramlich
2bfdd6552f14
Merged in default (pull request #649)
Clean up PidginMenuTray
Approved-by: Elliott Sales de Andrade
Approved-by: John Bailey
/*
* 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
"internal.h"
#include
"gtkplugin.h"
#include
"version.h"
#include
"protocol.h"
#include
"xmlnode.h"
#include
"gtkutils.h"
#include
<gdk/gdkkeysyms.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
(
protocol
)
purple_protocol_server_iface_send_raw
(
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
,
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
PidginPluginInfo
*
plugin_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
plugin_load
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
int
i
;
gboolean
any_registered
=
FALSE
;
xmpp_console_handle
=
plugin
;
i
=
0
;
while
(
xmpp_prpls
[
i
]
!=
NULL
)
{
PurpleProtocol
*
xmpp
;
xmpp
=
purple_protocols_find
(
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
plugin_unload
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
if
(
console
)
gtk_widget_destroy
(
console
->
window
);
return
TRUE
;
}
PURPLE_PLUGIN_INIT
(
xmppconsole
,
plugin_query
,
plugin_load
,
plugin_unload
);