pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
fixed the crash on disconnect by closing conversation windows when that buddy is done with it's events, rather than when processing each event.
2009-08-30, Gary Kramlich
8ab9212b3ed3
fixed the crash on disconnect by closing conversation windows when that buddy is done with it's events, rather than when processing each event.
added status text support as a status of the stress
/*--------------------------------------------------------------------------*
* AUTOPROFILE *
* *
* A Purple away message and profile manager that supports dynamic text *
* *
* AutoProfile is the legal property of its developers. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
*--------------------------------------------------------------------------*/
#include
"../common/pp_internal.h"
#include
"widget.h"
#include
"utility.h"
#include
<ctype.h>
#include
<string.h>
static
GStaticMutex
widget_mutex
=
G_STATIC_MUTEX_INIT
;
static
GList
*
widgets
=
NULL
;
static
GHashTable
*
identifiers
=
NULL
;
static
GRand
*
r
=
NULL
;
static
char
*
widget_pref
=
"/plugins/gtk/autoprofile/widgets/widget_ids"
;
static
void
ap_widget_init_default_statuses
()
{
// Make sure we don't keep on readding the default statuses if a user
// deleted them
if
(
!
purple_prefs_exists
(
widget_pref
))
{
purple_prefs_add_none
(
"/plugins/gtk/autoprofile/widgets/42"
);
purple_prefs_add_string
(
"/plugins/gtk/autoprofile/widgets/42/component"
,
"Timestamp"
);
purple_prefs_add_string
(
"/plugins/gtk/autoprofile/widgets/42/alias"
,
"Timestamp"
);
purple_prefs_add_string
(
"/plugins/gtk/autoprofile/widgets/42/timestamp_format"
,
"Automatically created at %I:%M %p"
);
}
}
void
ap_widget_init
()
{
GList
*
node
;
ap_widget_init_default_statuses
();
node
=
g_list_append
(
NULL
,
g_strdup
(
"42"
));
purple_prefs_add_string_list
(
widget_pref
,
node
);
free_string_list
(
node
);
}
/* Basic functions */
static
gchar
*
strip_whitespace
(
const
gchar
*
text
)
{
gchar
*
result
,
*
end
,
*
search
;
while
(
isspace
(
*
text
))
{
text
++
;
}
end
=
NULL
;
search
=
result
=
g_strdup
(
text
);
while
(
*
search
)
{
if
(
end
==
NULL
&&
isspace
(
*
search
))
{
end
=
search
;
}
if
(
!
isspace
(
*
search
))
{
end
=
NULL
;
}
search
++
;
}
if
(
end
!=
NULL
)
*
end
=
'\0'
;
return
result
;
}
static
void
update_widget_ids
()
{
GList
*
cur_node
,
*
ids
;
struct
widget
*
cur_widget
;
ids
=
NULL
;
for
(
cur_node
=
widgets
;
cur_node
!=
NULL
;
cur_node
=
cur_node
->
next
)
{
cur_widget
=
(
struct
widget
*
)
cur_node
->
data
;
ids
=
g_list_append
(
ids
,
cur_widget
->
wid
);
}
purple_prefs_set_string_list
(
widget_pref
,
ids
);
g_list_free
(
ids
);
}
// Mutex is ALREADY HELD when this function is called
static
struct
widget
*
ap_widget_find_internal
(
const
gchar
*
search_text
)
{
GList
*
cur_node
;
struct
widget
*
cur_widget
;
gchar
*
alias
;
alias
=
strip_whitespace
(
search_text
);
cur_node
=
widgets
;
while
(
cur_node
)
{
cur_widget
=
(
struct
widget
*
)
cur_node
->
data
;
if
(
!
purple_utf8_strcasecmp
(
alias
,
cur_widget
->
alias
))
{
free
(
alias
);
return
cur_widget
;
}
cur_node
=
cur_node
->
next
;
}
free
(
alias
);
return
NULL
;
}
struct
widget
*
ap_widget_find
(
const
gchar
*
search_text
)
{
struct
widget
*
w
;
g_static_mutex_lock
(
&
widget_mutex
);
w
=
ap_widget_find_internal
(
search_text
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
w
;
}
struct
widget
*
ap_widget_find_by_identifier
(
const
gchar
*
search_text
)
{
struct
widget
*
w
;
g_static_mutex_lock
(
&
widget_mutex
);
w
=
(
struct
widget
*
)
g_hash_table_lookup
(
identifiers
,
search_text
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
w
;
}
void
ap_widget_start
()
{
GList
*
widget_identifiers
,
*
widget_identifiers_start
;
GString
*
pref_name
;
const
gchar
*
identifier
,
*
component_identifier
;
struct
component
*
comp
;
struct
widget
*
w
;
g_static_mutex_lock
(
&
widget_mutex
);
r
=
g_rand_new
();
widgets
=
NULL
;
identifiers
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
pref_name
=
g_string_new
(
""
);
widget_identifiers_start
=
purple_prefs_get_string_list
(
widget_pref
);
for
(
widget_identifiers
=
widget_identifiers_start
;
widget_identifiers
!=
NULL
;
widget_identifiers
=
widget_identifiers
->
next
)
{
g_string_printf
(
pref_name
,
"/plugins/gtk/autoprofile/widgets/%s/component"
,
(
gchar
*
)
widget_identifiers
->
data
);
component_identifier
=
purple_prefs_get_string
(
pref_name
->
str
);
if
(
component_identifier
==
NULL
)
{
ap_debug_error
(
"widget"
,
"widget does not have component information"
);
continue
;
}
comp
=
ap_component_get_component
(
component_identifier
);
if
(
comp
==
NULL
)
{
ap_debug_error
(
"widget"
,
"no component matches widget identifier"
);
continue
;
}
g_string_printf
(
pref_name
,
"/plugins/gtk/autoprofile/widgets/%s/alias"
,
(
gchar
*
)
widget_identifiers
->
data
);
identifier
=
purple_prefs_get_string
(
pref_name
->
str
);
if
(
identifier
==
NULL
)
{
ap_debug_error
(
"widget"
,
"widget does not have alias information"
);
continue
;
}
w
=
ap_widget_find_internal
(
identifier
);
if
(
w
!=
NULL
)
{
ap_debug_error
(
"widget"
,
"widget alias already in use"
);
continue
;
}
w
=
(
struct
widget
*
)
malloc
(
sizeof
(
struct
widget
));
w
->
alias
=
g_strdup
(
identifier
);
w
->
wid
=
g_strdup
((
gchar
*
)
widget_identifiers
->
data
);
w
->
component
=
comp
;
w
->
data
=
g_hash_table_new
(
NULL
,
NULL
);
widgets
=
g_list_append
(
widgets
,
w
);
g_hash_table_insert
(
identifiers
,
w
->
wid
,
w
);
if
(
w
->
component
->
load
)
{
w
->
component
->
load
(
w
);
}
g_string_printf
(
pref_name
,
"loaded saved widget with alias %s and identifier %s"
,
w
->
alias
,
w
->
wid
);
ap_debug_misc
(
"widget"
,
pref_name
->
str
);
}
free_string_list
(
widget_identifiers_start
);
g_string_free
(
pref_name
,
TRUE
);
g_static_mutex_unlock
(
&
widget_mutex
);
ap_widget_gtk_start
();
}
void
ap_widget_finish
()
{
GList
*
tmp
;
struct
widget
*
w
;
g_static_mutex_lock
(
&
widget_mutex
);
ap_widget_gtk_finish
();
g_hash_table_destroy
(
identifiers
);
identifiers
=
NULL
;
while
(
widgets
)
{
w
=
(
struct
widget
*
)
widgets
->
data
;
if
(
w
->
component
->
unload
)
{
w
->
component
->
unload
(
w
);
}
g_hash_table_destroy
(
w
->
data
);
free
(
w
->
alias
);
free
(
w
->
wid
);
free
(
w
);
tmp
=
widgets
->
next
;
g_list_free_1
(
widgets
);
widgets
=
tmp
;
}
g_rand_free
(
r
);
r
=
NULL
;
g_static_mutex_unlock
(
&
widget_mutex
);
}
gboolean
ap_widget_has_content_changed
()
{
GList
*
node
;
struct
widget
*
w
;
gboolean
changed
=
FALSE
;
g_static_mutex_lock
(
&
widget_mutex
);
for
(
node
=
widgets
;
node
!=
NULL
;
node
=
node
->
next
)
{
w
=
(
struct
widget
*
)
node
->
data
;
if
(
w
->
component
->
has_content_changed
==
NULL
||
w
->
component
->
has_content_changed
(
w
))
{
changed
=
TRUE
;
break
;
}
}
g_static_mutex_unlock
(
&
widget_mutex
);
return
changed
;
}
GList
*
ap_widget_get_widgets
()
{
GList
*
result
;
g_static_mutex_lock
(
&
widget_mutex
);
result
=
g_list_copy
(
widgets
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
result
;
}
struct
widget
*
ap_widget_create
(
struct
component
*
comp
)
{
struct
widget
*
w
;
GString
*
s
;
gchar
*
identifier
,
*
alias
;
int
i
;
GList
*
node
;
g_static_mutex_lock
(
&
widget_mutex
);
// Sanity check to make sure we dont "delete" old widgets by
// overriding old pref
if
(
identifiers
==
NULL
)
{
ap_debug_warn
(
"widget"
,
"tried to create widget when variables unitialized"
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
NULL
;
}
ap_debug
(
"widget"
,
"instantiating new widget from component"
);
s
=
g_string_new
(
""
);
// Get alias
w
=
ap_widget_find_internal
(
comp
->
identifier
);
alias
=
NULL
;
// Stupid compiler
if
(
w
==
NULL
)
{
alias
=
g_strdup
(
comp
->
identifier
);
}
else
{
for
(
i
=
1
;
i
<
10000
;
i
++
)
{
g_string_printf
(
s
,
"%s%d"
,
comp
->
identifier
,
i
);
w
=
ap_widget_find_internal
(
s
->
str
);
if
(
w
==
NULL
)
{
alias
=
g_strdup
(
s
->
str
);
break
;
}
}
if
(
i
==
10000
)
{
// This would happen....very very rarely...
ap_debug_error
(
"widget"
,
"ran out of aliases for component"
);
g_string_free
(
s
,
TRUE
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
NULL
;
}
}
// Get identifier
while
(
TRUE
)
{
i
=
g_rand_int
(
r
);
g_string_printf
(
s
,
"%d"
,
i
);
node
=
widgets
;
while
(
node
)
{
w
=
(
struct
widget
*
)
node
->
data
;
if
(
!
strcmp
(
s
->
str
,
w
->
wid
))
{
break
;
}
node
=
node
->
next
;
}
if
(
node
==
NULL
)
{
identifier
=
g_strdup
(
s
->
str
);
break
;
}
}
w
=
(
struct
widget
*
)
malloc
(
sizeof
(
struct
widget
));
w
->
alias
=
alias
;
w
->
wid
=
identifier
;
w
->
component
=
comp
;
w
->
data
=
g_hash_table_new
(
NULL
,
NULL
);
widgets
=
g_list_append
(
widgets
,
w
);
g_hash_table_insert
(
identifiers
,
w
->
wid
,
w
);
// Modify Purple prefs
update_widget_ids
();
g_string_printf
(
s
,
"/plugins/gtk/autoprofile/widgets/%s"
,
w
->
wid
);
purple_prefs_add_none
(
s
->
str
);
g_string_printf
(
s
,
"/plugins/gtk/autoprofile/widgets/%s/component"
,
w
->
wid
);
purple_prefs_add_string
(
s
->
str
,
w
->
component
->
identifier
);
g_string_printf
(
s
,
"/plugins/gtk/autoprofile/widgets/%s/alias"
,
w
->
wid
);
purple_prefs_add_string
(
s
->
str
,
w
->
alias
);
// Initialize widget
if
(
w
->
component
->
init_pref
)
{
w
->
component
->
init_pref
(
w
);
}
if
(
w
->
component
->
load
)
{
w
->
component
->
load
(
w
);
}
// Cleanup
g_string_printf
(
s
,
"Created widget with alias %s and identifier %s"
,
alias
,
identifier
);
ap_debug
(
"widget"
,
s
->
str
);
g_string_free
(
s
,
TRUE
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
w
;
}
void
ap_widget_delete
(
struct
widget
*
w
)
{
GString
*
s
;
if
(
w
==
NULL
)
{
ap_debug_error
(
"widget"
,
"attempt to delete NULL widget"
);
return
;
}
g_static_mutex_lock
(
&
widget_mutex
);
// Sanity check to make sure we dont "delete" old widgets by
// overriding old pref
if
(
identifiers
==
NULL
)
{
ap_debug_warn
(
"widget"
,
"tried to delete widget when variables unitialized"
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
;
}
s
=
g_string_new
(
""
);
g_string_printf
(
s
,
"Deleting widget with alias %s and identifier %s"
,
w
->
alias
,
w
->
wid
);
ap_debug
(
"widget"
,
s
->
str
);
widgets
=
g_list_remove
(
widgets
,
w
);
g_hash_table_remove
(
identifiers
,
w
->
wid
);
update_widget_ids
();
g_string_printf
(
s
,
"/plugins/gtk/autoprofile/widgets/%s"
,
w
->
wid
);
purple_prefs_remove
(
s
->
str
);
g_string_free
(
s
,
TRUE
);
if
(
w
->
component
->
unload
)
{
w
->
component
->
unload
(
w
);
}
g_hash_table_destroy
(
w
->
data
);
free
(
w
->
wid
);
free
(
w
->
alias
);
free
(
w
);
g_static_mutex_unlock
(
&
widget_mutex
);
}
// TRUE if rename succeeds, FALSE otherwise
gboolean
ap_widget_rename
(
struct
widget
*
orig
,
const
gchar
*
new_alias
)
{
struct
widget
*
w
;
GString
*
s
;
gchar
*
orig_alias
;
g_static_mutex_lock
(
&
widget_mutex
);
w
=
ap_widget_find_internal
(
new_alias
);
if
(
w
!=
NULL
&&
w
!=
orig
)
{
g_static_mutex_unlock
(
&
widget_mutex
);
return
FALSE
;
}
orig_alias
=
orig
->
alias
;
orig
->
alias
=
g_strdup
(
new_alias
);
s
=
g_string_new
(
""
);
g_string_printf
(
s
,
"/plugins/gtk/autoprofile/widgets/%s/alias"
,
orig
->
wid
);
purple_prefs_set_string
(
s
->
str
,
new_alias
);
g_string_printf
(
s
,
"Changed alias of widget from %s to %s"
,
orig_alias
,
new_alias
);
ap_debug
(
"widget"
,
s
->
str
);
free
(
orig_alias
);
g_string_free
(
s
,
TRUE
);
g_static_mutex_unlock
(
&
widget_mutex
);
return
TRUE
;
}
/* Widget data galore! */
void
ap_widget_set_data
(
struct
widget
*
w
,
int
id
,
gpointer
data
)
{
g_static_mutex_lock
(
&
widget_mutex
);
g_hash_table_insert
(
w
->
data
,
GINT_TO_POINTER
(
id
),
data
);
g_static_mutex_unlock
(
&
widget_mutex
);
}
gpointer
ap_widget_get_data
(
struct
widget
*
w
,
int
id
)
{
gpointer
result
;
g_static_mutex_lock
(
&
widget_mutex
);
result
=
g_hash_table_lookup
(
w
->
data
,
GINT_TO_POINTER
(
id
));
g_static_mutex_unlock
(
&
widget_mutex
);
return
result
;
}
/* Widget preferences galore! */
gchar
*
ap_prefs_get_pref_name
(
struct
widget
*
w
,
const
char
*
name
)
{
GString
*
s
;
gchar
*
result
;
s
=
g_string_new
(
""
);
g_string_append
(
s
,
"/plugins/gtk/autoprofile/widgets/"
);
g_string_append_printf
(
s
,
"%s/%s"
,
w
->
wid
,
name
);
result
=
s
->
str
;
g_string_free
(
s
,
FALSE
);
return
result
;
}
void
ap_prefs_add_bool
(
struct
widget
*
w
,
const
char
*
name
,
gboolean
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_add_bool
(
pref
,
value
);
free
(
pref
);
}
void
ap_prefs_add_int
(
struct
widget
*
w
,
const
char
*
name
,
int
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_add_int
(
pref
,
value
);
free
(
pref
);
}
void
ap_prefs_add_none
(
struct
widget
*
w
,
const
char
*
name
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_add_none
(
pref
);
free
(
pref
);
}
void
ap_prefs_add_string
(
struct
widget
*
w
,
const
char
*
name
,
const
char
*
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_add_string
(
pref
,
value
);
free
(
pref
);
}
void
ap_prefs_add_string_list
(
struct
widget
*
w
,
const
char
*
name
,
GList
*
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_add_string_list
(
pref
,
value
);
free
(
pref
);
}
gboolean
ap_prefs_get_bool
(
struct
widget
*
w
,
const
char
*
name
)
{
gboolean
result
;
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
result
=
purple_prefs_get_bool
(
pref
);
free
(
pref
);
return
result
;
}
int
ap_prefs_get_int
(
struct
widget
*
w
,
const
char
*
name
)
{
int
result
;
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
result
=
purple_prefs_get_int
(
pref
);
free
(
pref
);
return
result
;
}
const
char
*
ap_prefs_get_string
(
struct
widget
*
w
,
const
char
*
name
)
{
const
char
*
result
;
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
result
=
purple_prefs_get_string
(
pref
);
free
(
pref
);
return
result
;
}
GList
*
ap_prefs_get_string_list
(
struct
widget
*
w
,
const
char
*
name
)
{
GList
*
result
;
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
result
=
purple_prefs_get_string_list
(
pref
);
free
(
pref
);
return
result
;
}
void
ap_prefs_set_bool
(
struct
widget
*
w
,
const
char
*
name
,
gboolean
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_set_bool
(
pref
,
value
);
free
(
pref
);
ap_widget_prefs_updated
(
w
);
}
void
ap_prefs_set_int
(
struct
widget
*
w
,
const
char
*
name
,
int
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_set_int
(
pref
,
value
);
free
(
pref
);
ap_widget_prefs_updated
(
w
);
}
void
ap_prefs_set_string
(
struct
widget
*
w
,
const
char
*
name
,
const
char
*
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_set_string
(
pref
,
value
);
free
(
pref
);
ap_widget_prefs_updated
(
w
);
}
void
ap_prefs_set_string_list
(
struct
widget
*
w
,
const
char
*
name
,
GList
*
value
)
{
gchar
*
pref
=
ap_prefs_get_pref_name
(
w
,
name
);
purple_prefs_set_string_list
(
pref
,
value
);
free
(
pref
);
ap_widget_prefs_updated
(
w
);
}