pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Remove all if 0'd code from gtkconv.c
2021-04-21, Gary Kramlich
1f54363a79f2
Remove all if 0'd code from gtkconv.c
This also help expose the bug that caused the pidgin user's nick to be black
in XMPP MUCs.
Testing Done:
Joined a MUC made sure it worked.
Reviewed at https://reviews.imfreedom.org/r/623/
/* purple
*
* Purple 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
<stdarg.h>
#include
<string.h>
#include
"json.h"
#include
"util.h"
typedef
struct
_FbJsonValue
FbJsonValue
;
struct
_FbJsonValue
{
const
gchar
*
expr
;
FbJsonType
type
;
gboolean
required
;
GValue
value
;
};
typedef
struct
{
JsonNode
*
root
;
GQueue
*
queue
;
GList
*
next
;
gboolean
isarray
;
JsonArray
*
array
;
guint
index
;
GError
*
error
;
}
FbJsonValuesPrivate
;
/**
* FbJsonValues:
*
* Represents a JSON value handler.
*/
struct
_FbJsonValues
{
GObject
parent
;
FbJsonValuesPrivate
*
priv
;
};
G_DEFINE_TYPE_WITH_PRIVATE
(
FbJsonValues
,
fb_json_values
,
G_TYPE_OBJECT
);
static
void
fb_json_values_dispose
(
GObject
*
obj
)
{
FbJsonValue
*
value
;
FbJsonValuesPrivate
*
priv
=
FB_JSON_VALUES
(
obj
)
->
priv
;
while
(
!
g_queue_is_empty
(
priv
->
queue
))
{
value
=
g_queue_pop_head
(
priv
->
queue
);
if
(
G_IS_VALUE
(
&
value
->
value
))
{
g_value_unset
(
&
value
->
value
);
}
g_free
(
value
);
}
if
(
priv
->
array
!=
NULL
)
{
json_array_unref
(
priv
->
array
);
}
if
(
priv
->
error
!=
NULL
)
{
g_error_free
(
priv
->
error
);
}
g_queue_free
(
priv
->
queue
);
}
static
void
fb_json_values_class_init
(
FbJsonValuesClass
*
klass
)
{
GObjectClass
*
gklass
=
G_OBJECT_CLASS
(
klass
);
gklass
->
dispose
=
fb_json_values_dispose
;
}
static
void
fb_json_values_init
(
FbJsonValues
*
values
)
{
FbJsonValuesPrivate
*
priv
=
fb_json_values_get_instance_private
(
values
);
values
->
priv
=
priv
;
priv
->
queue
=
g_queue_new
();
}
GQuark
fb_json_error_quark
(
void
)
{
static
GQuark
q
=
0
;
if
(
G_UNLIKELY
(
q
==
0
))
{
q
=
g_quark_from_static_string
(
"fb-json-error-quark"
);
}
return
q
;
}
JsonBuilder
*
fb_json_bldr_new
(
JsonNodeType
type
)
{
JsonBuilder
*
bldr
;
bldr
=
json_builder_new
();
switch
(
type
)
{
case
JSON_NODE_ARRAY
:
fb_json_bldr_arr_begin
(
bldr
,
NULL
);
break
;
case
JSON_NODE_OBJECT
:
fb_json_bldr_obj_begin
(
bldr
,
NULL
);
break
;
default
:
break
;
}
return
bldr
;
}
gchar
*
fb_json_bldr_close
(
JsonBuilder
*
bldr
,
JsonNodeType
type
,
gsize
*
size
)
{
gchar
*
ret
;
JsonGenerator
*
genr
;
JsonNode
*
root
;
switch
(
type
)
{
case
JSON_NODE_ARRAY
:
fb_json_bldr_arr_end
(
bldr
);
break
;
case
JSON_NODE_OBJECT
:
fb_json_bldr_obj_end
(
bldr
);
break
;
default
:
break
;
}
genr
=
json_generator_new
();
root
=
json_builder_get_root
(
bldr
);
json_generator_set_root
(
genr
,
root
);
ret
=
json_generator_to_data
(
genr
,
size
);
json_node_free
(
root
);
g_object_unref
(
genr
);
g_object_unref
(
bldr
);
return
ret
;
}
void
fb_json_bldr_arr_begin
(
JsonBuilder
*
bldr
,
const
gchar
*
name
)
{
if
(
name
!=
NULL
)
{
json_builder_set_member_name
(
bldr
,
name
);
}
json_builder_begin_array
(
bldr
);
}
void
fb_json_bldr_arr_end
(
JsonBuilder
*
bldr
)
{
json_builder_end_array
(
bldr
);
}
void
fb_json_bldr_obj_begin
(
JsonBuilder
*
bldr
,
const
gchar
*
name
)
{
if
(
name
!=
NULL
)
{
json_builder_set_member_name
(
bldr
,
name
);
}
json_builder_begin_object
(
bldr
);
}
void
fb_json_bldr_obj_end
(
JsonBuilder
*
bldr
)
{
json_builder_end_object
(
bldr
);
}
void
fb_json_bldr_add_bool
(
JsonBuilder
*
bldr
,
const
gchar
*
name
,
gboolean
value
)
{
if
(
name
!=
NULL
)
{
json_builder_set_member_name
(
bldr
,
name
);
}
json_builder_add_boolean_value
(
bldr
,
value
);
}
void
fb_json_bldr_add_dbl
(
JsonBuilder
*
bldr
,
const
gchar
*
name
,
gdouble
value
)
{
if
(
name
!=
NULL
)
{
json_builder_set_member_name
(
bldr
,
name
);
}
json_builder_add_double_value
(
bldr
,
value
);
}
void
fb_json_bldr_add_int
(
JsonBuilder
*
bldr
,
const
gchar
*
name
,
gint64
value
)
{
if
(
name
!=
NULL
)
{
json_builder_set_member_name
(
bldr
,
name
);
}
json_builder_add_int_value
(
bldr
,
value
);
}
void
fb_json_bldr_add_str
(
JsonBuilder
*
bldr
,
const
gchar
*
name
,
const
gchar
*
value
)
{
if
(
name
!=
NULL
)
{
json_builder_set_member_name
(
bldr
,
name
);
}
json_builder_add_string_value
(
bldr
,
value
);
}
void
fb_json_bldr_add_strf
(
JsonBuilder
*
bldr
,
const
gchar
*
name
,
const
gchar
*
format
,
...)
{
gchar
*
value
;
va_list
ap
;
va_start
(
ap
,
format
);
value
=
g_strdup_vprintf
(
format
,
ap
);
va_end
(
ap
);
fb_json_bldr_add_str
(
bldr
,
name
,
value
);
g_free
(
value
);
}
JsonNode
*
fb_json_node_new
(
const
gchar
*
data
,
gssize
size
,
GError
**
error
)
{
gchar
*
slice
;
JsonNode
*
root
;
JsonParser
*
prsr
;
g_return_val_if_fail
(
data
!=
NULL
,
NULL
);
if
(
size
<
0
)
{
size
=
strlen
(
data
);
}
/* Ensure data is null terminated for json-glib < 1.0.2 */
slice
=
g_strndup
(
data
,
size
);
prsr
=
json_parser_new
();
if
(
!
json_parser_load_from_data
(
prsr
,
slice
,
size
,
error
))
{
g_object_unref
(
prsr
);
g_free
(
slice
);
return
NULL
;
}
root
=
json_parser_get_root
(
prsr
);
root
=
json_node_copy
(
root
);
g_object_unref
(
prsr
);
g_free
(
slice
);
return
root
;
}
JsonNode
*
fb_json_node_get
(
JsonNode
*
root
,
const
gchar
*
expr
,
GError
**
error
)
{
GError
*
err
=
NULL
;
guint
size
;
JsonArray
*
rslt
;
JsonNode
*
node
;
JsonNode
*
ret
;
/* Special case for json-glib < 0.99.2 */
if
(
purple_strequal
(
expr
,
"$"
))
{
return
json_node_copy
(
root
);
}
node
=
json_path_query
(
expr
,
root
,
&
err
);
if
(
err
!=
NULL
)
{
g_propagate_error
(
error
,
err
);
json_node_free
(
node
);
return
NULL
;
}
rslt
=
json_node_get_array
(
node
);
size
=
json_array_get_length
(
rslt
);
if
(
size
<
1
)
{
g_set_error
(
error
,
FB_JSON_ERROR
,
FB_JSON_ERROR_NOMATCH
,
_
(
"No matches for %s"
),
expr
);
json_node_free
(
node
);
return
NULL
;
}
if
(
size
>
1
)
{
g_set_error
(
error
,
FB_JSON_ERROR
,
FB_JSON_ERROR_AMBIGUOUS
,
_
(
"Ambiguous matches for %s"
),
expr
);
json_node_free
(
node
);
return
NULL
;
}
if
(
json_array_get_null_element
(
rslt
,
0
))
{
g_set_error
(
error
,
FB_JSON_ERROR
,
FB_JSON_ERROR_NULL
,
_
(
"Null value for %s"
),
expr
);
json_node_free
(
node
);
return
NULL
;
}
ret
=
json_array_dup_element
(
rslt
,
0
);
json_node_free
(
node
);
return
ret
;
}
JsonNode
*
fb_json_node_get_nth
(
JsonNode
*
root
,
guint
n
)
{
GList
*
vals
;
JsonNode
*
ret
;
JsonObject
*
obj
;
obj
=
json_node_get_object
(
root
);
vals
=
json_object_get_values
(
obj
);
ret
=
g_list_nth_data
(
vals
,
n
);
g_list_free
(
vals
);
return
ret
;
}
JsonArray
*
fb_json_node_get_arr
(
JsonNode
*
root
,
const
gchar
*
expr
,
GError
**
error
)
{
JsonArray
*
ret
;
JsonNode
*
rslt
;
rslt
=
fb_json_node_get
(
root
,
expr
,
error
);
if
(
rslt
==
NULL
)
{
return
NULL
;
}
ret
=
json_node_dup_array
(
rslt
);
json_node_free
(
rslt
);
return
ret
;
}
gboolean
fb_json_node_get_bool
(
JsonNode
*
root
,
const
gchar
*
expr
,
GError
**
error
)
{
gboolean
ret
;
JsonNode
*
rslt
;
rslt
=
fb_json_node_get
(
root
,
expr
,
error
);
if
(
rslt
==
NULL
)
{
return
FALSE
;
}
ret
=
json_node_get_boolean
(
rslt
);
json_node_free
(
rslt
);
return
ret
;
}
gdouble
fb_json_node_get_dbl
(
JsonNode
*
root
,
const
gchar
*
expr
,
GError
**
error
)
{
gdouble
ret
;
JsonNode
*
rslt
;
rslt
=
fb_json_node_get
(
root
,
expr
,
error
);
if
(
rslt
==
NULL
)
{
return
0.0
;
}
ret
=
json_node_get_double
(
rslt
);
json_node_free
(
rslt
);
return
ret
;
}
gint64
fb_json_node_get_int
(
JsonNode
*
root
,
const
gchar
*
expr
,
GError
**
error
)
{
gint64
ret
;
JsonNode
*
rslt
;
rslt
=
fb_json_node_get
(
root
,
expr
,
error
);
if
(
rslt
==
NULL
)
{
return
0
;
}
ret
=
json_node_get_int
(
rslt
);
json_node_free
(
rslt
);
return
ret
;
}
gchar
*
fb_json_node_get_str
(
JsonNode
*
root
,
const
gchar
*
expr
,
GError
**
error
)
{
gchar
*
ret
;
JsonNode
*
rslt
;
rslt
=
fb_json_node_get
(
root
,
expr
,
error
);
if
(
rslt
==
NULL
)
{
return
NULL
;
}
ret
=
json_node_dup_string
(
rslt
);
json_node_free
(
rslt
);
return
ret
;
}
FbJsonValues
*
fb_json_values_new
(
JsonNode
*
root
)
{
FbJsonValues
*
values
;
FbJsonValuesPrivate
*
priv
;
g_return_val_if_fail
(
root
!=
NULL
,
NULL
);
values
=
g_object_new
(
FB_TYPE_JSON_VALUES
,
NULL
);
priv
=
values
->
priv
;
priv
->
root
=
root
;
return
values
;
}
void
fb_json_values_add
(
FbJsonValues
*
values
,
FbJsonType
type
,
gboolean
required
,
const
gchar
*
expr
)
{
FbJsonValue
*
value
;
FbJsonValuesPrivate
*
priv
;
g_return_if_fail
(
values
!=
NULL
);
g_return_if_fail
(
expr
!=
NULL
);
priv
=
values
->
priv
;
value
=
g_new0
(
FbJsonValue
,
1
);
value
->
expr
=
expr
;
value
->
type
=
type
;
value
->
required
=
required
;
g_queue_push_tail
(
priv
->
queue
,
value
);
}
JsonNode
*
fb_json_values_get_root
(
FbJsonValues
*
values
)
{
FbJsonValuesPrivate
*
priv
;
guint
index
;
g_return_val_if_fail
(
values
!=
NULL
,
NULL
);
priv
=
values
->
priv
;
if
(
priv
->
array
==
NULL
)
{
return
priv
->
root
;
}
g_return_val_if_fail
(
priv
->
index
>
0
,
NULL
);
index
=
priv
->
index
-
1
;
if
(
json_array_get_length
(
priv
->
array
)
<=
index
)
{
return
NULL
;
}
return
json_array_get_element
(
priv
->
array
,
index
);
}
void
fb_json_values_set_array
(
FbJsonValues
*
values
,
gboolean
required
,
const
gchar
*
expr
)
{
FbJsonValuesPrivate
*
priv
;
g_return_if_fail
(
values
!=
NULL
);
priv
=
values
->
priv
;
priv
->
array
=
fb_json_node_get_arr
(
priv
->
root
,
expr
,
&
priv
->
error
);
priv
->
isarray
=
TRUE
;
if
((
priv
->
error
!=
NULL
)
&&
!
required
)
{
g_clear_error
(
&
priv
->
error
);
}
}
gboolean
fb_json_values_update
(
FbJsonValues
*
values
,
GError
**
error
)
{
FbJsonValue
*
value
;
FbJsonValuesPrivate
*
priv
;
GError
*
err
=
NULL
;
GList
*
l
;
GType
type
;
JsonNode
*
root
;
JsonNode
*
node
;
g_return_val_if_fail
(
values
!=
NULL
,
FALSE
);
priv
=
values
->
priv
;
if
(
G_UNLIKELY
(
priv
->
error
!=
NULL
))
{
g_propagate_error
(
error
,
priv
->
error
);
priv
->
error
=
NULL
;
return
FALSE
;
}
if
(
priv
->
isarray
)
{
if
((
priv
->
array
==
NULL
)
||
(
json_array_get_length
(
priv
->
array
)
<=
priv
->
index
))
{
return
FALSE
;
}
root
=
json_array_get_element
(
priv
->
array
,
priv
->
index
++
);
}
else
{
root
=
priv
->
root
;
}
g_return_val_if_fail
(
root
!=
NULL
,
FALSE
);
for
(
l
=
priv
->
queue
->
head
;
l
!=
NULL
;
l
=
l
->
next
)
{
value
=
l
->
data
;
node
=
fb_json_node_get
(
root
,
value
->
expr
,
&
err
);
if
(
G_IS_VALUE
(
&
value
->
value
))
{
g_value_unset
(
&
value
->
value
);
}
if
(
err
!=
NULL
)
{
json_node_free
(
node
);
if
(
value
->
required
)
{
g_propagate_error
(
error
,
err
);
return
FALSE
;
}
g_clear_error
(
&
err
);
continue
;
}
type
=
json_node_get_value_type
(
node
);
if
(
G_UNLIKELY
(
type
!=
value
->
type
))
{
g_set_error
(
error
,
FB_JSON_ERROR
,
FB_JSON_ERROR_TYPE
,
_
(
"Expected a %s but got a %s for %s"
),
g_type_name
(
value
->
type
),
g_type_name
(
type
),
value
->
expr
);
json_node_free
(
node
);
return
FALSE
;
}
json_node_get_value
(
node
,
&
value
->
value
);
json_node_free
(
node
);
}
priv
->
next
=
priv
->
queue
->
head
;
return
TRUE
;
}
const
GValue
*
fb_json_values_next
(
FbJsonValues
*
values
)
{
FbJsonValue
*
value
;
FbJsonValuesPrivate
*
priv
;
g_return_val_if_fail
(
values
!=
NULL
,
NULL
);
priv
=
values
->
priv
;
g_return_val_if_fail
(
priv
->
next
!=
NULL
,
NULL
);
value
=
priv
->
next
->
data
;
priv
->
next
=
priv
->
next
->
next
;
if
(
!
G_IS_VALUE
(
&
value
->
value
))
{
return
NULL
;
}
return
&
value
->
value
;
}
gboolean
fb_json_values_next_bool
(
FbJsonValues
*
values
,
gboolean
defval
)
{
const
GValue
*
value
;
value
=
fb_json_values_next
(
values
);
if
(
G_UNLIKELY
(
value
==
NULL
))
{
return
defval
;
}
return
g_value_get_boolean
(
value
);
}
gdouble
fb_json_values_next_dbl
(
FbJsonValues
*
values
,
gdouble
defval
)
{
const
GValue
*
value
;
value
=
fb_json_values_next
(
values
);
if
(
G_UNLIKELY
(
value
==
NULL
))
{
return
defval
;
}
return
g_value_get_double
(
value
);
}
gint64
fb_json_values_next_int
(
FbJsonValues
*
values
,
gint64
defval
)
{
const
GValue
*
value
;
value
=
fb_json_values_next
(
values
);
if
(
G_UNLIKELY
(
value
==
NULL
))
{
return
defval
;
}
return
g_value_get_int64
(
value
);
}
const
gchar
*
fb_json_values_next_str
(
FbJsonValues
*
values
,
const
gchar
*
defval
)
{
const
GValue
*
value
;
value
=
fb_json_values_next
(
values
);
if
(
G_UNLIKELY
(
value
==
NULL
))
{
return
defval
;
}
return
g_value_get_string
(
value
);
}
gchar
*
fb_json_values_next_str_dup
(
FbJsonValues
*
values
,
const
gchar
*
defval
)
{
const
GValue
*
value
;
value
=
fb_json_values_next
(
values
);
if
(
G_UNLIKELY
(
value
==
NULL
))
{
return
g_strdup
(
defval
);
}
return
g_value_dup_string
(
value
);
}