|
|
|
/*
|
|
|
|
Copyright (c) 2000 Simon Hausmann <hausmann@kde.org>
|
|
|
|
Copyright (c) 2000 Lars Knoll <knoll@kde.org>
|
|
|
|
Copyright (c) 1999 Preston Brown <pbrown@kde.org>
|
|
|
|
Copyright (c) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "global.h"
|
|
|
|
#include "dcopc.h"
|
|
|
|
#include "dcopobject.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
typedef struct _DcopClientMessage DcopClientMessage;
|
|
|
|
|
|
|
|
struct _DcopClientMessage
|
|
|
|
{
|
|
|
|
int opcode;
|
|
|
|
CARD32 key;
|
|
|
|
dcop_data *data;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _DcopClientPrivate DcopClientPrivate;
|
|
|
|
|
|
|
|
struct _DcopClientPrivate
|
|
|
|
{
|
|
|
|
gchar *app_id;
|
|
|
|
IceConn ice_conn;
|
|
|
|
gint major_opcode;
|
|
|
|
gint major_version, minor_version;
|
|
|
|
gchar *vendor, *release;
|
|
|
|
gboolean registered;
|
|
|
|
gchar *sender_id;
|
|
|
|
|
|
|
|
gchar *default_object;
|
|
|
|
|
|
|
|
CARD32 key;
|
|
|
|
CARD32 current_key;
|
|
|
|
|
|
|
|
GList *transaction_list;
|
|
|
|
gboolean transaction;
|
|
|
|
gint32 transaction_id;
|
|
|
|
|
|
|
|
int opcode;
|
|
|
|
|
|
|
|
guint post_message_timer;
|
|
|
|
GList *messages;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _DcopClientTransaction
|
|
|
|
{
|
|
|
|
gint32 id;
|
|
|
|
CARD32 key;
|
|
|
|
gchar *sender_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
int DCOPAuthCount = 1;
|
|
|
|
const char *DCOPAuthNames[] = {"MIT-MAGIC-COOKIE-1"};
|
|
|
|
|
|
|
|
extern IcePoAuthStatus _IcePoMagicCookie1Proc (IceConn, void **, int, int, int, void *, int *, void **, char **);
|
|
|
|
extern IcePaAuthStatus _IcePaMagicCookie1Proc (IceConn, void **, int, int, void *, int *, void **, char **);
|
|
|
|
|
|
|
|
IcePoAuthProc DCOPClientAuthProcs[] = {_IcePoMagicCookie1Proc};
|
|
|
|
IcePaAuthProc DCOPServerAuthProcs[] = {_IcePaMagicCookie1Proc};
|
|
|
|
|
|
|
|
enum reply_status
|
|
|
|
{ Pending, Ok, Rejected, Failed };
|
|
|
|
|
|
|
|
typedef struct _reply_struct reply_struct;
|
|
|
|
|
|
|
|
struct _reply_struct
|
|
|
|
{
|
|
|
|
gint status;
|
|
|
|
gchar **reply_type;
|
|
|
|
dcop_data **reply_data;
|
|
|
|
guint reply_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void reply_struct_init( reply_struct *s )
|
|
|
|
{
|
|
|
|
s->status = Pending;
|
|
|
|
s->reply_type = 0;
|
|
|
|
s->reply_data = 0;
|
|
|
|
s->reply_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define P ((DcopClientPrivate *)(client->priv))
|
|
|
|
#define ERR( emsg ) \
|
|
|
|
{ \
|
|
|
|
if ( dcop_client_free_error_msg ) \
|
|
|
|
g_free( dcop_client_error_msg ); \
|
|
|
|
dcop_client_error_msg = (gchar *)emsg; \
|
|
|
|
dcop_client_free_error_msg = FALSE; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CLIENT_CLASS(obj) DCOP_CLIENT_CLASS(GTK_OBJECT_GET_CLASS(obj))
|
|
|
|
|
|
|
|
static gchar *dcop_client_server_address = 0;
|
|
|
|
static gchar *dcop_client_error_msg = 0;
|
|
|
|
static gboolean dcop_client_free_error_msg;
|
|
|
|
|
|
|
|
/* don't use the glib types for args here, as this is an ICE callback (Simon)*/
|
|
|
|
void dcop_process_message( IceConn ice_conn, IcePointer client_object,
|
|
|
|
int opcode, unsigned long length, Bool swap,
|
|
|
|
IceReplyWaitInfo *replyWait,
|
|
|
|
Bool *replyWaitRet );
|
|
|
|
|
|
|
|
gchar *dcop_client_normalize_function_signature( const gchar *fun );
|
|
|
|
|
|
|
|
static IcePoVersionRec DCOPVersions[] = {
|
|
|
|
{ DCOPVersionMajor, DCOPVersionMinor, dcop_process_message
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int dcop_client_count = 0;
|
|
|
|
static GtkObjectClass *parent_class = 0;
|
|
|
|
|
|
|
|
static void dcop_client_class_init(DcopClientClass *klass);
|
|
|
|
static void dcop_client_init(DcopClient *client);
|
|
|
|
|
|
|
|
static gboolean dcop_client_real_process ( DcopClient *client, const char *fun, dcop_data *data,
|
|
|
|
char **reply_type, dcop_data **reply_data );
|
|
|
|
|
|
|
|
GtkType
|
|
|
|
dcop_client_get_type(void)
|
|
|
|
{
|
|
|
|
static GtkType dcop_client_type = 0;
|
|
|
|
if (!dcop_client_type)
|
|
|
|
{
|
|
|
|
static const GtkTypeInfo dcop_client_info =
|
|
|
|
{
|
|
|
|
(gchar *)"DcopClient",
|
|
|
|
sizeof(DcopClient),
|
|
|
|
sizeof(DcopClientClass),
|
|
|
|
(GtkClassInitFunc)dcop_client_class_init,
|
|
|
|
(GtkObjectInitFunc)dcop_client_init,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
dcop_client_type = gtk_type_unique(GTK_TYPE_OBJECT, &dcop_client_info);
|
|
|
|
}
|
|
|
|
return dcop_client_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dcop_client_destroy( GtkObject *obj );
|
|
|
|
static void dcop_init(void);
|
|
|
|
static void dcop_shutdown(void);
|
|
|
|
|
|
|
|
void
|
|
|
|
dcop_client_class_init(DcopClientClass *klass)
|
|
|
|
{
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
object_class = (GtkObjectClass *)klass;
|
|
|
|
|
|
|
|
parent_class = (GtkObjectClass *)gtk_type_class(gtk_object_get_type());
|
|
|
|
|
|
|
|
object_class->destroy = dcop_client_destroy;
|
|
|
|
klass->process = dcop_client_real_process;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dcop_client_init(DcopClient *client)
|
|
|
|
{
|
|
|
|
DcopClientPrivate *p;
|
|
|
|
/* tststs :-) C++ hackers :-) (Simon)*/
|
|
|
|
/* p = new GtkDcopClientPrivate;*/
|
|
|
|
p = g_new( DcopClientPrivate, 1 );
|
|
|
|
|
|
|
|
p->app_id = 0;
|
|
|
|
p->ice_conn = 0;
|
|
|
|
p->major_opcode = p->major_version = p->minor_version = 0;
|
|
|
|
p->vendor = p->release = 0;
|
|
|
|
p->registered = FALSE;
|
|
|
|
p->sender_id = 0;
|
|
|
|
p->key = 0;
|
|
|
|
p->current_key = 0;
|
|
|
|
p->post_message_timer = 0;
|
|
|
|
p->messages = 0;
|
|
|
|
p->default_object = 0;
|
|
|
|
p->transaction_list = 0;
|
|
|
|
p->transaction = FALSE;
|
|
|
|
p->transaction_id = 0;
|
|
|
|
p->opcode = 0;
|
|
|
|
|
|
|
|
client->priv = p;
|
|
|
|
|
|
|
|
if ( dcop_client_count == 0 )
|
|
|
|
dcop_init();
|
|
|
|
|
|
|
|
dcop_client_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_destroy( GtkObject *obj )
|
|
|
|
{
|
|
|
|
DcopClient *client = DCOP_CLIENT(obj);
|
|
|
|
|
|
|
|
g_message( "dcop_client_destructor()\n" );
|
|
|
|
|
|
|
|
if ( P->ice_conn && IceConnectionStatus( P->ice_conn ) == IceConnectAccepted )
|
|
|
|
dcop_client_detach( client );
|
|
|
|
|
|
|
|
if ( P->post_message_timer != 0 )
|
|
|
|
g_source_remove( P->post_message_timer );
|
|
|
|
|
|
|
|
{
|
|
|
|
GList *it = g_list_first( P->messages );
|
|
|
|
while ( it )
|
|
|
|
{
|
|
|
|
DcopClientMessage *msg = (DcopClientMessage *)it->data;
|
|
|
|
dcop_data_deref( msg->data );
|
|
|
|
g_free( msg );
|
|
|
|
it = g_list_next( it );
|
|
|
|
}
|
|
|
|
g_list_free( P->messages );
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
GList *it = g_list_first( P->transaction_list );
|
|
|
|
while ( it )
|
|
|
|
{
|
|
|
|
g_free( ((DcopClientTransaction *)it->data)->sender_id );
|
|
|
|
g_free( (DcopClientTransaction *)it );
|
|
|
|
it = g_list_next( it );
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free( P->transaction_list );
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free( P->app_id );
|
|
|
|
g_free( P->vendor );
|
|
|
|
g_free( P->release );
|
|
|
|
g_free( P->sender_id );
|
|
|
|
|
|
|
|
g_free( P );
|
|
|
|
|
|
|
|
if ( !--dcop_client_count )
|
|
|
|
dcop_shutdown();
|
|
|
|
|
|
|
|
parent_class->destroy(GTK_OBJECT(client));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dcop_init()
|
|
|
|
{
|
|
|
|
g_message( "dcop_init\n" );
|
|
|
|
dcop_client_free_error_msg = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_shutdown()
|
|
|
|
{
|
|
|
|
g_message( "dcop_shutdown\n" );
|
|
|
|
dcop_free( dcop_client_server_address );
|
|
|
|
|
|
|
|
if ( dcop_client_free_error_msg )
|
|
|
|
dcop_free( dcop_client_error_msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
DcopClient *dcop_client_new()
|
|
|
|
{
|
|
|
|
return (DcopClient *) gtk_type_new(dcop_client_get_type());
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_set_server_address( const gchar *addr )
|
|
|
|
{
|
|
|
|
dcop_string_copy( dcop_client_server_address, addr );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SM DUMMY */
|
|
|
|
#include <X11/SM/SMlib.h>
|
|
|
|
static gboolean HostBasedAuthProc ( char* hostname)
|
|
|
|
{
|
|
|
|
/* we don't need any security here, as this is only a hack to
|
|
|
|
* get the protocol number we want for DCOP. We don't use the SM
|
|
|
|
* connection in any way */
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Status NewClientProc ( SmsConn c, SmPointer p, unsigned long*l, SmsCallbacks*cb, char**s )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dcop_client_registerXSM()
|
|
|
|
{
|
|
|
|
char errormsg[256];
|
|
|
|
if (!SmsInitialize ((char *)("SAMPLE-SM"), (char *)("1.0"),
|
|
|
|
NewClientProc, NULL,
|
|
|
|
HostBasedAuthProc, 256, errormsg))
|
|
|
|
{
|
|
|
|
g_error( "register xsm failed");
|
|
|
|
exit( 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* hack*/
|
|
|
|
extern int _IceLastMajorOpcode;
|
|
|
|
|
|
|
|
static void dcop_client_xsm_check()
|
|
|
|
{
|
|
|
|
if ( _IceLastMajorOpcode < 1 )
|
|
|
|
/* hack to enforce the correct ICE major opcode for DCOP*/
|
|
|
|
dcop_client_registerXSM();
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean dcop_client_attach_internal( DcopClient *client, gboolean anonymous )
|
|
|
|
{
|
|
|
|
gboolean bClearServerAddr = FALSE;
|
|
|
|
gchar *fname = 0;
|
|
|
|
const gchar *dcopSrvEnv = 0;
|
|
|
|
gchar *dcopSrv = 0;
|
|
|
|
gchar *dcopServerFileContent = 0;
|
|
|
|
glong dcopServerFileContentSize = 0;
|
|
|
|
ssize_t bytesRead = 0;
|
|
|
|
gchar *newLine = 0;
|
|
|
|
FILE *f = 0;
|
|
|
|
gchar errBuf[1024];
|
|
|
|
gint setupstat;
|
|
|
|
|
|
|
|
g_message( "dcop_client_attach\n" );
|
|
|
|
|
|
|
|
if ( dcop_client_is_attached( client ) )
|
|
|
|
dcop_client_detach( client );
|
|
|
|
|
|
|
|
dcop_client_xsm_check();
|
|
|
|
|
|
|
|
if ( ( P->major_opcode = IceRegisterForProtocolSetup( (char *)("DCOP"),
|
|
|
|
(char *)(DCOPVendorString),
|
|
|
|
(char *)(DCOPReleaseString),
|
|
|
|
1, DCOPVersions,
|
|
|
|
DCOPAuthCount,
|
|
|
|
(char **)(DCOPAuthNames),
|
|
|
|
DCOPClientAuthProcs, 0 ) ) < 0 )
|
|
|
|
{
|
|
|
|
ERR( "Communications could not be established." );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_message( "dcop: major opcode is %d\n", P->major_opcode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !dcop_client_server_address )
|
|
|
|
{
|
|
|
|
dcopSrvEnv = getenv( "DCOPSERVER" );
|
|
|
|
if ( !dcopSrvEnv || strlen( dcopSrvEnv ) == 0 )
|
|
|
|
{
|
|
|
|
char hostName[255];
|
|
|
|
|
|
|
|
fname = g_strdup( getenv( "HOME" ) );
|
|
|
|
fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + 13 );
|
|
|
|
strcat( fname, "/.DCOPserver_" );
|
|
|
|
|
|
|
|
if ( gethostname( hostName, 255 ) == 0 )
|
|
|
|
{
|
|
|
|
fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + strlen( hostName ) );
|
|
|
|
strcat( fname, hostName );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + 9 );
|
|
|
|
strcat( fname, "localhost" );
|
|
|
|
}
|
|
|
|
|
|
|
|
f = fopen( fname, "r" );
|
|
|
|
|
|
|
|
if ( f == NULL ) /* try .DCOPServer_hostname_display (for KDE > 2.0) */
|
|
|
|
{
|
|
|
|
char *i;
|
|
|
|
char *display = getenv( "DISPLAY" );
|
|
|
|
gchar *display_real = g_strdup( display );
|
|
|
|
gchar *disppos;
|
|
|
|
|
|
|
|
/* dcopserver per display, not per screen */
|
|
|
|
if ( ( disppos = strchr( display_real, '.' ) ) > strchr( display_real, ':' ) && disppos != NULL )
|
|
|
|
(*disppos) = '\0';
|
|
|
|
|
|
|
|
while((i = strchr(display_real, ':')) != NULL)
|
|
|
|
*i = '_';
|
|
|
|
|
|
|
|
fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + 1 + strlen( display_real ) );
|
|
|
|
strcat( fname, "_" );
|
|
|
|
strcat( fname, display_real );
|
|
|
|
|
|
|
|
g_free( display_real );
|
|
|
|
|
|
|
|
f = fopen( fname, "r" );
|
|
|
|
|
|
|
|
if ( f == NULL )
|
|
|
|
{
|
|
|
|
g_free( fname );
|
|
|
|
ERR( "Cannot open ~/.DCOPserver" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek( f, 0L, SEEK_END );
|
|
|
|
|
|
|
|
dcopServerFileContentSize = ftell( f );
|
|
|
|
|
|
|
|
if ( dcopServerFileContentSize == 0L )
|
|
|
|
{
|
|
|
|
g_free( fname );
|
|
|
|
ERR( "Invalid ~/.DCOPserver" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek( f, 0L, SEEK_SET );
|
|
|
|
|
|
|
|
dcopServerFileContent = (gchar *)g_malloc( dcopServerFileContentSize );
|
|
|
|
|
|
|
|
bytesRead = fread( (void *)dcopServerFileContent, sizeof(gchar), dcopServerFileContentSize, f );
|
|
|
|
|
|
|
|
if ( bytesRead != dcopServerFileContentSize )
|
|
|
|
{
|
|
|
|
g_free( fname );
|
|
|
|
g_free( dcopServerFileContent );
|
|
|
|
fclose( f );
|
|
|
|
ERR( "Cannot read ~/.DCOPserver" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
newLine = strchr( dcopServerFileContent, '\n' );
|
|
|
|
|
|
|
|
if ( newLine == NULL )
|
|
|
|
{
|
|
|
|
g_free( fname );
|
|
|
|
g_free( dcopServerFileContent );
|
|
|
|
fclose( f );
|
|
|
|
ERR( "Invalid ~/.DCOPserver" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*newLine = '\0';
|
|
|
|
|
|
|
|
fclose( f );
|
|
|
|
g_free( fname );
|
|
|
|
|
|
|
|
dcopSrv = g_strdup( dcopServerFileContent );
|
|
|
|
|
|
|
|
g_free( dcopServerFileContent );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dcopSrv = g_strdup( dcopSrvEnv );
|
|
|
|
|
|
|
|
if ( dcopSrv == NULL )
|
|
|
|
{
|
|
|
|
ERR( "Cannot determine dcop server address." );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_message( "dcop server address is : %s\n", dcopSrv );
|
|
|
|
|
|
|
|
dcop_client_server_address = dcopSrv;
|
|
|
|
|
|
|
|
bClearServerAddr = TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ( P->ice_conn = IceOpenConnection( (char *)( dcop_client_server_address ),
|
|
|
|
(IcePointer)( client ), False, P->major_opcode,
|
|
|
|
sizeof( errBuf ), errBuf ) ) == NULL )
|
|
|
|
{
|
|
|
|
if ( bClearServerAddr )
|
|
|
|
dcop_free( dcop_client_server_address );
|
|
|
|
ERR( g_strdup( errBuf ) );
|
|
|
|
dcop_client_free_error_msg = TRUE;
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
IceSetShutdownNegotiation( P->ice_conn, False );
|
|
|
|
|
|
|
|
setupstat = IceProtocolSetup( P->ice_conn, P->major_opcode, (IcePointer *)client, False,
|
|
|
|
&(P->major_version), &(P->minor_version),
|
|
|
|
&(P->vendor), &(P->release), sizeof( errBuf ), errBuf );
|
|
|
|
|
|
|
|
if ( setupstat == IceProtocolSetupFailure ||
|
|
|
|
setupstat == IceProtocolSetupIOError )
|
|
|
|
{
|
|
|
|
IceCloseConnection( P->ice_conn );
|
|
|
|
|
|
|
|
if ( bClearServerAddr )
|
|
|
|
dcop_free( dcop_client_server_address );
|
|
|
|
|
|
|
|
ERR( g_strdup( errBuf ) );
|
|
|
|
dcop_client_free_error_msg = TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if ( setupstat == IceProtocolAlreadyActive )
|
|
|
|
{
|
|
|
|
if ( bClearServerAddr )
|
|
|
|
dcop_free( dcop_client_server_address );
|
|
|
|
|
|
|
|
ERR( "Internal error in IceOpenConnection" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( IceConnectionStatus( P->ice_conn ) != IceConnectAccepted )
|
|
|
|
{
|
|
|
|
if ( bClearServerAddr )
|
|
|
|
dcop_free( dcop_client_server_address );
|
|
|
|
|
|
|
|
ERR( "DCOP server did not accept the connection" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( anonymous )
|
|
|
|
dcop_client_register_as( client, "anonymous", TRUE );
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_attach( DcopClient *client )
|
|
|
|
{
|
|
|
|
if ( !dcop_client_attach_internal( client, TRUE ) )
|
|
|
|
if ( !dcop_client_attach_internal( client, TRUE ) )
|
|
|
|
return FALSE; /* try two times!*/
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_detach( DcopClient *client )
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
g_message( "dcop_client_detach\n" );
|
|
|
|
|
|
|
|
if ( P->ice_conn )
|
|
|
|
{
|
|
|
|
IceProtocolShutdown( P->ice_conn, P->major_opcode );
|
|
|
|
status = IceCloseConnection( P->ice_conn );
|
|
|
|
if ( status != IceClosedNow )
|
|
|
|
{
|
|
|
|
ERR( "error detaching from DCOP server" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
P->ice_conn = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
P->registered = FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_is_attached( DcopClient *client )
|
|
|
|
{
|
|
|
|
if ( !P->ice_conn )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return (IceConnectionStatus( P->ice_conn ) == IceConnectAccepted );
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *dcop_client_register_as( DcopClient *client, const gchar *app_id, gboolean add_pid /* = TRUE */ )
|
|
|
|
{
|
|
|
|
gchar *result = 0;
|
|
|
|
|
|
|
|
gchar *id = g_strdup( app_id );
|
|
|
|
gchar pid[64];
|
|
|
|
gint pid_len = 0;
|
|
|
|
|
|
|
|
dcop_data *data = 0;
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
|
|
|
|
g_message( "dcop_client_register_as %s\n", app_id );
|
|
|
|
|
|
|
|
if ( dcop_client_is_registered( client ) )
|
|
|
|
dcop_client_detach( client );
|
|
|
|
|
|
|
|
if ( !dcop_client_is_attached( client ) )
|
|
|
|
if ( !dcop_client_attach_internal( client, FALSE ) )
|
|
|
|
return result; /*try two times*/
|
|
|
|
|
|
|
|
if ( add_pid )
|
|
|
|
{
|
|
|
|
pid_len = g_snprintf( pid, sizeof( pid ), "-%d", getpid() );
|
|
|
|
id = (gchar *)g_realloc( id, strlen( id ) + 1 + pid_len );
|
|
|
|
strcat( id, pid );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
g_message( "trying to register as %s\n", id );
|
|
|
|
|
|
|
|
data = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
dcop_marshal_string( data, id );
|
|
|
|
|
|
|
|
if ( dcop_client_call( client, "DCOPServer", "", "registerAs(TTQCString)", data,
|
|
|
|
&reply_type,
|
|
|
|
&reply_data ) )
|
|
|
|
{
|
|
|
|
dcop_data_reset( reply_data );
|
|
|
|
dcop_demarshal_string( reply_data, &result );
|
|
|
|
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
g_free( reply_type );
|
|
|
|
}
|
|
|
|
|
|
|
|
dcop_string_assign( P->app_id, result );
|
|
|
|
|
|
|
|
P->registered = ( P->app_id != NULL && strlen( P->app_id ) > 0 );
|
|
|
|
|
|
|
|
if ( P->registered )
|
|
|
|
g_message( "we are registered as %s\n", P->app_id );
|
|
|
|
else
|
|
|
|
g_message( "registration failed\n" );
|
|
|
|
|
|
|
|
dcop_data_deref( data );
|
|
|
|
|
|
|
|
g_free( id );
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_is_registered( DcopClient *client )
|
|
|
|
{
|
|
|
|
return P->registered;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *dcop_client_app_id( DcopClient *client )
|
|
|
|
{
|
|
|
|
return P->app_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dcop_client_socket( DcopClient *client )
|
|
|
|
{
|
|
|
|
if ( P->ice_conn )
|
|
|
|
return IceConnectionNumber( P->ice_conn );
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_send( DcopClient *client,
|
|
|
|
const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun,
|
|
|
|
dcop_data *data )
|
|
|
|
{
|
|
|
|
struct DCOPMsg *pMsg = 0;
|
|
|
|
dcop_data *hdata = 0;
|
|
|
|
gchar *func = 0;
|
|
|
|
gboolean res = TRUE;
|
|
|
|
|
|
|
|
g_message( "dcop_client_send( %s, %s, %s )\n", rem_app, rem_obj, rem_fun);
|
|
|
|
|
|
|
|
if ( !dcop_client_is_attached( client ) )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ( strcmp( P->app_id, rem_app ) == 0 )
|
|
|
|
{
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
|
|
|
|
if ( !dcop_client_receive( client, rem_app, rem_obj, rem_fun, data, &reply_type, &reply_data ) )
|
|
|
|
g_warning( "dcop failure in app %s:\n object '%s' has no function '%s'", rem_app, rem_obj, rem_fun );
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdata = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
dcop_marshal_string( hdata, P->app_id );
|
|
|
|
dcop_marshal_string( hdata, rem_app );
|
|
|
|
dcop_marshal_string( hdata, rem_obj );
|
|
|
|
|
|
|
|
func = dcop_client_normalize_function_signature( rem_fun );
|
|
|
|
dcop_marshal_string( hdata, func );
|
|
|
|
|
|
|
|
dcop_marshal_uint32( hdata, data->size );
|
|
|
|
|
|
|
|
IceGetHeader( P->ice_conn, P->major_opcode, DCOPSend, sizeof(struct DCOPMsg), struct DCOPMsg, pMsg );
|
|
|
|
|
|
|
|
pMsg->key = 1; /* DCOPSend always uses the magic key 1*/
|
|
|
|
pMsg->length += hdata->size + data->size;
|
|
|
|
|
|
|
|
IceSendData( P->ice_conn, hdata->size, hdata->ptr );
|
|
|
|
IceSendData( P->ice_conn, data->size, data->ptr );
|
|
|
|
|
|
|
|
/* IceFlush( P->ice_conn );
|
|
|
|
*/
|
|
|
|
if ( IceConnectionStatus( P->ice_conn ) != IceConnectAccepted )
|
|
|
|
res = FALSE;
|
|
|
|
|
|
|
|
g_free( func );
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean dcop_client_call_internal( DcopClient *client,
|
|
|
|
const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun,
|
|
|
|
dcop_data *data,
|
|
|
|
gchar **reply_type, dcop_data **reply_data,
|
|
|
|
gint minor_opcode )
|
|
|
|
{
|
|
|
|
gboolean success = FALSE;
|
|
|
|
struct DCOPMsg *pMsg = 0;
|
|
|
|
dcop_data *hdata = 0;
|
|
|
|
gchar *func = 0;
|
|
|
|
IceReplyWaitInfo waitInfo;
|
|
|
|
reply_struct reply;
|
|
|
|
gboolean readyRet;
|
|
|
|
IceProcessMessagesStatus status;
|
|
|
|
CARD32 old_current_key = 0;
|
|
|
|
|
|
|
|
reply_struct_init( &reply );
|
|
|
|
|
|
|
|
if ( !dcop_client_is_attached( client ) )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
old_current_key = P->current_key;
|
|
|
|
if ( !P->current_key )
|
|
|
|
P->current_key = P->key; /* no key, yet, initiate new call*/
|
|
|
|
|
|
|
|
hdata = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
dcop_marshal_string( hdata, P->app_id );
|
|
|
|
dcop_marshal_string( hdata, rem_app );
|
|
|
|
dcop_marshal_string( hdata, rem_obj );
|
|
|
|
|
|
|
|
func = dcop_client_normalize_function_signature( rem_fun );
|
|
|
|
dcop_marshal_string( hdata, func );
|
|
|
|
|
|
|
|
dcop_marshal_uint32( hdata, data->size );
|
|
|
|
|
|
|
|
IceGetHeader( P->ice_conn, P->major_opcode, minor_opcode,
|
|
|
|
sizeof(struct DCOPMsg), struct DCOPMsg, pMsg );
|
|
|
|
|
|
|
|
pMsg->key = P->current_key;
|
|
|
|
pMsg->length += hdata->size + data->size;
|
|
|
|
|
|
|
|
IceSendData( P->ice_conn, hdata->size, hdata->ptr );
|
|
|
|
IceSendData( P->ice_conn, data->size, data->ptr );
|
|
|
|
|
|
|
|
if ( IceConnectionStatus( P->ice_conn ) != IceConnectAccepted )
|
|
|
|
{
|
|
|
|
dcop_data_deref( hdata );
|
|
|
|
g_free( func );
|
|
|
|
P->current_key = old_current_key;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IceFlush( P->ice_conn );
|
|
|
|
|
|
|
|
waitInfo.sequence_of_request = IceLastSentSequenceNumber( P->ice_conn );
|
|
|
|
waitInfo.major_opcode_of_request = P->major_opcode;
|
|
|
|
waitInfo.minor_opcode_of_request = minor_opcode;
|
|
|
|
reply.reply_type = reply_type;
|
|
|
|
reply.reply_data = reply_data;
|
|
|
|
waitInfo.reply = (IcePointer)&reply;
|
|
|
|
|
|
|
|
readyRet = False;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
status = IceProcessMessages( P->ice_conn, &waitInfo, &readyRet );
|
|
|
|
if ( status == IceProcessMessagesIOError )
|
|
|
|
{
|
|
|
|
IceCloseConnection( P->ice_conn );
|
|
|
|
dcop_data_deref( hdata );
|
|
|
|
g_free( func );
|
|
|
|
P->current_key = old_current_key;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} while ( !readyRet );
|
|
|
|
|
|
|
|
dcop_data_deref( hdata );
|
|
|
|
|
|
|
|
success = reply.status == Ok;
|
|
|
|
|
|
|
|
g_free( func );
|
|
|
|
|
|
|
|
P->current_key = old_current_key;
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_call( DcopClient *client,
|
|
|
|
const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun,
|
|
|
|
dcop_data *data,
|
|
|
|
gchar **reply_type, dcop_data **reply_data )
|
|
|
|
{
|
|
|
|
return dcop_client_call_internal( client, rem_app, rem_obj, rem_fun, data,
|
|
|
|
reply_type, reply_data, DCOPCall );
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_is_application_registered( DcopClient *client, const gchar *app )
|
|
|
|
{
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
dcop_data *data = dcop_data_ref( dcop_data_new() );
|
|
|
|
gboolean res = FALSE;
|
|
|
|
|
|
|
|
dcop_marshal_string( data, app );
|
|
|
|
|
|
|
|
if ( dcop_client_call( client, "DCOPServer", "", "isApplicationRegistered(TTQCString)", data, &reply_type, &reply_data ) )
|
|
|
|
{
|
|
|
|
dcop_data_reset( reply_data );
|
|
|
|
dcop_demarshal_boolean( reply_data, &res );
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free( reply_type );
|
|
|
|
if ( reply_data )
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
GList *dcop_client_registered_applications( DcopClient *client )
|
|
|
|
{
|
|
|
|
GList *res = 0;
|
|
|
|
dcop_data *data = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
|
|
|
|
data = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
if ( dcop_client_call( client, "DCOPServer", "", "registeredApplications()", data,
|
|
|
|
&reply_type, &reply_data ) )
|
|
|
|
{
|
|
|
|
fprintf( stderr, "reply type is %s\n", reply_type );
|
|
|
|
dcop_data_reset( reply_data );
|
|
|
|
dcop_demarshal_stringlist( reply_data, &res );
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free( reply_type );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern GHashTable *object_dict;
|
|
|
|
|
|
|
|
GList *g_temp_object_list = 0;
|
|
|
|
|
|
|
|
static void dcop_client_receive_list_objects_internal( gpointer key, gpointer val, gpointer user_data )
|
|
|
|
{
|
|
|
|
gchar *nam = (gchar *)key;
|
|
|
|
DcopObject *obj = (DcopObject *)val;
|
|
|
|
DcopClient *client = (DcopClient *)user_data;
|
|
|
|
const gchar *id = DCOP_ID( obj );
|
|
|
|
|
|
|
|
if ( id && strlen( id ) > 0 )
|
|
|
|
{
|
|
|
|
if ( P->default_object &&
|
|
|
|
strcmp( id, P->default_object ) == 0 )
|
|
|
|
g_temp_object_list = g_list_append( g_temp_object_list, (gchar *)"default" );
|
|
|
|
|
|
|
|
g_temp_object_list = g_list_append( g_temp_object_list, (gchar *)id );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_receive( DcopClient *client,
|
|
|
|
const gchar *app, const gchar *obj, const gchar *fun,
|
|
|
|
dcop_data *data,
|
|
|
|
gchar **reply_type, dcop_data **reply_data )
|
|
|
|
{
|
|
|
|
DcopObject *o;
|
|
|
|
|
|
|
|
g_message( "dcop_client_receive app=%s obj=%s fun=%s\n", app, obj, fun);
|
|
|
|
|
|
|
|
if ( obj && strcmp( obj, "DCOPClient" ) == 0 )
|
|
|
|
{
|
|
|
|
if ( strcmp( fun, "objects()" ) == 0 )
|
|
|
|
{
|
|
|
|
GList *list = 0;
|
|
|
|
|
|
|
|
*reply_type = strdup( "TQCStringList" );
|
|
|
|
*reply_data = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
if ( object_dict )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
GList *it = g_list_first( object_list );
|
|
|
|
|
|
|
|
while ( it )
|
|
|
|
{
|
|
|
|
if ( it->data )
|
|
|
|
{
|
|
|
|
const gchar *id;
|
|
|
|
o = (DcopObject *)it->data;
|
|
|
|
id = DCOP_ID(o);
|
|
|
|
if ( id && strlen( id ) > 0 )
|
|
|
|
{
|
|
|
|
if ( P->default_object &&
|
|
|
|
strcmp( id, P->default_object ) == 0 )
|
|
|
|
list = g_list_append( list, (gchar *)"default" );
|
|
|
|
|
|
|
|
list = g_list_append( list, (gchar *)id );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
it = g_list_next( it );
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
g_temp_object_list = 0;
|
|
|
|
|
|
|
|
g_hash_table_foreach( object_dict, dcop_client_receive_list_objects_internal, client );
|
|
|
|
|
|
|
|
list = g_temp_object_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcop_marshal_stringlist( *reply_data, list );
|
|
|
|
/* important: only "free" (return to internal allocator) the list*/
|
|
|
|
/* itself, not it's data, as that data are either static strings*/
|
|
|
|
/* or strings already owned by someone else*/
|
|
|
|
g_list_free( list );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( CLIENT_CLASS(client)->process( client, fun, data, reply_type, reply_data ) )
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !obj || strlen( obj ) == 0 || strcmp( obj, "default" ) == 0 )
|
|
|
|
if ( P->default_object && strlen( P->default_object ) != 0 )
|
|
|
|
{
|
|
|
|
o = dcop_object_lookup( P->default_object );
|
|
|
|
if ( o && DCOP_OBJECT_CLASS(GTK_OBJECT_GET_CLASS(o))->process( o, fun, data, reply_type, reply_data ) )
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( obj && obj[ strlen( obj ) - 1 ] == '*' )
|
|
|
|
{
|
|
|
|
gchar *partial_id = (gchar *)g_malloc( strlen( obj ) - 1 );
|
|
|
|
GList *match_list = 0;
|
|
|
|
|
|
|
|
strncpy( partial_id, obj, strlen( obj ) - 1 );
|
|
|
|
|
|
|
|
match_list = dcop_object_match( partial_id );
|
|
|
|
|
|
|
|
if ( match_list )
|
|
|
|
{
|
|
|
|
GList *it = g_list_first( match_list );
|
|
|
|
|
|
|
|
while ( it )
|
|
|
|
{
|
|
|
|
o = (DcopObject *)it->data;
|
|
|
|
|
|
|
|
if ( !DCOP_OBJECT_CLASS(GTK_OBJECT_GET_CLASS(o))->process( o, fun, data, reply_type, reply_data ) )
|
|
|
|
{
|
|
|
|
g_list_free( match_list );
|
|
|
|
g_free( partial_id );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
it = g_list_next( it );
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free( match_list );
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free( partial_id );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ### proxy support
|
|
|
|
*/
|
|
|
|
o = dcop_object_lookup( obj );
|
|
|
|
if ( !o )
|
|
|
|
return FALSE;
|
|
|
|
return DCOP_OBJECT_CLASS(GTK_OBJECT_GET_CLASS(o))->process( o, fun, data, reply_type, reply_data );
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean is_ident_char( gchar x )
|
|
|
|
{ /* Avoid bug in isalnum */
|
|
|
|
return x == '_' || (x >= '0' && x <= '9') ||
|
|
|
|
(x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z');
|
|
|
|
}
|
|
|
|
|
|
|
|
gchar *dcop_client_normalize_function_signature( const gchar *fun )
|
|
|
|
{
|
|
|
|
gchar *result;
|
|
|
|
size_t len = strlen( fun );
|
|
|
|
const gchar *from;
|
|
|
|
gchar *to, *first;
|
|
|
|
gchar last;
|
|
|
|
|
|
|
|
if ( len == 0 )
|
|
|
|
return g_strdup( fun );
|
|
|
|
|
|
|
|
result = (gchar *)g_malloc( len + 1 );
|
|
|
|
|
|
|
|
from = fun;
|
|
|
|
first = to = result;
|
|
|
|
last = 0;
|
|
|
|
|
|
|
|
while ( 42 )
|
|
|
|
{
|
|
|
|
while ( *from && isspace( *from ) )
|
|
|
|
from++;
|
|
|
|
if ( last && is_ident_char( last ) && is_ident_char( *from ) )
|
|
|
|
*to++ = 0x20;
|
|
|
|
while ( *from && !isspace( *from ) )
|
|
|
|
{
|
|
|
|
last = *from++;
|
|
|
|
*to++ = last;
|
|
|
|
}
|
|
|
|
if ( !*from )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( to > first && *(to-1) == 0x20 )
|
|
|
|
to--;
|
|
|
|
*to = '\0';
|
|
|
|
result = (gchar *)g_realloc( result, (int)((long)to - (long)result) + 1 );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *dcop_client_sender_id( DcopClient *client )
|
|
|
|
{
|
|
|
|
return P->sender_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_process( DcopClient *client, const gchar *fun, dcop_data *data,
|
|
|
|
gchar **reply_type, dcop_data **reply_data )
|
|
|
|
{
|
|
|
|
return CLIENT_CLASS( client )->process( client, fun, data, reply_type, reply_data );
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_real_process( DcopClient *client, const gchar *fun, dcop_data *data,
|
|
|
|
gchar **reply_type, dcop_data **reply_data )
|
|
|
|
{
|
|
|
|
/* empty default implementation*/
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_process_socket_data( DcopClient *client )
|
|
|
|
{
|
|
|
|
IceProcessMessagesStatus status;
|
|
|
|
|
|
|
|
g_message( "dcop_client_process_socket_data\n" );
|
|
|
|
|
|
|
|
status = IceProcessMessages( P->ice_conn, 0, 0 );
|
|
|
|
|
|
|
|
g_message( "dcop_client_process_socket_data : messages processed\n" );
|
|
|
|
|
|
|
|
if ( status == IceProcessMessagesIOError )
|
|
|
|
{
|
|
|
|
IceCloseConnection( P->ice_conn );
|
|
|
|
g_message( "error receiving data from the DCOP server.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *dcop_client_error_message()
|
|
|
|
{
|
|
|
|
return dcop_client_error_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_process_internal( DcopClient *client, int opcode, CARD32 key, dcop_data *data_received, gboolean can_post );
|
|
|
|
|
|
|
|
/* don't use the glib types for args here, as this is an ICE callback (Simon)*/
|
|
|
|
void dcop_process_message( IceConn ice_conn, IcePointer client_object,
|
|
|
|
int opcode, unsigned long length, Bool swap,
|
|
|
|
IceReplyWaitInfo *replyWait,
|
|
|
|
Bool *replyWaitRet )
|
|
|
|
{
|
|
|
|
struct DCOPMsg *pMsg = 0;
|
|
|
|
DcopClient *client = (DcopClient *)client_object;
|
|
|
|
void *data_received;
|
|
|
|
dcop_data *tmp_stream = 0;
|
|
|
|
unsigned int id;
|
|
|
|
char *called_app = 0;
|
|
|
|
char *app = 0;
|
|
|
|
char *obj = 0;
|
|
|
|
char *fun = 0;
|
|
|
|
CARD32 key;
|
|
|
|
|
|
|
|
IceReadMessageHeader( ice_conn, sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg );
|
|
|
|
|
|
|
|
key = pMsg->key;
|
|
|
|
if ( P->key == 0 )
|
|
|
|
P->key = key; /* received a key from the server*/
|
|
|
|
|
|
|
|
data_received = g_malloc( length );
|
|
|
|
IceReadData( ice_conn, length, data_received );
|
|
|
|
|
|
|
|
tmp_stream = dcop_data_ref( dcop_data_new() );
|
|
|
|
dcop_data_assign( tmp_stream, (char *)data_received, length );
|
|
|
|
|
|
|
|
P->opcode = opcode;
|
|
|
|
|
|
|
|
switch ( opcode )
|
|
|
|
{
|
|
|
|
case DCOPReplyFailed:
|
|
|
|
if ( replyWait )
|
|
|
|
{
|
|
|
|
((reply_struct *)replyWait->reply)->status = Failed;
|
|
|
|
*replyWaitRet = True;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning( "dcop error: received an unexpected DCOPReplyFailed opcode.\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DCOPReply:
|
|
|
|
if ( replyWait )
|
|
|
|
{
|
|
|
|
((reply_struct *)replyWait->reply)->status = Ok;
|
|
|
|
|
|
|
|
dcop_demarshal_string( tmp_stream, &called_app );
|
|
|
|
dcop_demarshal_string( tmp_stream, &app );
|
|
|
|
dcop_demarshal_string( tmp_stream, ((reply_struct *)replyWait->reply)->reply_type );
|
|
|
|
dcop_demarshal_data( tmp_stream, ((reply_struct *)replyWait->reply)->reply_data );
|
|
|
|
|
|
|
|
*replyWaitRet = True;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning( "dcop error: received an unexpected DCOPReply.\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DCOPReplyWait:
|
|
|
|
if ( replyWait )
|
|
|
|
{
|
|
|
|
dcop_demarshal_string( tmp_stream, &called_app );
|
|
|
|
dcop_demarshal_string( tmp_stream, &app );
|
|
|
|
dcop_demarshal_uint32( tmp_stream, &id );
|
|
|
|
|
|
|
|
((reply_struct *)replyWait->reply)->reply_id = id;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning( "dcop error: received an unexpected DCOPReplyWait.\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DCOPReplyDelayed:
|
|
|
|
if ( replyWait )
|
|
|
|
{
|
|
|
|
((reply_struct *)replyWait->reply)->status = Ok;
|
|
|
|
|
|
|
|
dcop_demarshal_string( tmp_stream, &called_app );
|
|
|
|
dcop_demarshal_string( tmp_stream, &app );
|
|
|
|
dcop_demarshal_uint32( tmp_stream, &id );
|
|
|
|
dcop_demarshal_string( tmp_stream, ((reply_struct *)replyWait->reply)->reply_type );
|
|
|
|
dcop_demarshal_data( tmp_stream, ((reply_struct *)replyWait->reply)->reply_data );
|
|
|
|
|
|
|
|
if ( id != ((reply_struct *)replyWait->reply)->reply_id )
|
|
|
|
{
|
|
|
|
((reply_struct *)replyWait->reply)->status = Failed;
|
|
|
|
g_warning( "dcop error: received a wrong sequence id for DCOPReplyDelayed.\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
*replyWaitRet = True;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_message( "dcop error: received an unexpeced DCOPReplyDelayed.\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DCOPCall:
|
|
|
|
case DCOPFind:
|
|
|
|
case DCOPSend:
|
|
|
|
dcop_process_internal( client, opcode, key, tmp_stream, TRUE );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcop_data_deref( tmp_stream );
|
|
|
|
|
|
|
|
g_free( called_app );
|
|
|
|
g_free( app );
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean dcop_client_process_post_messages_internal( gpointer data )
|
|
|
|
{
|
|
|
|
DcopClient *client = DCOP_CLIENT( data );
|
|
|
|
GList *it = 0;
|
|
|
|
|
|
|
|
g_message( "dcop_client_process_post_messages_internal" );
|
|
|
|
|
|
|
|
if ( g_list_length( P->messages ) == 0 )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
it = g_list_first( P->messages );
|
|
|
|
while ( it )
|
|
|
|
{
|
|
|
|
DcopClientMessage *msg = (DcopClientMessage *)it->data;
|
|
|
|
it = g_list_next( it );
|
|
|
|
|
|
|
|
g_assert( msg );
|
|
|
|
|
|
|
|
if ( P->current_key && msg->key != P->current_key )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
P->messages = g_list_remove( P->messages, msg );
|
|
|
|
dcop_process_internal( client, msg->opcode, msg->key, msg->data, FALSE );
|
|
|
|
dcop_data_deref( msg->data );
|
|
|
|
g_free( msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( g_list_length( P->messages ) == 0 )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_process_internal( DcopClient *client, int opcode, CARD32 key, dcop_data *data_received, gboolean can_post )
|
|
|
|
{
|
|
|
|
gchar *app = 0;
|
|
|
|
gchar *obj = 0;
|
|
|
|
gchar *fun = 0;
|
|
|
|
char *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
gboolean b = FALSE;
|
|
|
|
CARD32 old_current_key = 0;
|
|
|
|
dcop_data *data = 0;
|
|
|
|
dcop_data *reply = 0;
|
|
|
|
struct DCOPMsg *pMsg = 0;
|
|
|
|
|
|
|
|
dcop_free( P->sender_id );
|
|
|
|
dcop_demarshal_string( data_received, &P->sender_id );
|
|
|
|
dcop_demarshal_string( data_received, &app );
|
|
|
|
dcop_demarshal_string( data_received, &obj );
|
|
|
|
dcop_demarshal_string( data_received, &fun );
|
|
|
|
dcop_demarshal_data( data_received, &data );
|
|
|
|
|
|
|
|
if ( can_post && P->current_key && key != P->current_key )
|
|
|
|
{
|
|
|
|
DcopClientMessage *msg = g_new( DcopClientMessage, 1 );
|
|
|
|
g_message( "posting message with key %i", key );
|
|
|
|
msg->opcode = opcode;
|
|
|
|
msg->key = key;
|
|
|
|
msg->data = dcop_data_ref( data_received );
|
|
|
|
P->messages = g_list_append( P->messages, msg );
|
|
|
|
if ( P->post_message_timer != 0 )
|
|
|
|
g_source_remove( P->post_message_timer );
|
|
|
|
P->post_message_timer = g_timeout_add( 0, dcop_client_process_post_messages_internal, client );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
old_current_key = P->current_key;
|
|
|
|
if ( opcode != DCOPSend ) /* DCOPSend doesn't change the current key*/
|
|
|
|
P->current_key = key;
|
|
|
|
|
|
|
|
if ( opcode == DCOPFind )
|
|
|
|
{
|
|
|
|
/* #### b = dcop_client_find( app, obj, fun, data, &reply_type, &reply_data ); */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
b = dcop_client_receive( client, app, obj, fun, data, &reply_type, &reply_data );
|
|
|
|
|
|
|
|
if ( opcode == DCOPSend )
|
|
|
|
{
|
|
|
|
g_free( app );
|
|
|
|
g_free( obj );
|
|
|
|
g_free( fun );
|
|
|
|
if ( data )
|
|
|
|
dcop_data_deref( data );
|
|
|
|
g_free( reply_type );
|
|
|
|
if ( reply_data )
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
P->current_key = old_current_key;
|
|
|
|
|
|
|
|
reply = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
if ( P->transaction_id )
|
|
|
|
{
|
|
|
|
dcop_marshal_string( reply, P->app_id );
|
|
|
|
dcop_marshal_string( reply, P->sender_id );
|
|
|
|
dcop_marshal_uint32( reply, (guint32)P->transaction_id );
|
|
|
|
|
|
|
|
IceGetHeader( P->ice_conn, P->major_opcode, DCOPReplyWait,
|
|
|
|
sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg );
|
|
|
|
|
|
|
|
pMsg->key = key;
|
|
|
|
pMsg->length += reply->size;
|
|
|
|
|
|
|
|
IceSendData( P->ice_conn, reply->size, reply->ptr );
|
|
|
|
|
|
|
|
dcop_data_deref( reply );
|
|
|
|
g_free( app );
|
|
|
|
g_free( obj );
|
|
|
|
g_free( fun );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !b )
|
|
|
|
{
|
|
|
|
g_warning( "dcop failure in app %s:\n object '%s' has no function '%s'", app, obj, fun );
|
|
|
|
|
|
|
|
dcop_marshal_string( reply, P->app_id );
|
|
|
|
dcop_marshal_string( reply, P->sender_id );
|
|
|
|
|
|
|
|
IceGetHeader( P->ice_conn, P->major_opcode, DCOPReplyFailed,
|
|
|
|
sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg );
|
|
|
|
pMsg->key = key;
|
|
|
|
pMsg->length += reply->size;
|
|
|
|
IceSendData( P->ice_conn, reply->size, reply->ptr );
|
|
|
|
|
|
|
|
dcop_data_deref( reply );
|
|
|
|
g_free( app );
|
|
|
|
g_free( obj );
|
|
|
|
g_free( fun );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !reply_data )
|
|
|
|
reply_data = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
dcop_marshal_string( reply, P->app_id );
|
|
|
|
dcop_marshal_string( reply, P->sender_id );
|
|
|
|
dcop_marshal_string( reply, reply_type );
|
|
|
|
dcop_marshal_uint32( reply, reply_data->size );
|
|
|
|
|
|
|
|
IceGetHeader( P->ice_conn, P->major_opcode, DCOPReply,
|
|
|
|
sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg );
|
|
|
|
|
|
|
|
pMsg->key = key;
|
|
|
|
pMsg->length += reply->size + reply_data->size;
|
|
|
|
/* use IceSendData not IceWriteData to avoid a copy. Output buffer
|
|
|
|
shouldn't need to be flushed. */
|
|
|
|
IceSendData( P->ice_conn, reply->size, reply->ptr );
|
|
|
|
IceSendData( P->ice_conn, reply_data->size, reply_data->ptr );
|
|
|
|
|
|
|
|
dcop_data_deref( reply );
|
|
|
|
g_free( app );
|
|
|
|
g_free( obj );
|
|
|
|
g_free( fun );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_set_default_object( DcopClient *client, const gchar *obj_id )
|
|
|
|
{
|
|
|
|
dcop_string_copy( P->default_object, obj_id );
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *dcop_client_default_object( DcopClient *client )
|
|
|
|
{
|
|
|
|
return P->default_object;
|
|
|
|
}
|
|
|
|
|
|
|
|
DcopClientTransaction *dcop_client_begin_transaction( DcopClient *client )
|
|
|
|
{
|
|
|
|
DcopClientTransaction *transaction = 0;
|
|
|
|
|
|
|
|
if ( P->opcode == DCOPSend )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
P->transaction = TRUE;
|
|
|
|
transaction = g_new( DcopClientTransaction, 1 );
|
|
|
|
transaction->sender_id = g_strdup( P->sender_id );
|
|
|
|
|
|
|
|
if ( !P->transaction_id )
|
|
|
|
P->transaction_id++;
|
|
|
|
|
|
|
|
transaction->id = ++(P->transaction_id);
|
|
|
|
transaction->key = P->current_key;
|
|
|
|
|
|
|
|
P->transaction_list = g_list_append( P->transaction_list, transaction );
|
|
|
|
|
|
|
|
return transaction;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint32 dcop_client_transaction_id( DcopClient *client )
|
|
|
|
{
|
|
|
|
if ( P->transaction )
|
|
|
|
return P->transaction_id;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_end_transaction( DcopClient *client, DcopClientTransaction *trans, gchar *reply_type, dcop_data *reply_data )
|
|
|
|
{
|
|
|
|
struct DCOPMsg *pMsg = 0;
|
|
|
|
dcop_data *data = 0;
|
|
|
|
|
|
|
|
if ( !trans )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( !dcop_client_is_attached( client ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( !P->transaction_list )
|
|
|
|
{
|
|
|
|
g_warning( "dcop_client_end_transaction: no pending transactions!" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !g_list_find( P->transaction_list, trans ) )
|
|
|
|
{
|
|
|
|
g_warning( "dcop_client_end_transaction: unknown transaction!" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
P->transaction_list = g_list_remove( P->transaction_list, trans );
|
|
|
|
|
|
|
|
data = dcop_data_ref( dcop_data_new() );
|
|
|
|
|
|
|
|
dcop_data_ref( reply_data );
|
|
|
|
|
|
|
|
dcop_marshal_string( data, P->app_id );
|
|
|
|
dcop_marshal_string( data, trans->sender_id );
|
|
|
|
dcop_marshal_uint32( data, (guint32)trans->id );
|
|
|
|
dcop_marshal_string( data, reply_type );
|
|
|
|
dcop_marshal_data( data, reply_data );
|
|
|
|
|
|
|
|
IceGetHeader( P->ice_conn, P->major_opcode, DCOPReplyDelayed, sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg );
|
|
|
|
|
|
|
|
pMsg->key = trans->key;
|
|
|
|
pMsg->length += data->size;
|
|
|
|
|
|
|
|
IceSendData( P->ice_conn, data->size, data->ptr );
|
|
|
|
|
|
|
|
dcop_data_deref( data );
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
|
|
|
|
g_free( trans->sender_id );
|
|
|
|
g_free( trans );
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_emit_dcop_signal( DcopClient *client,
|
|
|
|
const gchar *object, const gchar *signal, dcop_data *data )
|
|
|
|
{
|
|
|
|
gchar *normalized_signal_name = dcop_client_normalize_function_signature( signal );
|
|
|
|
gchar *signame = g_strdup( object );
|
|
|
|
|
|
|
|
signame = (gchar *)g_realloc( signame, strlen( object ) + 1 + 1 + strlen( normalized_signal_name ) );
|
|
|
|
strcat( signame, "#" );
|
|
|
|
strcat( signame, normalized_signal_name );
|
|
|
|
|
|
|
|
dcop_client_send( client, "DCOPServer", "emit", signame, data );
|
|
|
|
|
|
|
|
g_free( signame );
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_connect_dcop_signal( DcopClient *client,
|
|
|
|
const gchar *sender, const gchar *sender_obj,
|
|
|
|
const gchar *signal,
|
|
|
|
const gchar *receiver_obj, const gchar *slot,
|
|
|
|
gboolean _volatile )
|
|
|
|
{
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
dcop_data *data = dcop_data_ref( dcop_data_new() );
|
|
|
|
guint8 ivolatile = _volatile ? 1 : 0;
|
|
|
|
gchar *normalized_signame = dcop_client_normalize_function_signature( signal );
|
|
|
|
gchar *normalized_slotname = dcop_client_normalize_function_signature( slot );
|
|
|
|
guint8 result = 0;
|
|
|
|
|
|
|
|
dcop_marshal_string( data, sender );
|
|
|
|
dcop_marshal_string( data, sender_obj );
|
|
|
|
dcop_marshal_string( data, normalized_signame );
|
|
|
|
dcop_marshal_string( data, receiver_obj );
|
|
|
|
dcop_marshal_string( data, normalized_slotname );
|
|
|
|
dcop_marshal_uint8( data, ivolatile );
|
|
|
|
|
|
|
|
if ( dcop_client_call( client, "DCOPServer", "", "connectSignal(TTQCString,TTQCString,TTQCString,TTQCString,TTQCString,bool)", data, &reply_type, &reply_data ) == FALSE )
|
|
|
|
{
|
|
|
|
g_free( normalized_signame );
|
|
|
|
g_free( normalized_slotname );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( reply_type == NULL || strcmp( reply_type, "bool" ) != 0 ||
|
|
|
|
reply_data == NULL )
|
|
|
|
{
|
|
|
|
g_free( normalized_signame );
|
|
|
|
g_free( normalized_slotname );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
if ( reply_data != NULL )
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcop_data_reset( reply_data );
|
|
|
|
dcop_demarshal_uint8( reply_data, &result );
|
|
|
|
|
|
|
|
g_free( normalized_signame );
|
|
|
|
g_free( normalized_slotname );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
|
|
|
|
if ( result == 0 )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean dcop_client_disconnect_dcop_signal( DcopClient *client,
|
|
|
|
const gchar *sender, const gchar *sender_obj,
|
|
|
|
const gchar *signal,
|
|
|
|
const gchar *receiver_obj, const gchar *slot )
|
|
|
|
{
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
dcop_data *data = dcop_data_ref( dcop_data_new() );
|
|
|
|
gchar *normalized_signame = dcop_client_normalize_function_signature( signal );
|
|
|
|
gchar *normalized_slotname = dcop_client_normalize_function_signature( slot );
|
|
|
|
guint8 result = 0;
|
|
|
|
|
|
|
|
dcop_marshal_string( data, sender );
|
|
|
|
dcop_marshal_string( data, sender_obj );
|
|
|
|
dcop_marshal_string( data, normalized_signame );
|
|
|
|
dcop_marshal_string( data, receiver_obj );
|
|
|
|
dcop_marshal_string( data, normalized_slotname );
|
|
|
|
|
|
|
|
if ( dcop_client_call( client, "DCOPServer", "", "disconnectSignal(TTQCString,TTQCString,TTQCString,TTQCString,TTQCString)", data, &reply_type, &reply_data ) == FALSE )
|
|
|
|
{
|
|
|
|
g_free( normalized_signame );
|
|
|
|
g_free( normalized_slotname );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( reply_type == NULL || strcmp( reply_type, "bool" ) != 0 ||
|
|
|
|
reply_data == NULL )
|
|
|
|
{
|
|
|
|
g_free( normalized_signame );
|
|
|
|
g_free( normalized_slotname );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
if ( reply_data != NULL )
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcop_data_reset( reply_data );
|
|
|
|
dcop_demarshal_uint8( reply_data, &result );
|
|
|
|
|
|
|
|
g_free( normalized_signame );
|
|
|
|
g_free( normalized_slotname );
|
|
|
|
dcop_data_deref( data );
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
|
|
|
|
if ( result == 0 )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dcop_client_set_daemon_mode( DcopClient *client, gboolean daemon )
|
|
|
|
{
|
|
|
|
gchar *reply_type = 0;
|
|
|
|
dcop_data *reply_data = 0;
|
|
|
|
dcop_data *data = dcop_data_ref( dcop_data_new() );
|
|
|
|
guint8 idaemon = daemon ? 1 : 0;
|
|
|
|
dcop_marshal_uint8( data, idaemon );
|
|
|
|
|
|
|
|
dcop_client_call( client, "DCOPServer", "", "setDaemonMode(bool)", data, &reply_type, &reply_data );
|
|
|
|
|
|
|
|
if ( reply_data != NULL )
|
|
|
|
dcop_data_deref( reply_data );
|
|
|
|
|
|
|
|
dcop_data_deref( data );
|
|
|
|
|
|
|
|
dcop_free( reply_type );
|
|
|
|
}
|