gaim/gaim
Clone
Summary
Browse
Changes
Graph
Make this sucker compile again!!
draft
default
tip
2022-03-31, Gary Kramlich
ea0a68c3b8a8
Make this sucker compile again!!
#include
"perl-common.h"
#include
"perl-handlers.h"
#include
"debug.h"
#include
"signals.h"
extern
PerlInterpreter
*
my_perl
;
static
GList
*
cmd_handlers
=
NULL
;
static
GList
*
signal_handlers
=
NULL
;
static
GList
*
timeout_handlers
=
NULL
;
/* perl < 5.8.0 doesn't define PERL_MAGIC_ext */
#ifndef PERL_MAGIC_ext
#define PERL_MAGIC_ext '~'
#endif
void
gaim_perl_plugin_action_cb
(
GaimPluginAction
*
action
)
{
SV
**
callback
;
HV
*
hv
=
NULL
;
gchar
*
hvname
;
GaimPlugin
*
plugin
;
GaimPerlScript
*
gps
;
dSP
;
plugin
=
action
->
plugin
;
gps
=
(
GaimPerlScript
*
)
plugin
->
info
->
extra_info
;
hvname
=
g_strdup_printf
(
"%s::plugin_actions"
,
gps
->
package
);
hv
=
get_hv
(
hvname
,
FALSE
);
g_free
(
hvname
);
if
(
hv
==
NULL
)
croak
(
"No plugin_actions hash found in
\"
%s
\"
plugin."
,
gaim_plugin_get_name
(
plugin
));
ENTER
;
SAVETMPS
;
callback
=
hv_fetch
(
hv
,
action
->
label
,
strlen
(
action
->
label
),
0
);
if
(
callback
==
NULL
||
*
callback
==
NULL
)
croak
(
"No plugin_action function named
\"
%s
\"
in
\"
%s
\"
plugin."
,
action
->
label
,
gaim_plugin_get_name
(
plugin
));
PUSHMARK
(
sp
);
XPUSHs
(
gaim_perl_bless_object
(
gps
->
plugin
,
"Gaim::Plugin"
));
PUTBACK
;
call_sv
(
*
callback
,
G_VOID
|
G_DISCARD
);
SPAGAIN
;
PUTBACK
;
FREETMPS
;
LEAVE
;
}
GList
*
gaim_perl_plugin_actions
(
GaimPlugin
*
plugin
,
gpointer
context
)
{
GList
*
l
=
NULL
;
GaimPerlScript
*
gps
;
int
i
=
0
,
count
=
0
;
dSP
;
gps
=
(
GaimPerlScript
*
)
plugin
->
info
->
extra_info
;
ENTER
;
SAVETMPS
;
PUSHMARK
(
SP
);
XPUSHs
(
sv_2mortal
(
gaim_perl_bless_object
(
plugin
,
"Gaim::Plugin"
)));
/* XXX This *will* cease working correctly if context gets changed to
* ever be able to hold anything other than a GaimConnection */
if
(
context
!=
NULL
)
XPUSHs
(
sv_2mortal
(
gaim_perl_bless_object
(
context
,
"Gaim::Connection"
)));
else
XPUSHs
(
&
PL_sv_undef
);
PUTBACK
;
count
=
call_pv
(
gps
->
plugin_action_sub
,
G_ARRAY
);
SPAGAIN
;
if
(
count
==
0
)
croak
(
"The plugin_actions sub didn't return anything.
\n
"
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
SV
*
sv
;
gchar
*
label
;
GaimPluginAction
*
act
=
NULL
;
sv
=
POPs
;
label
=
SvPV_nolen
(
sv
);
/* XXX I think this leaks, but doing it without the strdup
* just showed garbage */
act
=
gaim_plugin_action_new
(
g_strdup
(
label
),
gaim_perl_plugin_action_cb
);
l
=
g_list_prepend
(
l
,
act
);
}
PUTBACK
;
FREETMPS
;
LEAVE
;
return
l
;
}
GtkWidget
*
gaim_perl_gtk_get_plugin_frame
(
GaimPlugin
*
plugin
)
{
SV
*
sv
;
int
count
;
MAGIC
*
mg
;
GtkWidget
*
ret
;
GaimPerlScript
*
gps
;
dSP
;
gps
=
(
GaimPerlScript
*
)
plugin
->
info
->
extra_info
;
ENTER
;
SAVETMPS
;
count
=
call_pv
(
gps
->
gtk_prefs_sub
,
G_SCALAR
|
G_NOARGS
);
if
(
count
!=
1
)
croak
(
"call_pv: Did not return the correct number of values.
\n
"
);
/* the frame was created in a perl sub and is returned */
SPAGAIN
;
/* We have a Gtk2::Frame on top of the stack */
sv
=
POPs
;
/* The magic field hides the pointer to the actual GtkWidget */
mg
=
mg_find
(
SvRV
(
sv
),
PERL_MAGIC_ext
);
ret
=
(
GtkWidget
*
)
mg
->
mg_ptr
;
PUTBACK
;
FREETMPS
;
LEAVE
;
return
ret
;
}
GaimPluginPrefFrame
*
gaim_perl_get_plugin_frame
(
GaimPlugin
*
plugin
)
{
/* Sets up the Perl Stack for our call back into the script to run the
* plugin_pref... sub */
int
count
;
GaimPerlScript
*
gps
;
GaimPluginPrefFrame
*
ret_frame
;
dSP
;
gps
=
(
GaimPerlScript
*
)
plugin
->
info
->
extra_info
;
ENTER
;
SAVETMPS
;
/* Some perl magic to run perl_plugin_pref_frame_SV perl sub and
* return the frame */
PUSHMARK
(
SP
);
PUTBACK
;
count
=
call_pv
(
gps
->
prefs_sub
,
G_SCALAR
|
G_NOARGS
);
SPAGAIN
;
if
(
count
!=
1
)
croak
(
"call_pv: Did not return the correct number of values.
\n
"
);
/* the frame was created in a perl sub and is returned */
ret_frame
=
(
GaimPluginPrefFrame
*
)
gaim_perl_ref_object
(
POPs
);
/* Tidy up the Perl stack */
PUTBACK
;
FREETMPS
;
LEAVE
;
return
ret_frame
;
}
static
void
destroy_timeout_handler
(
GaimPerlTimeoutHandler
*
handler
)
{
timeout_handlers
=
g_list_remove
(
timeout_handlers
,
handler
);
if
(
handler
->
callback
!=
NULL
)
SvREFCNT_dec
(
handler
->
callback
);
if
(
handler
->
data
!=
NULL
)
SvREFCNT_dec
(
handler
->
data
);
g_free
(
handler
);
}
static
void
destroy_signal_handler
(
GaimPerlSignalHandler
*
handler
)
{
signal_handlers
=
g_list_remove
(
signal_handlers
,
handler
);
if
(
handler
->
callback
!=
NULL
)
SvREFCNT_dec
(
handler
->
callback
);
if
(
handler
->
data
!=
NULL
)
SvREFCNT_dec
(
handler
->
data
);
g_free
(
handler
->
signal
);
g_free
(
handler
);
}
static
int
perl_timeout_cb
(
gpointer
data
)
{
GaimPerlTimeoutHandler
*
handler
=
(
GaimPerlTimeoutHandler
*
)
data
;
dSP
;
ENTER
;
SAVETMPS
;
PUSHMARK
(
sp
);
XPUSHs
((
SV
*
)
handler
->
data
);
PUTBACK
;
call_sv
(
handler
->
callback
,
G_EVAL
|
G_SCALAR
);
SPAGAIN
;
PUTBACK
;
FREETMPS
;
LEAVE
;
destroy_timeout_handler
(
handler
);
return
0
;
}
typedef
void
*
DATATYPE
;
static
void
*
perl_signal_cb
(
va_list
args
,
void
*
data
)
{
GaimPerlSignalHandler
*
handler
=
(
GaimPerlSignalHandler
*
)
data
;
void
*
ret_val
=
NULL
;
int
i
;
int
count
;
int
value_count
;
GaimValue
*
ret_value
,
**
values
;
SV
**
sv_args
;
DATATYPE
**
copy_args
;
STRLEN
na
;
dSP
;
ENTER
;
SAVETMPS
;
PUSHMARK
(
sp
);
gaim_signal_get_values
(
handler
->
instance
,
handler
->
signal
,
&
ret_value
,
&
value_count
,
&
values
);
sv_args
=
g_new
(
SV
*
,
value_count
);
copy_args
=
g_new
(
void
**
,
value_count
);
for
(
i
=
0
;
i
<
value_count
;
i
++
)
{
sv_args
[
i
]
=
gaim_perl_sv_from_vargs
(
values
[
i
],
(
va_list
*
)
&
args
,
&
copy_args
[
i
]);
XPUSHs
(
sv_args
[
i
]);
}
XPUSHs
((
SV
*
)
handler
->
data
);
PUTBACK
;
if
(
ret_value
!=
NULL
)
{
count
=
call_sv
(
handler
->
callback
,
G_EVAL
|
G_SCALAR
);
SPAGAIN
;
if
(
count
!=
1
)
croak
(
"Uh oh! call_sv returned %i != 1"
,
i
);
else
ret_val
=
gaim_perl_data_from_sv
(
ret_value
,
POPs
);
}
else
{
call_sv
(
handler
->
callback
,
G_SCALAR
);
SPAGAIN
;
}
if
(
SvTRUE
(
ERRSV
))
{
gaim_debug_error
(
"perl"
,
"Perl function exited abnormally: %s
\n
"
,
SvPV
(
ERRSV
,
na
));
}
/* See if any parameters changed. */
for
(
i
=
0
;
i
<
value_count
;
i
++
)
{
if
(
gaim_value_is_outgoing
(
values
[
i
]))
{
switch
(
gaim_value_get_type
(
values
[
i
]))
{
case
GAIM_TYPE_BOOLEAN
:
*
((
gboolean
*
)
copy_args
[
i
])
=
SvIV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_INT
:
*
((
int
*
)
copy_args
[
i
])
=
SvIV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_UINT
:
*
((
unsigned
int
*
)
copy_args
[
i
])
=
SvUV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_LONG
:
*
((
long
*
)
copy_args
[
i
])
=
SvIV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_ULONG
:
*
((
unsigned
long
*
)
copy_args
[
i
])
=
SvUV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_INT64
:
*
((
gint64
*
)
copy_args
[
i
])
=
SvIV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_UINT64
:
*
((
guint64
*
)
copy_args
[
i
])
=
SvUV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_STRING
:
if
(
strcmp
(
*
((
char
**
)
copy_args
[
i
]),
SvPVX
(
sv_args
[
i
])))
{
g_free
(
*
((
char
**
)
copy_args
[
i
]));
*
((
char
**
)
copy_args
[
i
])
=
g_strdup
(
SvPV
(
sv_args
[
i
],
na
));
}
break
;
case
GAIM_TYPE_POINTER
:
*
((
void
**
)
copy_args
[
i
])
=
(
void
*
)
SvIV
(
sv_args
[
i
]);
break
;
case
GAIM_TYPE_BOXED
:
*
((
void
**
)
copy_args
[
i
])
=
(
void
*
)
SvIV
(
sv_args
[
i
]);
break
;
default
:
break
;
}
#if 0
*((void **)copy_args[i]) = gaim_perl_data_from_sv(values[i],
sv_args[i]);
#endif
}
}
PUTBACK
;
FREETMPS
;
LEAVE
;
g_free
(
sv_args
);
g_free
(
copy_args
);
gaim_debug_misc
(
"perl"
,
"ret_val = %p
\n
"
,
ret_val
);
return
ret_val
;
}
static
GaimPerlSignalHandler
*
find_signal_handler
(
GaimPlugin
*
plugin
,
void
*
instance
,
const
char
*
signal
)
{
GaimPerlSignalHandler
*
handler
;
GList
*
l
;
for
(
l
=
signal_handlers
;
l
!=
NULL
;
l
=
l
->
next
)
{
handler
=
(
GaimPerlSignalHandler
*
)
l
->
data
;
if
(
handler
->
plugin
==
plugin
&&
handler
->
instance
==
instance
&&
!
strcmp
(
handler
->
signal
,
signal
))
{
return
handler
;
}
}
return
NULL
;
}
void
gaim_perl_timeout_add
(
GaimPlugin
*
plugin
,
int
seconds
,
SV
*
callback
,
SV
*
data
)
{
GaimPerlTimeoutHandler
*
handler
;
if
(
plugin
==
NULL
)
{
croak
(
"Invalid handle in adding perl timeout handler.
\n
"
);
return
;
}
handler
=
g_new0
(
GaimPerlTimeoutHandler
,
1
);
handler
->
plugin
=
plugin
;
handler
->
callback
=
(
callback
!=
NULL
&&
callback
!=
&
PL_sv_undef
?
newSVsv
(
callback
)
:
NULL
);
handler
->
data
=
(
data
!=
NULL
&&
data
!=
&
PL_sv_undef
?
newSVsv
(
data
)
:
NULL
);
timeout_handlers
=
g_list_append
(
timeout_handlers
,
handler
);
handler
->
iotag
=
g_timeout_add
(
seconds
*
1000
,
perl_timeout_cb
,
handler
);
}
void
gaim_perl_timeout_clear_for_plugin
(
GaimPlugin
*
plugin
)
{
GaimPerlTimeoutHandler
*
handler
;
GList
*
l
,
*
l_next
;
for
(
l
=
timeout_handlers
;
l
!=
NULL
;
l
=
l_next
)
{
l_next
=
l
->
next
;
handler
=
(
GaimPerlTimeoutHandler
*
)
l
->
data
;
if
(
handler
->
plugin
==
plugin
)
destroy_timeout_handler
(
handler
);
}
}
void
gaim_perl_timeout_clear
(
void
)
{
while
(
timeout_handlers
!=
NULL
)
destroy_timeout_handler
(
timeout_handlers
->
data
);
}
void
gaim_perl_signal_connect
(
GaimPlugin
*
plugin
,
void
*
instance
,
const
char
*
signal
,
SV
*
callback
,
SV
*
data
,
int
priority
)
{
GaimPerlSignalHandler
*
handler
;
handler
=
g_new0
(
GaimPerlSignalHandler
,
1
);
handler
->
plugin
=
plugin
;
handler
->
instance
=
instance
;
handler
->
signal
=
g_strdup
(
signal
);
handler
->
callback
=
(
callback
!=
NULL
&&
callback
!=
&
PL_sv_undef
?
newSVsv
(
callback
)
:
NULL
);
handler
->
data
=
(
data
!=
NULL
&&
data
!=
&
PL_sv_undef
?
newSVsv
(
data
)
:
NULL
);
signal_handlers
=
g_list_append
(
signal_handlers
,
handler
);
gaim_signal_connect_priority_vargs
(
instance
,
signal
,
plugin
,
GAIM_CALLBACK
(
perl_signal_cb
),
handler
,
priority
);
}
void
gaim_perl_signal_disconnect
(
GaimPlugin
*
plugin
,
void
*
instance
,
const
char
*
signal
)
{
GaimPerlSignalHandler
*
handler
;
handler
=
find_signal_handler
(
plugin
,
instance
,
signal
);
if
(
handler
==
NULL
)
{
croak
(
"Invalid signal handler information in "
"disconnecting a perl signal handler.
\n
"
);
return
;
}
destroy_signal_handler
(
handler
);
}
void
gaim_perl_signal_clear_for_plugin
(
GaimPlugin
*
plugin
)
{
GaimPerlSignalHandler
*
handler
;
GList
*
l
,
*
l_next
;
for
(
l
=
signal_handlers
;
l
!=
NULL
;
l
=
l_next
)
{
l_next
=
l
->
next
;
handler
=
(
GaimPerlSignalHandler
*
)
l
->
data
;
if
(
handler
->
plugin
==
plugin
)
destroy_signal_handler
(
handler
);
}
}
void
gaim_perl_signal_clear
(
void
)
{
while
(
signal_handlers
!=
NULL
)
destroy_signal_handler
(
signal_handlers
->
data
);
}
static
GaimCmdRet
perl_cmd_cb
(
GaimConversation
*
conv
,
const
gchar
*
command
,
gchar
**
args
,
gchar
**
error
,
void
*
data
)
{
int
i
=
0
,
count
,
ret_value
=
GAIM_CMD_RET_OK
;
SV
*
cmdSV
,
*
tmpSV
,
*
convSV
;
GaimPerlCmdHandler
*
handler
=
(
GaimPerlCmdHandler
*
)
data
;
dSP
;
ENTER
;
SAVETMPS
;
PUSHMARK
(
SP
);
/* Push the conversation onto the perl stack */
convSV
=
sv_2mortal
(
gaim_perl_bless_object
(
conv
,
"Gaim::Conversation"
));
XPUSHs
(
convSV
);
/* Push the command string onto the perl stack */
cmdSV
=
newSVpv
(
command
,
0
);
cmdSV
=
sv_2mortal
(
cmdSV
);
XPUSHs
(
cmdSV
);
/* Push the data onto the perl stack */
XPUSHs
((
SV
*
)
handler
->
data
);
/* Push any arguments we may have */
for
(
i
=
0
;
args
[
i
]
!=
NULL
;
i
++
)
{
/* XXX The mortality of these created SV's should prevent
* memory issues, if I read/understood everything correctly...
*/
tmpSV
=
newSVpv
(
args
[
i
],
0
);
tmpSV
=
sv_2mortal
(
tmpSV
);
XPUSHs
(
tmpSV
);
}
PUTBACK
;
count
=
call_sv
(
handler
->
callback
,
G_EVAL
|
G_SCALAR
);
if
(
count
!=
1
)
croak
(
"call_sv: Did not return the correct number of values.
\n
"
);
SPAGAIN
;
ret_value
=
POPi
;
PUTBACK
;
FREETMPS
;
LEAVE
;
return
ret_value
;
}
GaimCmdId
gaim_perl_cmd_register
(
GaimPlugin
*
plugin
,
const
gchar
*
command
,
const
gchar
*
args
,
GaimCmdPriority
priority
,
GaimCmdFlag
flag
,
const
gchar
*
prpl_id
,
SV
*
callback
,
const
gchar
*
helpstr
,
SV
*
data
)
{
GaimPerlCmdHandler
*
handler
;
handler
=
g_new0
(
GaimPerlCmdHandler
,
1
);
handler
->
plugin
=
plugin
;
handler
->
cmd
=
g_strdup
(
command
);
handler
->
prpl_id
=
g_strdup
(
prpl_id
);
if
(
callback
!=
NULL
&&
callback
!=
&
PL_sv_undef
)
handler
->
callback
=
newSVsv
(
callback
);
else
handler
->
callback
=
NULL
;
if
(
data
!=
NULL
&&
data
!=
&
PL_sv_undef
)
handler
->
data
=
newSVsv
(
data
);
else
handler
->
data
=
NULL
;
cmd_handlers
=
g_list_append
(
cmd_handlers
,
handler
);
handler
->
id
=
gaim_cmd_register
(
command
,
args
,
priority
,
flag
,
prpl_id
,
GAIM_CMD_FUNC
(
perl_cmd_cb
),
helpstr
,
handler
);
return
handler
->
id
;
}
static
void
destroy_cmd_handler
(
GaimPerlCmdHandler
*
handler
)
{
cmd_handlers
=
g_list_remove
(
cmd_handlers
,
handler
);
if
(
handler
->
callback
!=
NULL
)
SvREFCNT_dec
(
handler
->
callback
);
if
(
handler
->
data
!=
NULL
)
SvREFCNT_dec
(
handler
->
data
);
g_free
(
handler
->
cmd
);
g_free
(
handler
->
prpl_id
);
g_free
(
handler
);
}
void
gaim_perl_cmd_clear_for_plugin
(
GaimPlugin
*
plugin
)
{
GList
*
l
,
*
l_next
;
for
(
l
=
cmd_handlers
;
l
!=
NULL
;
l
=
l_next
)
{
GaimPerlCmdHandler
*
handler
=
(
GaimPerlCmdHandler
*
)
l
->
data
;
l_next
=
l
->
next
;
if
(
handler
->
plugin
==
plugin
)
destroy_cmd_handler
(
handler
);
}
}
static
GaimPerlCmdHandler
*
find_cmd_handler
(
GaimCmdId
id
)
{
GList
*
l
;
for
(
l
=
cmd_handlers
;
l
!=
NULL
;
l
=
l
->
next
)
{
GaimPerlCmdHandler
*
handler
=
(
GaimPerlCmdHandler
*
)
l
->
data
;
if
(
handler
->
id
==
id
)
return
handler
;
}
return
NULL
;
}
void
gaim_perl_cmd_unregister
(
GaimCmdId
id
)
{
GaimPerlCmdHandler
*
handler
;
handler
=
find_cmd_handler
(
id
);
if
(
handler
==
NULL
)
{
croak
(
"Invalid command id in removing a perl command handler.
\n
"
);
return
;
}
gaim_cmd_unregister
(
id
);
destroy_cmd_handler
(
handler
);
}