00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#include <qobjectlist.h>
00027
#include <qmetaobject.h>
00028
#include <qvariant.h>
00029
#include <qtimer.h>
00030
#include <qintdict.h>
00031
#include <qeventloop.h>
00032
00033
00034
#include "config.h"
00035
00036
#include <config.h>
00037
#include <dcopref.h>
00038
00039
#include <sys/types.h>
00040
#include <sys/stat.h>
00041
#include <sys/file.h>
00042
#include <sys/socket.h>
00043
00044
#include <ctype.h>
00045
#include <unistd.h>
00046
#include <stdlib.h>
00047
#include <assert.h>
00048
#include <string.h>
00049
00050
#ifndef QT_CLEAN_NAMESPACE
00051
#define QT_CLEAN_NAMESPACE
00052
#endif
00053
#include <qguardedptr.h>
00054
#include <qtextstream.h>
00055
#include <qfile.h>
00056
#include <qapplication.h>
00057
#include <qsocketnotifier.h>
00058
#include <qregexp.h>
00059
00060
#include <private/qucomextra_p.h>
00061
00062
#include <dcopglobal.h>
00063
#include <dcopclient.h>
00064
#include <dcopobject.h>
00065
00066
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
00067
#include <X11/Xmd.h>
00068
#endif
00069
extern "C" {
00070
#include <KDE-ICE/ICElib.h>
00071
#include <KDE-ICE/ICEutil.h>
00072
#include <KDE-ICE/ICEmsg.h>
00073
#include <KDE-ICE/ICEproto.h>
00074
00075
00076
#include <sys/time.h>
00077
#include <sys/types.h>
00078
#include <unistd.h>
00079 }
00080
00081
extern QMap<QCString, DCOPObject *> * kde_dcopObjMap;
00082
00083
00084
00085
00086
typedef QAsciiDict<DCOPClient> client_map_t;
00087
static client_map_t *DCOPClient_CliMap = 0;
00088
00089
static
00090 client_map_t *cliMap()
00091 {
00092
if (!DCOPClient_CliMap)
00093 DCOPClient_CliMap =
new client_map_t;
00094
return DCOPClient_CliMap;
00095 }
00096
00097 DCOPClient *
DCOPClient::findLocalClient(
const QCString &_appId )
00098 {
00099
return cliMap()->find(_appId.data());
00100 }
00101
00102
static
00103
void registerLocalClient(
const QCString &_appId,
DCOPClient *client )
00104 {
00105 cliMap()->replace(_appId.data(), client);
00106 }
00107
00108
static
00109
void unregisterLocalClient(
const QCString &_appId )
00110 {
00111 client_map_t *map = cliMap();
00112 map->remove(_appId.data());
00113 }
00115
00116
template class QPtrList<DCOPObjectProxy>;
00117
template class QPtrList<DCOPClientTransaction>;
00118
template class QPtrList<_IceConn>;
00119
00120
struct DCOPClientMessage
00121 {
00122
int opcode;
00123 CARD32
key;
00124
QByteArray data;
00125 };
00126
00127
class DCOPClient::ReplyStruct
00128 {
00129
public:
00130
enum ReplyStatus { Pending, Ok, Failed };
00131 ReplyStruct() {
00132 status = Pending;
00133 replyType = 0;
00134 replyData = 0;
00135 replyId = -1;
00136 transactionId = -1;
00137 replyObject = 0;
00138 }
00139 ReplyStatus status;
00140
QCString* replyType;
00141
QByteArray* replyData;
00142
int replyId;
00143 Q_INT32 transactionId;
00144
QCString calledApp;
00145
QGuardedPtr<QObject> replyObject;
00146
QCString replySlot;
00147 };
00148
00149
class DCOPClientPrivate
00150 {
00151
public:
00152
DCOPClient *parent;
00153
QCString appId;
00154 IceConn iceConn;
00155
int majorOpcode;
00156
00157
int majorVersion, minorVersion;
00158
00159
static const char* serverAddr;
00160
QSocketNotifier *notifier;
00161
bool non_blocking_call_lock;
00162
bool registered;
00163
bool foreign_server;
00164
bool accept_calls;
00165
bool accept_calls_override;
00166
bool qt_bridge_enabled;
00167
00168
QCString senderId;
00169
QCString objId;
00170
QCString function;
00171
00172
QCString defaultObject;
00173
QPtrList<DCOPClientTransaction> *transactionList;
00174
bool transaction;
00175 Q_INT32 transactionId;
00176
int opcode;
00177
00178
00179
00180
00181
00182
00183 CARD32
key;
00184 CARD32 currentKey;
00185 CARD32 currentKeySaved;
00186
00187
QTimer postMessageTimer;
00188
QPtrList<DCOPClientMessage> messages;
00189
00190
QPtrList<DCOPClient::ReplyStruct> pendingReplies;
00191
QPtrList<DCOPClient::ReplyStruct> asyncReplyQueue;
00192
00193
struct LocalTransactionResult
00194 {
00195
QCString replyType;
00196
QByteArray replyData;
00197 };
00198
00199
QIntDict<LocalTransactionResult> localTransActionList;
00200
00201
QTimer eventLoopTimer;
00202 };
00203
00204
class DCOPClientTransaction
00205 {
00206
public:
00207 Q_INT32
id;
00208 CARD32
key;
00209
QCString senderId;
00210 };
00211
00212 QCString DCOPClient::iceauthPath()
00213 {
00214
QCString path = ::getenv(
"PATH");
00215
if (path.isEmpty())
00216 path =
"/bin:/usr/bin";
00217 path +=
":/usr/bin/X11:/usr/X11/bin:/usr/X11R6/bin";
00218
QCString fPath = strtok(path.data(),
":\b");
00219
while (!fPath.isNull())
00220 {
00221 fPath +=
"/iceauth";
00222
if (access(fPath.data(), X_OK) == 0)
00223 {
00224
return fPath;
00225 }
00226
00227 fPath = strtok(NULL,
":\b");
00228 }
00229
return 0;
00230 }
00231
00232
static QCString dcopServerFile(
const QCString &hostname,
bool old)
00233 {
00234
QCString fName = ::getenv(
"DCOPAUTHORITY");
00235
if (!old && !fName.isEmpty())
00236
return fName;
00237
00238 fName = ::getenv(
"HOME");
00239
if (fName.isEmpty())
00240 {
00241 fprintf(stderr,
"Aborting. $HOME is not set.\n");
00242 exit(1);
00243 }
00244
#ifdef Q_WS_X11
00245
QCString disp = getenv(
"DISPLAY");
00246
#elif defined(Q_WS_QWS)
00247
QCString disp = getenv(
"QWS_DISPLAY");
00248
#else
00249
QCString disp;
00250
#endif
00251
if (disp.isEmpty())
00252 disp =
"NODISPLAY";
00253
00254
int i;
00255
if((i = disp.findRev(
'.')) > disp.findRev(
':') && i >= 0)
00256 disp.truncate(i);
00257
00258
if (!old)
00259 {
00260
while( (i = disp.find(
':')) >= 0)
00261 disp[i] =
'_';
00262 }
00263
00264 fName +=
"/.DCOPserver_";
00265
if (hostname.isEmpty())
00266 {
00267
char hostName[256];
00268 hostName[0] =
'\0';
00269
if (gethostname(hostName,
sizeof(hostName)))
00270 {
00271 fName +=
"localhost";
00272 }
00273
else
00274 {
00275 hostName[
sizeof(hostName)-1] =
'\0';
00276 fName += hostName;
00277 }
00278 }
00279
else
00280 {
00281 fName += hostname;
00282 }
00283 fName +=
"_"+disp;
00284
return fName;
00285 }
00286
00287
00288
00289 QCString DCOPClient::dcopServerFile(
const QCString &hostname)
00290 {
00291 return ::dcopServerFile(hostname,
false);
00292 }
00293
00294
00295
00296 QCString DCOPClient::dcopServerFileOld(
const QCString &hostname)
00297 {
00298 return ::dcopServerFile(hostname,
true);
00299 }
00300
00301
00302
const char* DCOPClientPrivate::serverAddr = 0;
00303
00304
static void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const QByteArray& dataReceived,
bool canPost );
00305
00306
void DCOPClient::handleAsyncReply(ReplyStruct *replyStruct)
00307 {
00308
if (replyStruct->replyObject)
00309 {
00310 QObject::connect(
this, SIGNAL(callBack(
int,
const QCString&,
const QByteArray &)),
00311 replyStruct->replyObject, replyStruct->replySlot);
00312 emit callBack(replyStruct->replyId, *(replyStruct->replyType), *(replyStruct->replyData));
00313 QObject::disconnect(
this, SIGNAL(callBack(
int,
const QCString&,
const QByteArray &)),
00314 replyStruct->replyObject, replyStruct->replySlot);
00315 }
00316
delete replyStruct;
00317 }
00318
00322
static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject,
00323
int opcode,
unsigned long length, Bool ,
00324 IceReplyWaitInfo *replyWait,
00325 Bool *replyWaitRet)
00326 {
00327 DCOPMsg *pMsg = 0;
00328 DCOPClientPrivate *d = static_cast<DCOPClientPrivate *>(clientObject);
00329 DCOPClient::ReplyStruct *replyStruct = replyWait ? static_cast<DCOPClient::ReplyStruct*>(replyWait->reply) : 0;
00330
00331 IceReadMessageHeader(iceConn,
sizeof(DCOPMsg), DCOPMsg, pMsg);
00332 CARD32
key = pMsg->key;
00333
if ( d->key == 0 )
00334 d->key =
key;
00335
00336
QByteArray dataReceived( length );
00337 IceReadData(iceConn, length, dataReceived.data() );
00338
00339 d->opcode = opcode;
00340
switch (opcode ) {
00341
00342
case DCOPReplyFailed:
00343
if ( replyStruct ) {
00344 replyStruct->status = DCOPClient::ReplyStruct::Failed;
00345 replyStruct->transactionId = 0;
00346 *replyWaitRet = True;
00347
return;
00348 }
else {
00349 qWarning(
"Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!");
00350
return;
00351 }
00352
case DCOPReply:
00353
if ( replyStruct ) {
00354
QByteArray* b = replyStruct->replyData;
00355
QCString* t = replyStruct->replyType;
00356 replyStruct->status = DCOPClient::ReplyStruct::Ok;
00357 replyStruct->transactionId = 0;
00358
00359
QCString calledApp, app;
00360
QDataStream ds( dataReceived, IO_ReadOnly );
00361 ds >> calledApp >> app >> *t >> *b;
00362
00363 *replyWaitRet = True;
00364
return;
00365 }
else {
00366 qWarning(
"Very strange! got a DCOPReply opcode, but we were not waiting for a reply!");
00367
return;
00368 }
00369
case DCOPReplyWait:
00370
if ( replyStruct ) {
00371
QCString calledApp, app;
00372 Q_INT32
id;
00373
QDataStream ds( dataReceived, IO_ReadOnly );
00374 ds >> calledApp >> app >>
id;
00375 replyStruct->transactionId =
id;
00376 replyStruct->calledApp = calledApp;
00377 d->pendingReplies.append(replyStruct);
00378 *replyWaitRet = True;
00379
return;
00380 }
else {
00381 qWarning(
"Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!");
00382
return;
00383 }
00384
case DCOPReplyDelayed:
00385 {
00386
QDataStream ds( dataReceived, IO_ReadOnly );
00387
QCString calledApp, app;
00388 Q_INT32
id;
00389
00390 ds >> calledApp >> app >>
id;
00391
if (replyStruct && (
id == replyStruct->transactionId) && (calledApp == replyStruct->calledApp))
00392 {
00393 *replyWaitRet = True;
00394 }
00395
00396
for(DCOPClient::ReplyStruct *rs = d->pendingReplies.first(); rs;
00397 rs = d->pendingReplies.next())
00398 {
00399
if ((rs->transactionId ==
id) && (rs->calledApp == calledApp))
00400 {
00401 d->pendingReplies.remove();
00402
QByteArray* b = rs->replyData;
00403
QCString* t = rs->replyType;
00404 ds >> *t >> *b;
00405
00406 rs->status = DCOPClient::ReplyStruct::Ok;
00407 rs->transactionId = 0;
00408
if (!rs->replySlot.isEmpty())
00409 {
00410 d->parent->handleAsyncReply(rs);
00411 }
00412
return;
00413 }
00414 }
00415 }
00416 qWarning(
"Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!");
00417
return;
00418
case DCOPCall:
00419
case DCOPFind:
00420
case DCOPSend:
00421 DCOPProcessInternal( d, opcode, key, dataReceived,
true );
00422 }
00423 }
00424
00425
00426
void DCOPClient::processPostedMessagesInternal()
00427 {
00428
if ( d->messages.isEmpty() )
00429
return;
00430
QPtrListIterator<DCOPClientMessage> it (d->messages );
00431 DCOPClientMessage* msg ;
00432
while ( ( msg = it.current() ) ) {
00433 ++it;
00434
if ( d->currentKey && msg->key != d->currentKey )
00435
continue;
00436 d->messages.removeRef( msg );
00437 d->opcode = msg->opcode;
00438 DCOPProcessInternal( d, msg->opcode, msg->key, msg->data,
false );
00439
delete msg;
00440 }
00441
if ( !d->messages.isEmpty() )
00442 d->postMessageTimer.start( 100,
true );
00443 }
00444
00448
void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const QByteArray& dataReceived,
bool canPost )
00449 {
00450
if (!d->accept_calls && (opcode == DCOPSend))
00451
return;
00452
00453 IceConn iceConn = d->iceConn;
00454 DCOPMsg *pMsg = 0;
00455
DCOPClient *c = d->parent;
00456
QDataStream ds( dataReceived, IO_ReadOnly );
00457
00458
QCString fromApp;
00459 ds >> fromApp;
00460
if (fromApp.isEmpty())
00461
return;
00462
00463
if (!d->accept_calls)
00464 {
00465
QByteArray reply;
00466
QDataStream replyStream( reply, IO_WriteOnly );
00467
00468 replyStream << d->appId << fromApp;
00469 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
00470
sizeof(DCOPMsg), DCOPMsg, pMsg );
00471
int datalen = reply.size();
00472 pMsg->key =
key;
00473 pMsg->length += datalen;
00474 IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
00475
return;
00476 }
00477
00478
QCString app, objId, fun;
00479
QByteArray data;
00480 ds >> app >> objId >> fun >> data;
00481 d->senderId = fromApp;
00482 d->objId = objId;
00483 d->function = fun;
00484
00485
00486
00487
if ( canPost && d->currentKey &&
key != d->currentKey ) {
00488 DCOPClientMessage* msg =
new DCOPClientMessage;
00489 msg->opcode = opcode;
00490 msg->key =
key;
00491 msg->data = dataReceived;
00492 d->messages.append( msg );
00493 d->postMessageTimer.start( 0,
true );
00494
return;
00495 }
00496
00497 d->objId = objId;
00498 d->function = fun;
00499
00500
QCString replyType;
00501
QByteArray replyData;
00502
bool b;
00503 CARD32 oldCurrentKey = d->currentKey;
00504
if ( opcode != DCOPSend )
00505 d->currentKey =
key;
00506
00507
if ( opcode == DCOPFind )
00508 b = c->
find(app, objId, fun, data, replyType, replyData );
00509
else
00510 b = c->
receive( app, objId, fun, data, replyType, replyData );
00511
00512
00513
if ( opcode == DCOPSend )
00514
return;
00515
00516
if ((d->currentKey ==
key) || (oldCurrentKey != 2))
00517 d->currentKey = oldCurrentKey;
00518
00519
QByteArray reply;
00520
QDataStream replyStream( reply, IO_WriteOnly );
00521
00522 Q_INT32
id = c->
transactionId();
00523
if (
id) {
00524
00525 replyStream << d->appId << fromApp <<
id;
00526
00527 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait,
00528
sizeof(DCOPMsg), DCOPMsg, pMsg );
00529 pMsg->key =
key;
00530 pMsg->length += reply.size();
00531 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
00532
return;
00533 }
00534
00535
if ( !b ) {
00536
00537
00538 replyStream << d->appId << fromApp;
00539 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
00540
sizeof(DCOPMsg), DCOPMsg, pMsg );
00541
int datalen = reply.size();
00542 pMsg->key =
key;
00543 pMsg->length += datalen;
00544 IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
00545
return;
00546 }
00547
00548
00549 replyStream << d->appId << fromApp << replyType << replyData.size();
00550
00551
00552
00553 IceGetHeader( iceConn, d->majorOpcode,
DCOPReply,
00554
sizeof(DCOPMsg), DCOPMsg, pMsg );
00555
int datalen = reply.size() + replyData.size();
00556 pMsg->key =
key;
00557 pMsg->length += datalen;
00558
00559
00560 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
00561 IceSendData( iceConn, replyData.size(), const_cast<char *>(replyData.data()));
00562 }
00563
00564
00565
00566
static IcePoVersionRec DCOPClientVersions[] = {
00567 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
00568 };
00569
00570
00571
static DCOPClient* dcop_main_client = 0;
00572
00573 DCOPClient*
DCOPClient::mainClient()
00574 {
00575
return dcop_main_client;
00576 }
00577
00578 void DCOPClient::setMainClient(
DCOPClient* client )
00579 {
00580 dcop_main_client = client;
00581 }
00582
00583
00584 DCOPClient::DCOPClient()
00585 {
00586 d =
new DCOPClientPrivate;
00587 d->parent =
this;
00588 d->iceConn = 0L;
00589 d->majorOpcode = 0;
00590 d->key = 0;
00591 d->currentKey = 0;
00592 d->appId = 0;
00593 d->notifier = 0L;
00594 d->non_blocking_call_lock =
false;
00595 d->registered =
false;
00596 d->foreign_server =
true;
00597 d->accept_calls =
true;
00598 d->accept_calls_override =
false;
00599 d->qt_bridge_enabled =
true;
00600 d->transactionList = 0L;
00601 d->transactionId = 0;
00602 QObject::connect( &d->postMessageTimer, SIGNAL( timeout() ),
this, SLOT( processPostedMessagesInternal() ) );
00603 QObject::connect( &d->eventLoopTimer, SIGNAL( timeout() ),
this, SLOT( eventLoopTimeout() ) );
00604
00605
if ( !
mainClient() )
00606
setMainClient(
this );
00607 }
00608
00609 DCOPClient::~DCOPClient()
00610 {
00611
if (d->iceConn)
00612
if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
00613
detach();
00614
00615
if (d->registered)
00616 unregisterLocalClient( d->appId );
00617
00618
delete d->notifier;
00619
delete d->transactionList;
00620
delete d;
00621
00622
if (
mainClient() ==
this )
00623
setMainClient( 0 );
00624 }
00625
00626 void DCOPClient::setServerAddress(
const QCString &addr)
00627 {
00628
QCString env =
"DCOPSERVER=" + addr;
00629 putenv(strdup(env.data()));
00630
delete [] DCOPClientPrivate::serverAddr;
00631 DCOPClientPrivate::serverAddr = qstrdup( addr.data() );
00632 }
00633
00634 bool DCOPClient::attach()
00635 {
00636
if (!attachInternal(
true ))
00637
if (!attachInternal(
true ))
00638
return false;
00639
return true;
00640 }
00641
00642
void DCOPClient::bindToApp()
00643 {
00644
00645
00646
if (qApp) {
00647
if ( d->notifier )
00648
delete d->notifier;
00649 d->notifier =
new QSocketNotifier(
socket(),
00650 QSocketNotifier::Read, 0, 0);
00651 QObject::connect(d->notifier, SIGNAL(activated(
int)),
00652 SLOT(
processSocketData(
int)));
00653 }
00654 }
00655
00656 void DCOPClient::suspend()
00657 {
00658 assert(d->notifier);
00659 d->notifier->setEnabled(
false);
00660 }
00661
00662 void DCOPClient::resume()
00663 {
00664 assert(d->notifier);
00665 d->notifier->setEnabled(
true);
00666 }
00667
00668 bool DCOPClient::isSuspended()
const
00669
{
00670
return !d->notifier->isEnabled();
00671 }
00672
00673
#ifdef SO_PEERCRED
00674
00675
static bool peerIsUs(
int sockfd)
00676 {
00677
struct ucred cred;
00678 socklen_t siz =
sizeof(cred);
00679
if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0)
00680
return false;
00681
return (cred.uid == getuid());
00682 }
00683
#else
00684
00685
static bool isServerSocketOwnedByUser(
const char*server)
00686 {
00687
if (strncmp(server,
"local/", 6) != 0)
00688
return false;
00689
const char *path = strchr(server,
':');
00690
if (!path)
00691
return false;
00692 path++;
00693
00694
struct stat stat_buf;
00695
if (stat(path, &stat_buf) != 0)
00696
return false;
00697
00698
return (stat_buf.st_uid == getuid());
00699 }
00700
#endif
00701
00702
00703
bool DCOPClient::attachInternal(
bool registerAsAnonymous )
00704 {
00705
char errBuf[1024];
00706
00707
if (
isAttached() )
00708
detach();
00709
00710
if ((d->majorOpcode = IceRegisterForProtocolSetup(const_cast<char *>(
"DCOP"),
00711 const_cast<char *>(DCOPVendorString),
00712 const_cast<char *>(DCOPReleaseString),
00713 1, DCOPClientVersions,
00714 DCOPAuthCount,
00715 const_cast<char **>(DCOPAuthNames),
00716 DCOPClientAuthProcs, 0L)) < 0) {
00717 emit
attachFailed(QString::fromLatin1(
"Communications could not be established." ));
00718
return false;
00719 }
00720
00721
bool bClearServerAddr =
false;
00722
00723
if (!d->serverAddr) {
00724
00725
00726
QString dcopSrv;
00727 dcopSrv = ::getenv(
"DCOPSERVER");
00728
if (dcopSrv.isEmpty()) {
00729
QString fName =
dcopServerFile();
00730
QFile f(fName);
00731
if (!f.open(IO_ReadOnly)) {
00732 emit
attachFailed(QString::fromLatin1(
"Could not read network connection list.\n" )+fName);
00733
return false;
00734 }
00735
int size = QMIN( 1024, f.size() );
00736
QCString contents( size+1 );
00737
if ( f.readBlock( contents.data(), size ) != size )
00738 {
00739 qDebug(
"Error reading from %s, didn't read the expected %d bytes", fName.latin1(), size);
00740
00741 }
00742 contents[size] =
'\0';
00743
int pos = contents.find(
'\n');
00744
if ( pos == -1 )
00745 {
00746 qDebug(
"Only one line in dcopserver file !: %s", contents.data());
00747 dcopSrv = QString::fromLatin1(contents);
00748 }
00749
else
00750 {
00751 dcopSrv = QString::fromLatin1(contents.left( pos ));
00752
00753
00754
00755 }
00756 }
00757 d->serverAddr = qstrdup( const_cast<char *>(dcopSrv.latin1()) );
00758 bClearServerAddr =
true;
00759 }
00760
00761
if ((d->iceConn = IceOpenConnection(const_cast<char*>(d->serverAddr),
00762 static_cast<IcePointer>(
this), False, d->majorOpcode,
00763
sizeof(errBuf), errBuf)) == 0L) {
00764 qDebug(
"DCOPClient::attachInternal. Attach failed %s", errBuf ? errBuf :
"");
00765 d->iceConn = 0;
00766
if (bClearServerAddr) {
00767
delete [] d->serverAddr;
00768 d->serverAddr = 0;
00769 }
00770 emit
attachFailed(QString::fromLatin1( errBuf ));
00771
return false;
00772 }
00773
00774 IceSetShutdownNegotiation(d->iceConn, False);
00775
00776
int setupstat;
00777
char* vendor = 0;
00778
char* release = 0;
00779 setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode,
00780 static_cast<IcePointer>(d),
00781 False,
00782 &(d->majorVersion), &(d->minorVersion),
00783 &(vendor), &(release), 1024, errBuf);
00784
if (vendor) free(vendor);
00785
if (release) free(release);
00786
00787
if (setupstat == IceProtocolSetupFailure ||
00788 setupstat == IceProtocolSetupIOError) {
00789 IceCloseConnection(d->iceConn);
00790 d->iceConn = 0;
00791
if (bClearServerAddr) {
00792
delete [] d->serverAddr;
00793 d->serverAddr = 0;
00794 }
00795 emit
attachFailed(QString::fromLatin1( errBuf ));
00796
return false;
00797 }
else if (setupstat == IceProtocolAlreadyActive) {
00798
if (bClearServerAddr) {
00799
delete [] d->serverAddr;
00800 d->serverAddr = 0;
00801 }
00802
00803 emit
attachFailed(QString::fromLatin1(
"internal error in IceOpenConnection" ));
00804
return false;
00805 }
00806
00807
00808
if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) {
00809
if (bClearServerAddr) {
00810
delete [] d->serverAddr;
00811 d->serverAddr = 0;
00812 }
00813 emit
attachFailed(QString::fromLatin1(
"DCOP server did not accept the connection." ));
00814
return false;
00815 }
00816
00817
#ifdef SO_PEERCRED
00818
d->foreign_server = !peerIsUs(
socket());
00819
#else
00820
d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr);
00821
#endif
00822
if (!d->accept_calls_override)
00823 d->accept_calls = !d->foreign_server;
00824
00825 bindToApp();
00826
00827
if ( registerAsAnonymous )
00828
registerAs(
"anonymous",
true );
00829
00830
return true;
00831 }
00832
00833
00834 bool DCOPClient::detach()
00835 {
00836
int status;
00837
00838
if (d->iceConn) {
00839 IceProtocolShutdown(d->iceConn, d->majorOpcode);
00840 status = IceCloseConnection(d->iceConn);
00841
if (status != IceClosedNow)
00842
return false;
00843
else
00844 d->iceConn = 0L;
00845 }
00846
00847
if (d->registered)
00848 unregisterLocalClient(d->appId);
00849
00850
delete d->notifier;
00851 d->notifier = 0L;
00852 d->registered =
false;
00853 d->foreign_server =
true;
00854
return true;
00855 }
00856
00857 bool DCOPClient::isAttached()
const
00858
{
00859
if (!d->iceConn)
00860
return false;
00861
00862
return (IceConnectionStatus(d->iceConn) == IceConnectAccepted);
00863 }
00864
00865 bool DCOPClient::isAttachedToForeignServer()
const
00866
{
00867
return isAttached() && d->foreign_server;
00868 }
00869
00870 bool DCOPClient::acceptCalls()
const
00871
{
00872
return isAttached() && d->accept_calls;
00873 }
00874
00875 void DCOPClient::setAcceptCalls(
bool b)
00876 {
00877 d->accept_calls = b;
00878 d->accept_calls_override =
true;
00879 }
00880
00881 bool DCOPClient::qtBridgeEnabled()
00882 {
00883
return d->qt_bridge_enabled;
00884 }
00885
00886 void DCOPClient::setQtBridgeEnabled(
bool b)
00887 {
00888 d->qt_bridge_enabled = b;
00889 }
00890
00891 QCString DCOPClient::registerAs(
const QCString &appId,
bool addPID )
00892 {
00893
QCString result;
00894
00895
QCString _appId = appId;
00896
00897
if (addPID) {
00898
QCString pid;
00899 pid.sprintf(
"-%d", getpid());
00900 _appId = _appId + pid;
00901 }
00902
00903
if( d->appId == _appId )
00904
return d->appId;
00905
00906
#if 0 // no need to detach, dcopserver can handle renaming
00907
00908
if (
isRegistered() ) {
00909
detach();
00910 }
00911
#endif
00912
00913
if ( !
isAttached() ) {
00914
if (!attachInternal(
false ))
00915
if (!attachInternal(
false ))
00916
return result;
00917 }
00918
00919
00920
QCString replyType;
00921
QByteArray data, replyData;
00922
QDataStream arg( data, IO_WriteOnly );
00923 arg << _appId;
00924
if (
call(
"DCOPServer",
"",
"registerAs(QCString)", data, replyType, replyData ) ) {
00925
QDataStream reply( replyData, IO_ReadOnly );
00926 reply >> result;
00927 }
00928
00929 d->appId = result;
00930 d->registered = !result.isNull();
00931
00932
if (d->registered)
00933 registerLocalClient( d->appId,
this );
00934
00935
return result;
00936 }
00937
00938 bool DCOPClient::isRegistered()
const
00939
{
00940
return d->registered;
00941 }
00942
00943
00944 QCString DCOPClient::appId()
const
00945
{
00946
return d->appId;
00947 }
00948
00949
00950 int DCOPClient::socket()
const
00951
{
00952
if (d->iceConn)
00953
return IceConnectionNumber(d->iceConn);
00954
else
00955
return 0;
00956 }
00957
00958
static inline bool isIdentChar(
char x )
00959 {
00960
return x ==
'_' || (x >=
'0' && x <=
'9') ||
00961 (x >=
'a' && x <= 'z') || (x >=
'A' && x <=
'Z');
00962 }
00963
00964 QCString DCOPClient::normalizeFunctionSignature(
const QCString& fun ) {
00965
if ( fun.isEmpty() )
00966
return fun.copy();
00967
QCString result( fun.size() );
00968
char *from = fun.data();
00969
char *to = result.data();
00970
char *first = to;
00971
char last = 0;
00972
while (
true ) {
00973
while ( *from && isspace(*from) )
00974 from++;
00975
if ( last && isIdentChar( last ) && isIdentChar( *from ) )
00976 *to++ = 0x20;
00977
while ( *from && !isspace(*from) ) {
00978 last = *from++;
00979 *to++ = last;
00980 }
00981
if ( !*from )
00982
break;
00983 }
00984
if ( to > first && *(to-1) == 0x20 )
00985 to--;
00986 *to =
'\0';
00987 result.resize( (
int)((
long)to - (
long)result.data()) + 1 );
00988
return result;
00989 }
00990
00991
00992 QCString DCOPClient::senderId()
const
00993
{
00994
return d->senderId;
00995 }
00996
00997
00998 bool DCOPClient::send(
const QCString &remApp,
const QCString &remObjId,
00999
const QCString &remFun,
const QByteArray &data)
01000 {
01001
if (remApp.isEmpty())
01002
return false;
01003
DCOPClient *localClient =
findLocalClient( remApp );
01004
01005
if ( localClient ) {
01006
bool saveTransaction = d->transaction;
01007 Q_INT32 saveTransactionId = d->transactionId;
01008
QCString saveSenderId = d->senderId;
01009
01010 d->senderId = 0;
01011
QCString replyType;
01012
QByteArray replyData;
01013 (
void) localClient->
receive( remApp, remObjId, remFun, data, replyType, replyData );
01014
01015 d->transaction = saveTransaction;
01016 d->transactionId = saveTransactionId;
01017 d->senderId = saveSenderId;
01018
01019
01020
01021
01022
return true;
01023 }
01024
01025
if ( !
isAttached() )
01026
return false;
01027
01028
01029 DCOPMsg *pMsg;
01030
01031
QByteArray ba;
01032
QDataStream ds(ba, IO_WriteOnly);
01033 ds << d->appId << remApp << remObjId <<
normalizeFunctionSignature(remFun) << data.size();
01034
01035 IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend,
01036
sizeof(DCOPMsg), DCOPMsg, pMsg);
01037
01038 pMsg->key = 1;
01039
int datalen = ba.size() + data.size();
01040 pMsg->length += datalen;
01041
01042 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
01043 IceSendData( d->iceConn, data.size(), const_cast<char *>(data.data()) );
01044
01045
01046
01047
if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
01048
return false;
01049
else
01050
return true;
01051 }
01052
01053 bool DCOPClient::send(
const QCString &remApp,
const QCString &remObjId,
01054
const QCString &remFun,
const QString &data)
01055 {
01056
QByteArray ba;
01057
QDataStream ds(ba, IO_WriteOnly);
01058 ds << data;
01059
return send(remApp, remObjId, remFun, ba);
01060 }
01061
01062 bool DCOPClient::findObject(
const QCString &remApp,
const QCString &remObj,
01063
const QCString &remFun,
const QByteArray &data,
01064
QCString &foundApp,
QCString &foundObj,
01065
bool useEventLoop)
01066 {
01067
return findObject( remApp, remObj, remFun, data, foundApp, foundObj, useEventLoop, -1 );
01068 }
01069
01070 bool DCOPClient::findObject(
const QCString &remApp,
const QCString &remObj,
01071
const QCString &remFun,
const QByteArray &data,
01072
QCString &foundApp,
QCString &foundObj,
01073
bool useEventLoop,
int timeout)
01074 {
01075
QCStringList appList;
01076
QCString app = remApp;
01077
if (app.isEmpty())
01078 app =
"*";
01079
01080 foundApp = 0;
01081 foundObj = 0;
01082
01083
if (app[app.length()-1] ==
'*')
01084 {
01085
01086
01087
01088
int len = app.length()-1;
01089
QCStringList apps=
registeredApplications();
01090
for( QCStringList::ConstIterator it = apps.begin();
01091 it != apps.end();
01092 ++it)
01093 {
01094
if ( strncmp( (*it).data(), app.data(), len) == 0)
01095 appList.append(*it);
01096 }
01097 }
01098
else
01099 {
01100 appList.append(app);
01101 }
01102
01103
01104
for(
int phase=1; phase <= 2; phase++)
01105 {
01106
for( QCStringList::ConstIterator it = appList.begin();
01107 it != appList.end();
01108 ++it)
01109 {
01110
QCString remApp = *it;
01111
QCString replyType;
01112
QByteArray replyData;
01113
bool result =
false;
01114
DCOPClient *localClient =
findLocalClient( remApp );
01115
01116
if ( (phase == 1) && localClient ) {
01117
01118
bool saveTransaction = d->transaction;
01119 Q_INT32 saveTransactionId = d->transactionId;
01120
QCString saveSenderId = d->senderId;
01121
01122 d->senderId = 0;
01123 result = localClient->
find( remApp, remObj, remFun, data, replyType, replyData );
01124
01125 Q_INT32
id = localClient->
transactionId();
01126
if (
id) {
01127
01128
do {
01129 QApplication::eventLoop()->processEvents( QEventLoop::WaitForMore);
01130 }
while( !localClient->
isLocalTransactionFinished(
id, replyType, replyData));
01131 result =
true;
01132 }
01133 d->transaction = saveTransaction;
01134 d->transactionId = saveTransactionId;
01135 d->senderId = saveSenderId;
01136 }
01137
else if ((phase == 2) && !localClient)
01138 {
01139
01140 result = callInternal(remApp, remObj, remFun, data,
01141 replyType, replyData, useEventLoop, timeout, DCOPFind);
01142 }
01143
01144
if (result)
01145 {
01146
if (replyType ==
"DCOPRef")
01147 {
01148
DCOPRef ref;
01149
QDataStream reply( replyData, IO_ReadOnly );
01150 reply >> ref;
01151
01152
if (ref.app() == remApp)
01153 {
01154
01155 foundApp = ref.app();
01156 foundObj = ref.object();
01157
return true;
01158 }
01159 }
01160 }
01161 }
01162 }
01163
return false;
01164 }
01165
01166 bool DCOPClient::process(
const QCString &,
const QByteArray &,
01167
QCString&,
QByteArray &)
01168 {
01169
return false;
01170 }
01171
01172 bool DCOPClient::isApplicationRegistered(
const QCString& remApp)
01173 {
01174
QCString replyType;
01175
QByteArray data, replyData;
01176
QDataStream arg( data, IO_WriteOnly );
01177 arg << remApp;
01178
int result =
false;
01179
if (
call(
"DCOPServer",
"",
"isApplicationRegistered(QCString)", data, replyType, replyData ) ) {
01180
QDataStream reply( replyData, IO_ReadOnly );
01181 reply >> result;
01182 }
01183
return result;
01184 }
01185
01186 QCStringList DCOPClient::registeredApplications()
01187 {
01188
QCString replyType;
01189
QByteArray data, replyData;
01190
QCStringList result;
01191
if (
call(
"DCOPServer",
"",
"registeredApplications()", data, replyType, replyData ) ) {
01192
QDataStream reply( replyData, IO_ReadOnly );
01193 reply >> result;
01194 }
01195
return result;
01196 }
01197
01198 QCStringList DCOPClient::remoteObjects(
const QCString& remApp,
bool *ok )
01199 {
01200
QCString replyType;
01201
QByteArray data, replyData;
01202
QCStringList result;
01203
if ( ok )
01204 *ok =
false;
01205
if (
call( remApp,
"DCOPClient",
"objects()", data, replyType, replyData ) ) {
01206
QDataStream reply( replyData, IO_ReadOnly );
01207 reply >> result;
01208
if ( ok )
01209 *ok =
true;
01210 }
01211
return result;
01212 }
01213
01214 QCStringList DCOPClient::remoteInterfaces(
const QCString& remApp,
const QCString& remObj,
bool *ok )
01215 {
01216
QCString replyType;
01217
QByteArray data, replyData;
01218
QCStringList result;
01219
if ( ok )
01220 *ok =
false;
01221
if (
call( remApp, remObj,
"interfaces()", data, replyType, replyData ) && replyType ==
"QCStringList") {
01222
QDataStream reply( replyData, IO_ReadOnly );
01223 reply >> result;
01224
if ( ok )
01225 *ok =
true;
01226 }
01227
return result;
01228 }
01229
01230 QCStringList DCOPClient::remoteFunctions(
const QCString& remApp,
const QCString& remObj,
bool *ok )
01231 {
01232
QCString replyType;
01233
QByteArray data, replyData;
01234
QCStringList result;
01235
if ( ok )
01236 *ok =
false;
01237
if (
call( remApp, remObj,
"functions()", data, replyType, replyData ) && replyType ==
"QCStringList") {
01238
QDataStream reply( replyData, IO_ReadOnly );
01239 reply >> result;
01240
if ( ok )
01241 *ok =
true;
01242 }
01243
return result;
01244 }
01245
01246 void DCOPClient::setNotifications(
bool enabled)
01247 {
01248
QByteArray data;
01249
QDataStream ds(data, IO_WriteOnly);
01250 ds << static_cast<Q_INT8>(enabled);
01251
01252
QCString replyType;
01253
QByteArray reply;
01254
if (!
call(
"DCOPServer",
"",
"setNotifications( bool )", data, replyType, reply))
01255 qWarning(
"I couldn't enable notifications at the dcopserver!");
01256 }
01257
01258 void DCOPClient::setDaemonMode(
bool daemonMode )
01259 {
01260
QByteArray data;
01261
QDataStream ds(data, IO_WriteOnly);
01262 ds << static_cast<Q_INT8>( daemonMode );
01263
01264
QCString replyType;
01265
QByteArray reply;
01266
if (!
call(
"DCOPServer",
"",
"setDaemonMode(bool)", data, replyType, reply))
01267 qWarning(
"I couldn't enable daemon mode at the dcopserver!");
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277
static void fillQtObjects(
QCStringList& l,
QObject* o,
QCString path )
01278 {
01279
if ( !path.isEmpty() )
01280 path +=
'/';
01281
01282
int unnamed = 0;
01283
const QObjectList *list = o ? o->children() :
QObject::objectTrees();
01284
if ( list ) {
01285 QObjectListIt it( *list );
01286
QObject *obj;
01287
while ( (obj=it.current()) ) {
01288 ++it;
01289
QCString n = obj->name();
01290
if ( n ==
"unnamed" || n.isEmpty() )
01291 {
01292 n.sprintf(
"%p", (
void *) obj);
01293 n =
QString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(n).latin1();
01294 }
01295
QCString fn = path + n;
01296 l.append( fn );
01297
if ( obj->children() )
01298 fillQtObjects( l, obj, fn );
01299 }
01300 }
01301 }
01302
01303
namespace
01304
{
01305
struct O
01306 {
01307 O(): o(0) {}
01308 O (
const QCString& str,
QObject* obj ):s(str), o(obj){}
01309
QCString s;
01310
QObject* o;
01311 };
01312 }
01313
01314
static void fillQtObjectsEx(
QValueList<O>& l,
QObject* o,
QCString path )
01315 {
01316
if ( !path.isEmpty() )
01317 path +=
'/';
01318
01319
int unnamed = 0;
01320
const QObjectList *list = o ? o->children() :
QObject::objectTrees();
01321
if ( list ) {
01322 QObjectListIt it( *list );
01323
QObject *obj;
01324
while ( (obj=it.current()) ) {
01325 ++it;
01326
QCString n = obj->name();
01327
if ( n ==
"unnamed" || n.isEmpty() )
01328 {
01329 n.sprintf(
"%p", (
void *) obj);
01330 n =
QString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(n).latin1();
01331 }
01332
QCString fn = path + n;
01333 l.append( O( fn, obj ) );
01334
if ( obj->children() )
01335 fillQtObjectsEx( l, obj, fn );
01336 }
01337 }
01338 }
01339
01340
01341
static QObject* findQtObject(
QCString id )
01342 {
01343
QRegExp expr(
id );
01344
QValueList<O> l;
01345 fillQtObjectsEx( l, 0,
"qt" );
01346
01347
QObject* firstContains = 0L;
01348
for (
QValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
01349
if ( (*it).s ==
id )
01350
return (*it).o;
01351
if ( !firstContains && (*it).s.contains( expr ) ) {
01352 firstContains = (*it).o;
01353 }
01354 }
01355
return firstContains;
01356 }
01357
01358
static QCStringList findQtObjects(
QCString id )
01359 {
01360
QRegExp expr(
id );
01361
QValueList<O> l;
01362 fillQtObjectsEx( l, 0,
"qt" );
01363
QCStringList result;
01364
for (
QValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
01365
if ( (*it).s.contains( expr ) )
01366 result << (*it).s;
01367 }
01368
return result;
01369 }
01370
01371
static bool receiveQtObject(
const QCString &objId,
const QCString &fun,
const QByteArray &data,
01372
QCString& replyType,
QByteArray &replyData)
01373 {
01374
if ( objId ==
"qt" ) {
01375
if ( fun ==
"interfaces()" ) {
01376 replyType =
"QCStringList";
01377
QDataStream reply( replyData, IO_WriteOnly );
01378
QCStringList l;
01379 l <<
"DCOPObject";
01380 l <<
"Qt";
01381 reply << l;
01382
return true;
01383 }
else if ( fun ==
"functions()" ) {
01384 replyType =
"QCStringList";
01385
QDataStream reply( replyData, IO_WriteOnly );
01386
QCStringList l;
01387 l <<
"QCStringList functions()";
01388 l <<
"QCStringList interfaces()";
01389 l <<
"QCStringList objects()";
01390 l <<
"QCStringList find(QCString)";
01391 reply << l;
01392
return true;
01393 }
else if ( fun ==
"objects()" ) {
01394 replyType =
"QCStringList";
01395
QDataStream reply( replyData, IO_WriteOnly );
01396
QCStringList l;
01397 fillQtObjects( l, 0,
"qt" );
01398 reply << l;
01399
return true;
01400 }
else if ( fun ==
"find(QCString)" ) {
01401
QDataStream ds( data, IO_ReadOnly );
01402
QCString id;
01403 ds >>
id ;
01404 replyType =
"QCStringList";
01405
QDataStream reply( replyData, IO_WriteOnly );
01406 reply << findQtObjects(
id ) ;
01407
return true;
01408 }
01409 }
else if ( objId.left(3) ==
"qt/" ) {
01410
QObject* o = findQtObject( objId );
01411
if ( !o )
01412
return false;
01413
if ( fun ==
"functions()" ) {
01414 replyType =
"QCStringList";
01415
QDataStream reply( replyData, IO_WriteOnly );
01416
QCStringList l;
01417 l <<
"QCStringList functions()";
01418 l <<
"QCStringList interfaces()";
01419 l <<
"QCStringList properties()";
01420 l <<
"bool setProperty(QCString,QVariant)";
01421 l <<
"QVariant property(QCString)";
01422
QStrList lst = o->metaObject()->slotNames(
true );
01423
int i = 0;
01424
for (
QPtrListIterator<char> it( lst ); it.current(); ++it ) {
01425
if ( o->metaObject()->slot( i++,
true )->access != QMetaData::Public )
01426
continue;
01427
QCString slot = it.current();
01428
if ( slot.contains(
"()" ) ) {
01429 slot.prepend(
"void ");
01430 l << slot;
01431 }
01432 }
01433 reply << l;
01434
return true;
01435 }
else if ( fun ==
"interfaces()" ) {
01436 replyType =
"QCStringList";
01437
QDataStream reply( replyData, IO_WriteOnly );
01438
QCStringList l;
01439
QMetaObject *meta = o->metaObject();
01440
while ( meta ) {
01441 l.prepend( meta->
className() );
01442 meta = meta->
superClass();
01443 }
01444 reply << l;
01445
return true;
01446 }
else if ( fun ==
"properties()" ) {
01447 replyType =
"QCStringList";
01448
QDataStream reply( replyData, IO_WriteOnly );
01449
QCStringList l;
01450
QStrList lst = o->metaObject()->propertyNames(
true );
01451
for (
QPtrListIterator<char> it( lst ); it.current(); ++it ) {
01452
QMetaObject *mo = o->metaObject();
01453
const QMetaProperty* p = mo->
property( mo->findProperty( it.current(),
true ),
true );
01454
if ( !p )
01455
continue;
01456
QCString prop = p->type();
01457 prop +=
' ';
01458 prop += p->name();
01459
if ( !p->writable() )
01460 prop +=
" readonly";
01461 l << prop;
01462 }
01463 reply << l;
01464
return true;
01465 }
else if ( fun ==
"property(QCString)" ) {
01466 replyType =
"QVariant";
01467
QDataStream ds( data, IO_ReadOnly );
01468
QCString name;
01469 ds >>
name ;
01470
QVariant result = o->property( name );
01471
QDataStream reply( replyData, IO_WriteOnly );
01472 reply << result;
01473
return true;
01474 }
else if ( fun ==
"setProperty(QCString,QVariant)" ) {
01475
QDataStream ds( data, IO_ReadOnly );
01476
QCString name;
01477
QVariant value;
01478 ds >>
name >> value;
01479 replyType =
"bool";
01480
QDataStream reply( replyData, IO_WriteOnly );
01481 reply << (Q_INT8) o->setProperty( name, value );
01482
return true;
01483 }
else {
01484
int slot = o->metaObject()->findSlot( fun,
true );
01485
if ( slot != -1 ) {
01486 replyType =
"void";
01487 QUObject uo[ 1 ];
01488 o->qt_invoke( slot, uo );
01489
return true;
01490 }
01491 }
01492
01493
01494 }
01495
return false;
01496 }
01497
01498
01499
01500
01501
01502
01503
01504
01505
bool DCOPClient::receive(
const QCString &,
const QCString &objId,
01506
const QCString &fun,
const QByteArray &data,
01507
QCString& replyType,
QByteArray &replyData)
01508 {
01509 d->transaction =
false;
01510
if ( objId ==
"DCOPClient" ) {
01511
if ( fun ==
"objects()" ) {
01512 replyType =
"QCStringList";
01513
QDataStream reply( replyData, IO_WriteOnly );
01514
QCStringList l;
01515
if (d->qt_bridge_enabled)
01516 {
01517 l <<
"qt";
01518 }
01519
if ( kde_dcopObjMap ) {
01520
QMap<QCString, DCOPObject *>::ConstIterator it( kde_dcopObjMap->begin());
01521
for (; it != kde_dcopObjMap->end(); ++it) {
01522
if ( !it.key().isEmpty() ) {
01523
if ( it.key() == d->defaultObject )
01524 l <<
"default";
01525 l << it.key();
01526 }
01527 }
01528 }
01529 reply << l;
01530
return true;
01531 }
01532 }
01533
01534
if ( objId.isEmpty() || objId ==
"DCOPClient" ) {
01535
if ( fun ==
"applicationRegistered(QCString)" ) {
01536
QDataStream ds( data, IO_ReadOnly );
01537
QCString r;
01538 ds >> r;
01539 emit
applicationRegistered( r );
01540
return true;
01541 }
else if ( fun ==
"applicationRemoved(QCString)" ) {
01542
QDataStream ds( data, IO_ReadOnly );
01543
QCString r;
01544 ds >> r;
01545 emit
applicationRemoved( r );
01546
return true;
01547 }
01548
01549
if (
process( fun, data, replyType, replyData ) )
01550
return true;
01551
01552
01553 }
else if (d->qt_bridge_enabled &&
01554 (objId ==
"qt" || objId.left(3) ==
"qt/") ) {
01555
return receiveQtObject( objId, fun, data, replyType, replyData );
01556 }
01557
01558
if ( objId.isEmpty() || objId ==
"default" ) {
01559
if ( !d->defaultObject.isEmpty() &&
DCOPObject::hasObject( d->defaultObject ) ) {
01560
DCOPObject *objPtr =
DCOPObject::find( d->defaultObject );
01561 objPtr->
setCallingDcopClient(
this);
01562
if (objPtr->
process(fun, data, replyType, replyData))
01563
return true;
01564 }
01565
01566
01567 }
01568
01569
if (!objId.isEmpty() && objId[objId.length()-1] ==
'*') {
01570
01571
01572
QPtrList<DCOPObject> matchList =
01573
DCOPObject::match(objId.left(objId.length()-1));
01574
for (
DCOPObject *objPtr = matchList.first();
01575 objPtr != 0L; objPtr = matchList.next()) {
01576 objPtr->
setCallingDcopClient(
this);
01577
if (!objPtr->
process(fun, data, replyType, replyData))
01578
return false;
01579 }
01580
return true;
01581 }
else if (!
DCOPObject::hasObject(objId)) {
01582
if ( DCOPObjectProxy::proxies ) {
01583
for (
QPtrListIterator<DCOPObjectProxy> it( *DCOPObjectProxy::proxies ); it.current(); ++it ) {
01584
01585
if ( it.current()->process( objId, fun, data, replyType, replyData ) )
01586
return true;
01587 }
01588 }
01589
return false;
01590
01591 }
else {
01592
DCOPObject *objPtr =
DCOPObject::find(objId);
01593 objPtr->
setCallingDcopClient(
this);
01594
if (!objPtr->
process(fun, data, replyType, replyData)) {
01595
01596
return false;
01597 }
01598 }
01599
01600
return true;
01601 }
01602
01603
01604
01605
01606
static bool findResultOk(
QCString &replyType,
QByteArray &replyData)
01607 {
01608 Q_INT8 success;
01609
if (replyType !=
"bool")
return false;
01610
01611
QDataStream reply( replyData, IO_ReadOnly );
01612 reply >> success;
01613
01614
if (!success)
return false;
01615
return true;
01616 }
01617
01618
01619
01620
static bool findSuccess(
const QCString &app,
const QCString objId,
QCString &replyType,
QByteArray &replyData)
01621 {
01622
DCOPRef ref(app, objId);
01623 replyType =
"DCOPRef";
01624
01625 replyData =
QByteArray();
01626
QDataStream final_reply( replyData, IO_WriteOnly );
01627 final_reply << ref;
01628
return true;
01629 }
01630
01631
01632
bool DCOPClient::find(
const QCString &app,
const QCString &objId,
01633
const QCString &fun,
const QByteArray &data,
01634
QCString& replyType,
QByteArray &replyData)
01635 {
01636 d->transaction =
false;
01637
if ( !app.isEmpty() && app != d->appId && app[app.length()-1] !=
'*') {
01638 qWarning(
"WEIRD! we somehow received a DCOP message w/a different appId");
01639
return false;
01640 }
01641
01642
if (objId.isEmpty() || objId[objId.length()-1] !=
'*')
01643 {
01644
if (fun.isEmpty())
01645 {
01646
if (objId.isEmpty() ||
DCOPObject::hasObject(objId))
01647
return findSuccess(app, objId, replyType, replyData);
01648
return false;
01649 }
01650
01651
if (receive(app, objId, fun, data, replyType, replyData))
01652 {
01653
if (findResultOk(replyType, replyData))
01654
return findSuccess(app, objId, replyType, replyData);
01655 }
01656 }
01657
else {
01658
01659
01660
QPtrList<DCOPObject> matchList =
01661
DCOPObject::match(objId.left(objId.length()-1));
01662
for (
DCOPObject *objPtr = matchList.first();
01663 objPtr != 0L; objPtr = matchList.next())
01664 {
01665 replyType = 0;
01666 replyData =
QByteArray();
01667
if (fun.isEmpty())
01668
return findSuccess(app, objPtr->
objId(), replyType, replyData);
01669 objPtr->
setCallingDcopClient(
this);
01670
if (objPtr->
process(fun, data, replyType, replyData))
01671
if (findResultOk(replyType, replyData))
01672
return findSuccess(app, objPtr->
objId(), replyType, replyData);
01673 }
01674 }
01675
return false;
01676 }
01677
01678
01679 bool DCOPClient::call(
const QCString &remApp,
const QCString &remObjId,
01680
const QCString &remFun,
const QByteArray &data,
01681
QCString& replyType,
QByteArray &replyData,
01682
bool useEventLoop)
01683 {
01684
return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, -1 );
01685 }
01686
01687 bool DCOPClient::call(
const QCString &remApp,
const QCString &remObjId,
01688
const QCString &remFun,
const QByteArray &data,
01689
QCString& replyType,
QByteArray &replyData,
01690
bool useEventLoop,
int timeout)
01691 {
01692
if (remApp.isEmpty())
01693
return false;
01694
DCOPClient *localClient =
findLocalClient( remApp );
01695
01696
if ( localClient ) {
01697
bool saveTransaction = d->transaction;
01698 Q_INT32 saveTransactionId = d->transactionId;
01699
QCString saveSenderId = d->senderId;
01700
01701 d->senderId = 0;
01702
bool b = localClient->
receive( remApp, remObjId, remFun, data, replyType, replyData );
01703
01704 Q_INT32
id = localClient->
transactionId();
01705
if (
id) {
01706
01707
do {
01708 QApplication::eventLoop()->processEvents( QEventLoop::WaitForMore);
01709 }
while( !localClient->
isLocalTransactionFinished(
id, replyType, replyData));
01710 b =
true;
01711 }
01712 d->transaction = saveTransaction;
01713 d->transactionId = saveTransactionId;
01714 d->senderId = saveSenderId;
01715
return b;
01716 }
01717
01718
return callInternal(remApp, remObjId, remFun, data,
01719 replyType, replyData, useEventLoop, timeout, DCOPCall);
01720 }
01721
01722
void DCOPClient::asyncReplyReady()
01723 {
01724
while( d->asyncReplyQueue.count() )
01725 {
01726 ReplyStruct *replyStruct = d->asyncReplyQueue.take(0);
01727 handleAsyncReply(replyStruct);
01728 }
01729 }
01730
01731 int DCOPClient::callAsync(
const QCString &remApp,
const QCString &remObjId,
01732
const QCString &remFun,
const QByteArray &data,
01733
QObject *callBackObj,
const char *callBackSlot)
01734 {
01735
QCString replyType;
01736
QByteArray replyData;
01737
01738 ReplyStruct *replyStruct =
new ReplyStruct;
01739 replyStruct->replyType =
new QCString;
01740 replyStruct->replyData =
new QByteArray;
01741 replyStruct->replyObject = callBackObj;
01742 replyStruct->replySlot = callBackSlot;
01743 replyStruct->replyId = ++d->transactionId;
01744
if (d->transactionId < 0)
01745 d->transactionId = 0;
01746
01747
bool b = callInternal(remApp, remObjId, remFun, data,
01748 replyStruct,
false, -1, DCOPCall);
01749
if (!b)
01750 {
01751
delete replyStruct->replyType;
01752
delete replyStruct->replyData;
01753
delete replyStruct;
01754
return 0;
01755 }
01756
01757
if (replyStruct->transactionId == 0)
01758 {
01759
01760 QTimer::singleShot(0,
this, SLOT(asyncReplyReady()));
01761 d->asyncReplyQueue.append(replyStruct);
01762 }
01763
01764
return replyStruct->replyId;
01765 }
01766
01767
bool DCOPClient::callInternal(
const QCString &remApp,
const QCString &remObjId,
01768
const QCString &remFun,
const QByteArray &data,
01769
QCString& replyType,
QByteArray &replyData,
01770
bool useEventLoop,
int timeout,
int minor_opcode)
01771 {
01772 ReplyStruct replyStruct;
01773 replyStruct.replyType = &replyType;
01774 replyStruct.replyData = &replyData;
01775
return callInternal(remApp, remObjId, remFun, data, &replyStruct, useEventLoop, timeout, minor_opcode);
01776 }
01777
01778
bool DCOPClient::callInternal(
const QCString &remApp,
const QCString &remObjId,
01779
const QCString &remFun,
const QByteArray &data,
01780 ReplyStruct *replyStruct,
01781
bool useEventLoop,
int timeout,
int minor_opcode)
01782 {
01783
if ( !
isAttached() )
01784
return false;
01785
01786 DCOPMsg *pMsg;
01787
01788 CARD32 oldCurrentKey = d->currentKey;
01789
if ( !d->currentKey )
01790 d->currentKey = d->key;
01791
01792
QByteArray ba;
01793
QDataStream ds(ba, IO_WriteOnly);
01794 ds << d->appId << remApp << remObjId <<
normalizeFunctionSignature(remFun) << data.size();
01795
01796 IceGetHeader(d->iceConn, d->majorOpcode, minor_opcode,
01797
sizeof(DCOPMsg), DCOPMsg, pMsg);
01798
01799 pMsg->key = d->currentKey;
01800
int datalen = ba.size() + data.size();
01801 pMsg->length += datalen;
01802
01803
01804
01805 IceSendData(d->iceConn, ba.size(), const_cast<char *>(ba.data()));
01806 IceSendData(d->iceConn, data.size(), const_cast<char *>(data.data()));
01807
01808
if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
01809
return false;
01810
01811 IceFlush (d->iceConn);
01812
01813 IceReplyWaitInfo waitInfo;
01814 waitInfo.sequence_of_request = IceLastSentSequenceNumber(d->iceConn);
01815 waitInfo.major_opcode_of_request = d->majorOpcode;
01816 waitInfo.minor_opcode_of_request = minor_opcode;
01817
01818 replyStruct->transactionId = -1;
01819 waitInfo.reply = static_cast<IcePointer>(replyStruct);
01820
01821 Bool readyRet = False;
01822 IceProcessMessagesStatus s;
01823
01824 timeval time_start;
01825
int time_left = -1;
01826
if( timeout >= 0 )
01827 {
01828 gettimeofday( &time_start, NULL );
01829 time_left = timeout;
01830 }
01831
for(;;) {
01832
bool checkMessages =
true;
01833
if ( useEventLoop
01834 ? d->notifier != NULL
01835 : timeout >= 0 ) {
01836
const int guiTimeout = 100;
01837 checkMessages =
false;
01838
01839
int msecs = useEventLoop
01840 ? guiTimeout
01841 : time_left;
01842 fd_set fds;
01843
struct timeval tv;
01844 FD_ZERO( &fds );
01845 FD_SET(
socket(), &fds );
01846 tv.tv_sec = msecs / 1000;
01847 tv.tv_usec = (msecs % 1000) * 1000;
01848
if ( select(
socket() + 1, &fds, 0, 0, &tv ) <= 0 ) {
01849
if( useEventLoop && (time_left > guiTimeout)) {
01850
01851
01852
bool old_lock = d->non_blocking_call_lock;
01853
if ( !old_lock ) {
01854 d->non_blocking_call_lock =
true;
01855 emit
blockUserInput(
true );
01856 }
01857 d->eventLoopTimer.start(time_left - guiTimeout,
true);
01858 qApp->enter_loop();
01859 d->eventLoopTimer.stop();
01860
if ( !old_lock ) {
01861 d->non_blocking_call_lock =
false;
01862 emit
blockUserInput(
false );
01863 }
01864 }
01865 }
01866
else
01867 {
01868 checkMessages =
true;
01869 }
01870 }
01871
if (!d->iceConn)
01872
return false;
01873
01874
if( replyStruct->transactionId != -1 )
01875 {
01876
if (replyStruct->transactionId == 0)
01877
break;
01878
if (!replyStruct->replySlot.isEmpty())
01879
break;
01880 }
01881
01882
if( checkMessages ) {
01883 s = IceProcessMessages(d->iceConn, &waitInfo,
01884 &readyRet);
01885
if (s == IceProcessMessagesIOError) {
01886
detach();
01887 d->currentKey = oldCurrentKey;
01888
return false;
01889 }
01890 }
01891
01892
if( replyStruct->transactionId != -1 )
01893 {
01894
if (replyStruct->transactionId == 0)
01895
break;
01896
if (!replyStruct->replySlot.isEmpty())
01897
break;
01898 }
01899
01900
if( timeout < 0 )
01901
continue;
01902 timeval time_now;
01903 gettimeofday( &time_now, NULL );
01904 time_left = timeout -
01905 ((time_now.tv_sec - time_start.tv_sec) * 1000) -
01906 ((time_now.tv_usec - time_start.tv_usec) / 1000);
01907
if( time_left <= 0)
01908 {
01909
if (useEventLoop)
01910 {
01911
01912 time_left = 0;
01913 useEventLoop =
false;
01914
continue;
01915 }
01916 *(replyStruct->replyType) =
QCString();
01917 *(replyStruct->replyData) =
QByteArray();
01918 replyStruct->status = ReplyStruct::Failed;
01919
break;
01920 }
01921 }
01922
01923
01924
if ( d->non_blocking_call_lock ) {
01925 qApp->exit_loop();
01926 }
01927
01928 d->currentKey = oldCurrentKey;
01929
return replyStruct->status != ReplyStruct::Failed;
01930 }
01931
01932
void DCOPClient::eventLoopTimeout()
01933 {
01934 qApp->exit_loop();
01935 }
01936
01937 void DCOPClient::processSocketData(
int fd)
01938 {
01939
01940 fd_set fds;
01941 timeval timeout;
01942 timeout.tv_sec = 0;
01943 timeout.tv_usec = 0;
01944 FD_ZERO(&fds);
01945 FD_SET(fd, &fds);
01946
int result = select(fd+1, &fds, 0, 0, &timeout);
01947
if (result == 0)
01948
return;
01949
01950
if ( d->non_blocking_call_lock ) {
01951 qApp->exit_loop();
01952
return;
01953 }
01954
01955
if (!d->iceConn) {
01956 d->notifier->deleteLater();
01957 d->notifier = 0;
01958 qWarning(
"received an error processing data from the DCOP server!");
01959
return;
01960 }
01961
01962 IceProcessMessagesStatus s = IceProcessMessages(d->iceConn, 0, 0);
01963
01964
if (s == IceProcessMessagesIOError) {
01965
detach();
01966 qWarning(
"received an error processing data from the DCOP server!");
01967
return;
01968 }
01969 }
01970
01971 void DCOPClient::setDefaultObject(
const QCString& objId )
01972 {
01973 d->defaultObject = objId;
01974 }
01975
01976
01977 QCString DCOPClient::defaultObject()
const
01978
{
01979
return d->defaultObject;
01980 }
01981
01982
bool
01983 DCOPClient::isLocalTransactionFinished(Q_INT32
id,
QCString &replyType,
QByteArray &replyData)
01984 {
01985 DCOPClientPrivate::LocalTransactionResult *result = d->localTransActionList.take(
id);
01986
if (!result)
01987
return false;
01988
01989 replyType = result->replyType;
01990 replyData = result->replyData;
01991
delete result;
01992
01993
return true;
01994 }
01995
01996 DCOPClientTransaction *
01997 DCOPClient::beginTransaction()
01998 {
01999
if (d->opcode == DCOPSend)
02000
return 0;
02001
if (!d->transactionList)
02002 d->transactionList =
new QPtrList<DCOPClientTransaction>;
02003
02004 d->transaction =
true;
02005 DCOPClientTransaction *trans =
new DCOPClientTransaction();
02006 trans->senderId = d->senderId;
02007 trans->id = ++d->transactionId;
02008
if (d->transactionId < 0)
02009 d->transactionId = 0;
02010 trans->key = d->currentKey;
02011
02012 d->transactionList->append( trans );
02013
02014
return trans;
02015 }
02016
02017 Q_INT32
02018 DCOPClient::transactionId()
const
02019
{
02020
if (d->transaction)
02021
return d->transactionId;
02022
else
02023
return 0;
02024 }
02025
02026
void
02027 DCOPClient::endTransaction( DCOPClientTransaction *trans,
QCString& replyType,
02028
QByteArray &replyData)
02029 {
02030
if ( !trans )
02031
return;
02032
02033
if ( !
isAttached() )
02034
return;
02035
02036
if ( !d->transactionList) {
02037 qWarning(
"Transaction unknown: No pending transactions!");
02038
return;
02039 }
02040
02041
if ( !d->transactionList->removeRef( trans ) ) {
02042 qWarning(
"Transaction unknown: Not on list of pending transactions!");
02043
return;
02044 }
02045
02046
if (trans->senderId.isEmpty())
02047 {
02048
02049 DCOPClientPrivate::LocalTransactionResult *result =
new DCOPClientPrivate::LocalTransactionResult();
02050 result->replyType = replyType;
02051 result->replyData = replyData;
02052
02053 d->localTransActionList.insert(trans->id, result);
02054
02055
delete trans;
02056
02057
return;
02058 }
02059
02060 DCOPMsg *pMsg;
02061
02062
QByteArray ba;
02063
QDataStream ds(ba, IO_WriteOnly);
02064 ds << d->appId << trans->senderId << trans->id << replyType << replyData;
02065
02066 IceGetHeader(d->iceConn, d->majorOpcode, DCOPReplyDelayed,
02067
sizeof(DCOPMsg), DCOPMsg, pMsg);
02068
02069 pMsg->key = trans->key;
02070 pMsg->length += ba.size();
02071
02072 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
02073
02074
delete trans;
02075 }
02076
02077
void
02078 DCOPClient::emitDCOPSignal(
const QCString &object,
const QCString &signal,
const QByteArray &data)
02079 {
02080
02081
send(
"DCOPServer",
"emit", object+
"#"+
normalizeFunctionSignature(signal), data);
02082 }
02083
02084
void
02085
DCOPClient::emitDCOPSignal(
const QCString &signal,
const QByteArray &data)
02086 {
02087
emitDCOPSignal(0, signal, data);
02088 }
02089
02090
bool
02091 DCOPClient::connectDCOPSignal(
const QCString &sender,
const QCString &senderObj,
02092
const QCString &signal,
02093
const QCString &receiverObj,
const QCString &slot,
bool Volatile)
02094 {
02095
QCString replyType;
02096
QByteArray data, replyData;
02097 Q_INT8 iVolatile = Volatile ? 1 : 0;
02098
02099
QDataStream args(data, IO_WriteOnly );
02100 args << sender << senderObj <<
normalizeFunctionSignature(signal) << receiverObj <<
normalizeFunctionSignature(slot) << iVolatile;
02101
02102
if (!
call(
"DCOPServer", 0,
02103
"connectSignal(QCString,QCString,QCString,QCString,QCString,bool)",
02104 data, replyType, replyData))
02105 {
02106
return false;
02107 }
02108
02109
if (replyType !=
"bool")
02110
return false;
02111
02112
QDataStream reply(replyData, IO_ReadOnly );
02113 Q_INT8 result;
02114 reply >> result;
02115
return (result != 0);
02116 }
02117
02118
bool
02119 DCOPClient::connectDCOPSignal(
const QCString &sender,
const QCString &signal,
02120
const QCString &receiverObj,
const QCString &slot,
bool Volatile)
02121 {
02122
return connectDCOPSignal( sender, 0, signal, receiverObj, slot, Volatile);
02123 }
02124
02125
bool
02126 DCOPClient::disconnectDCOPSignal(
const QCString &sender,
const QCString &senderObj,
02127
const QCString &signal,
02128
const QCString &receiverObj,
const QCString &slot)
02129 {
02130
QCString replyType;
02131
QByteArray data, replyData;
02132
02133
QDataStream args(data, IO_WriteOnly );
02134 args << sender << senderObj <<
normalizeFunctionSignature(signal) << receiverObj <<
normalizeFunctionSignature(slot);
02135
02136
if (!
call(
"DCOPServer", 0,
02137
"disconnectSignal(QCString,QCString,QCString,QCString,QCString)",
02138 data, replyType, replyData))
02139 {
02140
return false;
02141 }
02142
02143
if (replyType !=
"bool")
02144
return false;
02145
02146
QDataStream reply(replyData, IO_ReadOnly );
02147 Q_INT8 result;
02148 reply >> result;
02149
return (result != 0);
02150 }
02151
02152
bool
02153 DCOPClient::disconnectDCOPSignal(
const QCString &sender,
const QCString &signal,
02154
const QCString &receiverObj,
const QCString &slot)
02155 {
02156
return disconnectDCOPSignal( sender, 0, signal, receiverObj, slot);
02157 }
02158
02159
void
02160 DCOPClient::setPriorityCall(
bool b)
02161 {
02162
if (b)
02163 {
02164
if (d->currentKey == 2)
02165
return;
02166 d->currentKeySaved = d->currentKey;
02167 d->currentKey = 2;
02168 }
02169
else
02170 {
02171
if (d->currentKey != 2)
02172
return;
02173 d->currentKey = d->currentKeySaved;
02174
if ( !d->messages.isEmpty() )
02175 d->postMessageTimer.start( 0,
true );
02176 }
02177 }
02178
02179
02180
02181
void
02182 DCOPClient::emergencyClose()
02183 {
02184
QPtrList<DCOPClient> list;
02185 client_map_t *map = DCOPClient_CliMap;
02186
if (!map)
return;
02187
QAsciiDictIterator<DCOPClient> it(*map);
02188
while(it.current()) {
02189 list.removeRef(it.current());
02190 list.append(it.current());
02191 ++it;
02192 }
02193
for(
DCOPClient *cl = list.first(); cl; cl = list.next())
02194 {
02195
if (cl->
d->iceConn) {
02196 IceProtocolShutdown(cl->
d->iceConn, cl->
d->majorOpcode);
02197 IceCloseConnection(cl->
d->iceConn);
02198 cl->
d->iceConn = 0L;
02199 }
02200 }
02201 }
02202
02203
const char *
02204 DCOPClient::postMortemSender()
02205 {
02206
if (!dcop_main_client)
02207
return "";
02208
if (dcop_main_client->
d->senderId.isEmpty())
02209
return "";
02210
return dcop_main_client->
d->senderId.data();
02211 }
02212
02213
const char *
02214 DCOPClient::postMortemObject()
02215 {
02216
if (!dcop_main_client)
02217
return "";
02218
return dcop_main_client->
d->objId.data();
02219 }
02220
const char *
02221 DCOPClient::postMortemFunction()
02222 {
02223
if (!dcop_main_client)
02224
return "";
02225
return dcop_main_client->
d->function.data();
02226 }
02227
02228
void DCOPClient::virtual_hook(
int,
void* )
02229 { }
02230
02231
#include <dcopclient.moc>
02232