pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Fix an error caused by misreading purple_strequal()
release-2.x.y
2019-11-05, John Bailey
60fbcaffa69a
Fix an error caused by misreading purple_strequal()
/**
* @file tcl_cmd.c Purple Tcl cmd API
*
* purple
*
* Copyright (C) 2006 Etan Reisner <deryni@gmail.com>
*
* 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
<tcl.h>
#include
"tcl_purple.h"
#include
"internal.h"
#include
"cmds.h"
#include
"debug.h"
static
GList
*
tcl_cmd_callbacks
;
static
PurpleCmdRet
tcl_cmd_callback
(
PurpleConversation
*
conv
,
const
gchar
*
cmd
,
gchar
**
args
,
gchar
**
errors
,
struct
tcl_cmd_handler
*
handler
);
static
Tcl_Obj
*
new_cmd_cb_namespace
(
void
);
void
tcl_cmd_init
()
{
tcl_cmd_callbacks
=
NULL
;
}
void
tcl_cmd_handler_free
(
struct
tcl_cmd_handler
*
handler
)
{
if
(
handler
==
NULL
)
return
;
Tcl_DecrRefCount
(
handler
->
namespace
);
g_free
(
handler
);
}
void
tcl_cmd_cleanup
(
Tcl_Interp
*
interp
)
{
GList
*
cur
;
struct
tcl_cmd_handler
*
handler
;
for
(
cur
=
tcl_cmd_callbacks
;
cur
!=
NULL
;
cur
=
g_list_next
(
cur
))
{
handler
=
cur
->
data
;
if
(
handler
->
interp
==
interp
)
{
purple_cmd_unregister
(
handler
->
id
);
tcl_cmd_handler_free
(
handler
);
cur
->
data
=
NULL
;
}
}
tcl_cmd_callbacks
=
g_list_remove_all
(
tcl_cmd_callbacks
,
NULL
);
}
PurpleCmdId
tcl_cmd_register
(
struct
tcl_cmd_handler
*
handler
)
{
int
id
;
GString
*
proc
;
if
((
id
=
purple_cmd_register
(
Tcl_GetString
(
handler
->
cmd
),
handler
->
args
,
handler
->
priority
,
handler
->
flags
,
handler
->
prpl_id
,
PURPLE_CMD_FUNC
(
tcl_cmd_callback
),
handler
->
helpstr
,
(
void
*
)
handler
))
==
0
)
return
0
;
handler
->
namespace
=
new_cmd_cb_namespace
();
Tcl_IncrRefCount
(
handler
->
namespace
);
proc
=
g_string_new
(
""
);
g_string_append_printf
(
proc
,
"namespace eval %s { proc cb { conv cmd arglist } { %s } }"
,
Tcl_GetString
(
handler
->
namespace
),
Tcl_GetString
(
handler
->
proc
));
if
(
Tcl_Eval
(
handler
->
interp
,
proc
->
str
)
!=
TCL_OK
)
{
Tcl_DecrRefCount
(
handler
->
namespace
);
g_string_free
(
proc
,
TRUE
);
return
0
;
}
g_string_free
(
proc
,
TRUE
);
tcl_cmd_callbacks
=
g_list_append
(
tcl_cmd_callbacks
,
(
gpointer
)
handler
);
return
id
;
}
void
tcl_cmd_unregister
(
PurpleCmdId
id
,
Tcl_Interp
*
interp
)
{
GList
*
cur
;
GString
*
cmd
;
gboolean
found
=
FALSE
;
struct
tcl_cmd_handler
*
handler
;
for
(
cur
=
tcl_cmd_callbacks
;
cur
!=
NULL
;
cur
=
g_list_next
(
cur
))
{
handler
=
cur
->
data
;
if
(
handler
->
interp
==
interp
&&
handler
->
id
==
id
)
{
purple_cmd_unregister
(
id
);
cmd
=
g_string_sized_new
(
64
);
g_string_printf
(
cmd
,
"namespace delete %s"
,
Tcl_GetString
(
handler
->
namespace
));
Tcl_EvalEx
(
interp
,
cmd
->
str
,
-1
,
TCL_EVAL_GLOBAL
);
tcl_cmd_handler_free
(
handler
);
g_string_free
(
cmd
,
TRUE
);
cur
->
data
=
NULL
;
found
=
TRUE
;
break
;
}
}
if
(
found
)
tcl_cmd_callbacks
=
g_list_remove_all
(
tcl_cmd_callbacks
,
NULL
);
}
static
PurpleCmdRet
tcl_cmd_callback
(
PurpleConversation
*
conv
,
const
gchar
*
cmd
,
gchar
**
args
,
gchar
**
errors
,
struct
tcl_cmd_handler
*
handler
)
{
int
retval
,
i
;
Tcl_Obj
*
command
,
*
arg
,
*
tclargs
,
*
result
;
command
=
Tcl_NewListObj
(
0
,
NULL
);
Tcl_IncrRefCount
(
command
);
/* The callback */
arg
=
Tcl_DuplicateObj
(
handler
->
namespace
);
Tcl_AppendStringsToObj
(
arg
,
"::cb"
,
NULL
);
Tcl_ListObjAppendElement
(
handler
->
interp
,
command
,
arg
);
/* The conversation */
arg
=
purple_tcl_ref_new
(
PurpleTclRefConversation
,
conv
);
Tcl_ListObjAppendElement
(
handler
->
interp
,
command
,
arg
);
/* The command */
arg
=
Tcl_NewStringObj
(
cmd
,
-1
);
Tcl_ListObjAppendElement
(
handler
->
interp
,
command
,
arg
);
/* The args list */
tclargs
=
Tcl_NewListObj
(
0
,
NULL
);
for
(
i
=
0
;
i
<
handler
->
nargs
;
i
++
)
{
arg
=
Tcl_NewStringObj
(
args
[
i
],
-1
);
Tcl_ListObjAppendElement
(
handler
->
interp
,
tclargs
,
arg
);
}
Tcl_ListObjAppendElement
(
handler
->
interp
,
command
,
tclargs
);
if
(
Tcl_EvalObjEx
(
handler
->
interp
,
command
,
TCL_EVAL_GLOBAL
)
!=
TCL_OK
)
{
gchar
*
errorstr
;
errorstr
=
g_strdup_printf
(
"error evaluating callback: %s
\n
"
,
Tcl_GetString
(
Tcl_GetObjResult
(
handler
->
interp
)));
purple_debug
(
PURPLE_DEBUG_ERROR
,
"tcl"
,
"%s"
,
errorstr
);
*
errors
=
errorstr
;
retval
=
PURPLE_CMD_RET_FAILED
;
}
else
{
result
=
Tcl_GetObjResult
(
handler
->
interp
);
if
(
Tcl_GetIntFromObj
(
handler
->
interp
,
result
,
&
retval
)
!=
TCL_OK
)
{
gchar
*
errorstr
;
errorstr
=
g_strdup_printf
(
"Error retreiving procedure result: %s
\n
"
,
Tcl_GetString
(
Tcl_GetObjResult
(
handler
->
interp
)));
purple_debug
(
PURPLE_DEBUG_ERROR
,
"tcl"
,
"%s"
,
errorstr
);
*
errors
=
errorstr
;
retval
=
PURPLE_CMD_RET_FAILED
;
}
}
return
retval
;
}
static
Tcl_Obj
*
new_cmd_cb_namespace
()
{
char
name
[
32
];
static
int
cbnum
;
g_snprintf
(
name
,
sizeof
(
name
),
"::purple::_cmd_callback::cb_%d"
,
cbnum
++
);
return
Tcl_NewStringObj
(
name
,
-1
);
}