26 #include <tqobjectlist.h>
27 #include <tqmetaobject.h>
28 #include <tqvariant.h>
30 #include <tqintdict.h>
31 #include <tqeventloop.h>
40 #include <sys/types.h>
43 #include <sys/socket.h>
53 #ifndef QT_CLEAN_NAMESPACE
54 #define QT_CLEAN_NAMESPACE
56 #include <tqguardedptr.h>
57 #include <tqtextstream.h>
60 #include <tqapplication.h>
61 #include <tqsocketnotifier.h>
64 #include <tqucomextra_p.h>
66 #include <dcopglobal.h>
67 #include <dcopclient.h>
68 #include <dcopobject.h>
70 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
74 #include <KDE-ICE/ICElib.h>
75 #include <KDE-ICE/ICEutil.h>
76 #include <KDE-ICE/ICEmsg.h>
77 #include <KDE-ICE/ICEproto.h>
82 extern TQMap<TQCString, DCOPObject *> * kde_dcopObjMap;
87 typedef TQAsciiDict<DCOPClient> client_map_t;
88 static client_map_t *DCOPClient_CliMap = 0;
91 client_map_t *cliMap()
93 if (!DCOPClient_CliMap)
94 DCOPClient_CliMap =
new client_map_t;
95 return DCOPClient_CliMap;
100 return cliMap()->find(_appId.data());
104 void registerLocalClient(
const TQCString &_appId,
DCOPClient *client )
106 cliMap()->replace(_appId.data(), client);
110 void unregisterLocalClient(
const TQCString &_appId )
112 client_map_t *map = cliMap();
113 map->remove(_appId.data());
117 template class TQPtrList<DCOPObjectProxy>;
118 template class TQPtrList<DCOPClientTransaction>;
119 template class TQPtrList<_IceConn>;
121 struct DCOPClientMessage
128 class DCOPClient::ReplyStruct
131 enum ReplyStatus { Pending, Ok, Failed };
141 TQCString* replyType;
142 TQByteArray* replyData;
144 TQ_INT32 transactionId;
146 TQGuardedPtr<TQObject> replyObject;
150 class DCOPClientPrivate
158 int majorVersion, minorVersion;
160 static const char* serverAddr;
161 TQSocketNotifier *notifier;
162 bool non_blocking_call_lock;
166 bool accept_calls_override;
167 bool qt_bridge_enabled;
173 TQCString defaultObject;
174 TQPtrList<DCOPClientTransaction> *transactionList;
176 TQ_INT32 transactionId;
186 CARD32 currentKeySaved;
188 TQTimer postMessageTimer;
189 TQPtrList<DCOPClientMessage> messages;
191 TQPtrList<DCOPClient::ReplyStruct> pendingReplies;
192 TQPtrList<DCOPClient::ReplyStruct> asyncReplyQueue;
194 struct LocalTransactionResult
197 TQByteArray replyData;
200 TQIntDict<LocalTransactionResult> localTransActionList;
202 TQTimer eventLoopTimer;
205 class DCOPClientTransaction
219 ret = SearchPathA(NULL,
"iceauth.exe",NULL,
sizeof(szPath)/
sizeof(szPath[0]),szPath,&pszFilePart);
221 return TQCString(szPath);
223 TQCString path = ::getenv(
"PATH");
225 path =
"/bin:/usr/bin";
226 path +=
":/usr/bin/X11:/usr/X11/bin:/usr/X11R6/bin";
227 TQCString fPath = strtok(path.data(),
":\b");
228 while (!fPath.isNull())
231 if (access(fPath.data(), X_OK) == 0)
236 fPath = strtok(NULL,
":\b");
242 static TQCString dcopServerFile(
const TQCString &hostname,
bool old)
244 TQCString fName = ::getenv(
"DCOPAUTHORITY");
245 if (!old && !fName.isEmpty())
248 fName = TQFile::encodeName( TQDir::homeDirPath() );
252 fprintf(stderr,
"Aborting. $HOME is not set.\n");
256 TQCString disp = getenv(
"DISPLAY");
257 #elif defined(Q_WS_QWS)
258 TQCString disp = getenv(
"QWS_DISPLAY");
266 if((i = disp.findRev(
'.')) > disp.findRev(KPATH_SEPARATOR) && i >= 0)
271 while( (i = disp.find(KPATH_SEPARATOR)) >= 0)
275 fName +=
"/.DCOPserver_";
276 if (hostname.isEmpty())
280 if (getenv(
"XAUTHLOCALHOSTNAME"))
281 fName += getenv(
"XAUTHLOCALHOSTNAME");
282 else if (gethostname(hostName,
sizeof(hostName)))
284 fName +=
"localhost";
288 hostName[
sizeof(hostName)-1] =
'\0';
304 return ::dcopServerFile(hostname,
false);
311 return ::dcopServerFile(hostname,
true);
315 const char* DCOPClientPrivate::serverAddr = 0;
317 static void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const TQByteArray& dataReceived,
bool canPost );
319 void DCOPClient::handleAsyncReply(ReplyStruct *replyStruct)
321 if (replyStruct->replyObject)
323 TQObject::connect(
this, TQT_SIGNAL(callBack(
int,
const TQCString&,
const TQByteArray &)),
324 replyStruct->replyObject, replyStruct->replySlot);
325 emit callBack(replyStruct->replyId, *(replyStruct->replyType), *(replyStruct->replyData));
326 TQObject::disconnect(
this, TQT_SIGNAL(callBack(
int,
const TQCString&,
const TQByteArray &)),
327 replyStruct->replyObject, replyStruct->replySlot);
335 static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject,
336 int opcode,
unsigned long length, Bool ,
337 IceReplyWaitInfo *replyWait,
341 DCOPClientPrivate *d =
static_cast<DCOPClientPrivate *
>(clientObject);
342 DCOPClient::ReplyStruct *replyStruct = replyWait ?
static_cast<DCOPClient::ReplyStruct*
>(replyWait->reply) : 0;
344 IceReadMessageHeader(iceConn,
sizeof(DCOPMsg), DCOPMsg, pMsg);
345 CARD32
key = pMsg->key;
349 TQByteArray dataReceived( length );
350 IceReadData(iceConn, length, dataReceived.data() );
355 case DCOPReplyFailed:
357 replyStruct->status = DCOPClient::ReplyStruct::Failed;
358 replyStruct->transactionId = 0;
359 *replyWaitRet = True;
362 qWarning(
"Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!");
367 TQByteArray* b = replyStruct->replyData;
368 TQCString* t = replyStruct->replyType;
369 replyStruct->status = DCOPClient::ReplyStruct::Ok;
370 replyStruct->transactionId = 0;
372 TQCString calledApp, app;
373 TQDataStream ds( dataReceived, IO_ReadOnly );
374 ds >> calledApp >> app >> *t >> *b;
376 *replyWaitRet = True;
379 qWarning(
"Very strange! got a DCOPReply opcode, but we were not waiting for a reply!");
384 TQCString calledApp, app;
386 TQDataStream ds( dataReceived, IO_ReadOnly );
387 ds >> calledApp >> app >> id;
388 replyStruct->transactionId = id;
389 replyStruct->calledApp = calledApp;
390 d->pendingReplies.append(replyStruct);
391 *replyWaitRet = True;
394 qWarning(
"Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!");
397 case DCOPReplyDelayed:
399 TQDataStream ds( dataReceived, IO_ReadOnly );
400 TQCString calledApp, app;
403 ds >> calledApp >> app >> id;
404 if (replyStruct && (
id == replyStruct->transactionId) && (calledApp == replyStruct->calledApp))
406 *replyWaitRet = True;
409 for(DCOPClient::ReplyStruct *rs = d->pendingReplies.first(); rs;
410 rs = d->pendingReplies.next())
412 if ((rs->transactionId ==
id) && (rs->calledApp == calledApp))
414 d->pendingReplies.remove();
415 TQByteArray* b = rs->replyData;
416 TQCString* t = rs->replyType;
419 rs->status = DCOPClient::ReplyStruct::Ok;
420 rs->transactionId = 0;
421 if (!rs->replySlot.isEmpty())
423 d->parent->handleAsyncReply(rs);
429 qWarning(
"Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!");
434 DCOPProcessInternal( d, opcode, key, dataReceived,
true );
438 void DCOPClient::processPostedMessagesInternal()
440 if ( d->messages.isEmpty() )
442 TQPtrListIterator<DCOPClientMessage> it (d->messages );
443 DCOPClientMessage* msg ;
444 while ( ( msg = it.current() ) ) {
446 if ( d->currentKey && msg->key != d->currentKey )
448 d->messages.removeRef( msg );
449 d->opcode = msg->opcode;
450 DCOPProcessInternal( d, msg->opcode, msg->key, msg->data,
false );
453 if ( !d->messages.isEmpty() )
454 d->postMessageTimer.start( 100,
true );
460 void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const TQByteArray& dataReceived,
bool canPost )
462 if (!d->accept_calls && (opcode == DCOPSend))
465 IceConn iceConn = d->iceConn;
468 TQDataStream ds( dataReceived, IO_ReadOnly );
472 if (fromApp.isEmpty())
475 if (!d->accept_calls)
478 TQDataStream replyStream( reply, IO_WriteOnly );
480 replyStream << d->appId << fromApp;
481 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
482 sizeof(DCOPMsg), DCOPMsg, pMsg );
483 int datalen = reply.size();
485 pMsg->length += datalen;
486 IceSendData( iceConn, datalen, reply.data());
490 TQCString app, objId, fun;
492 ds >> app >> objId >> fun >> data;
493 d->senderId = fromApp;
499 if ( canPost && d->currentKey && key != d->currentKey ) {
500 DCOPClientMessage* msg =
new DCOPClientMessage;
501 msg->opcode = opcode;
503 msg->data = dataReceived;
504 d->messages.append( msg );
505 d->postMessageTimer.start( 0,
true );
513 TQByteArray replyData;
515 CARD32 oldCurrentKey = d->currentKey;
516 if ( opcode != DCOPSend )
519 if ( opcode == DCOPFind )
520 b = c->find(app, objId, fun, data, replyType, replyData );
522 b = c->receive( app, objId, fun, data, replyType, replyData );
525 if ( opcode == DCOPSend )
528 if ((d->currentKey == key) || (oldCurrentKey != 2))
529 d->currentKey = oldCurrentKey;
532 TQDataStream replyStream( reply, IO_WriteOnly );
537 replyStream << d->appId << fromApp << id;
539 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait,
540 sizeof(DCOPMsg), DCOPMsg, pMsg );
542 pMsg->length += reply.size();
543 IceSendData( iceConn, reply.size(),
const_cast<char *
>(reply.data()));
550 replyStream << d->appId << fromApp;
551 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
552 sizeof(DCOPMsg), DCOPMsg, pMsg );
553 int datalen = reply.size();
555 pMsg->length += datalen;
556 IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
561 replyStream << d->appId << fromApp << replyType << replyData.size();
565 IceGetHeader( iceConn, d->majorOpcode,
DCOPReply,
566 sizeof(DCOPMsg), DCOPMsg, pMsg );
567 int datalen = reply.size() + replyData.size();
569 pMsg->length += datalen;
572 IceSendData( iceConn, reply.size(),
const_cast<char *
>(reply.data()));
573 IceSendData( iceConn, replyData.size(),
const_cast<char *
>(replyData.data()));
578 static IcePoVersionRec DCOPClientVersions[] = {
579 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
587 return dcop_main_client;
592 dcop_main_client = client;
598 d =
new DCOPClientPrivate;
606 d->non_blocking_call_lock =
false;
607 d->registered =
false;
608 d->foreign_server =
true;
609 d->accept_calls =
true;
610 d->accept_calls_override =
false;
611 d->qt_bridge_enabled =
true;
612 d->transactionList = 0L;
613 d->transactionId = 0;
614 TQObject::connect( &d->postMessageTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( processPostedMessagesInternal() ) );
615 TQObject::connect( &d->eventLoopTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( eventLoopTimeout() ) );
623 #ifdef DCOPCLIENT_DEBUG
624 qWarning(
"d->messages.count() = %d", d->messages.count());
625 TQPtrListIterator<DCOPClientMessage> it (d->messages );
626 DCOPClientMessage* msg ;
627 while ( ( msg = it.current() ) ) {
629 d->messages.removeRef( msg );
630 qWarning(
"DROPPING UNHANDLED DCOP MESSAGE:");
631 qWarning(
" opcode = %d key = %d", msg->opcode, msg->key);
632 TQDataStream ds( msg->data, IO_ReadOnly );
634 TQCString fromApp, app, objId, fun;
635 ds >> fromApp >> app >> objId >> fun;
636 qWarning(
" from = %s", fromApp.data());
637 qWarning(
" to = %s / %s / %s", app.data(), objId.data(), fun.data());
642 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
646 unregisterLocalClient( d->appId );
649 delete d->transactionList;
650 d->messages.setAutoDelete(
true);
659 TQCString env =
"DCOPSERVER=" + addr;
660 putenv(strdup(env.data()));
661 delete [] DCOPClientPrivate::serverAddr;
662 DCOPClientPrivate::serverAddr = qstrdup( addr.data() );
667 if (!attachInternal(
true ))
668 if (!attachInternal(
true ))
673 void DCOPClient::bindToApp()
680 d->notifier =
new TQSocketNotifier(
socket(),
681 TQSocketNotifier::Read, 0, 0);
682 TQObject::connect(d->notifier, TQT_SIGNAL(activated(
int)),
689 #ifdef Q_WS_WIN //TODO: remove (win32 ports sometimes do not create notifiers)
694 d->notifier->setEnabled(
false);
699 #ifdef Q_WS_WIN //TODO: remove
704 d->notifier->setEnabled(
true);
709 #if defined(Q_WS_WIN) || defined(Q_WS_MAC) //TODO: REMOVE
713 return !d->notifier->isEnabled();
718 static bool peerIsUs(
int sockfd)
721 socklen_t siz =
sizeof(cred);
722 if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0)
724 return (cred.uid == getuid());
728 static bool isServerSocketOwnedByUser(
const char*server)
731 if (strncmp(server,
"tcp/", 4) != 0)
736 if (strncmp(server,
"local/", 6) != 0)
738 const char *path = strchr(server, KPATH_SEPARATOR);
743 struct stat stat_buf;
744 if (stat(path, &stat_buf) != 0)
747 return (stat_buf.st_uid == getuid());
753 bool DCOPClient::attachInternal(
bool registerAsAnonymous )
760 if ((d->majorOpcode = IceRegisterForProtocolSetup(const_cast<char *>(
"DCOP"),
761 const_cast<char *>(DCOPVendorString),
762 const_cast<char *>(DCOPReleaseString),
763 1, DCOPClientVersions,
765 const_cast<char **>(DCOPAuthNames),
766 DCOPClientAuthProcs, 0L)) < 0) {
767 emit
attachFailed(TQString::fromLatin1(
"Communications could not be established." ));
771 bool bClearServerAddr =
false;
773 if (!d->serverAddr) {
777 dcopSrv = ::getenv(
"DCOPSERVER");
778 if (dcopSrv.isEmpty()) {
780 TQFile f(TQFile::decodeName(fName));
781 if (!f.open(IO_ReadOnly)) {
782 emit
attachFailed(TQString::fromLatin1(
"Could not read network connection list.\n" )+TQFile::decodeName(fName));
785 int size = QMIN( (qint64)1024, f.size() );
786 TQCString contents( size+1 );
787 if ( f.readBlock( contents.data(), size ) != size )
789 qDebug(
"Error reading from %s, didn't read the expected %d bytes", fName.data(), size);
792 contents[size] =
'\0';
793 int pos = contents.find(
'\n');
796 qDebug(
"Only one line in dcopserver file !: %s", contents.data());
801 if(contents[pos - 1] ==
'\r')
803 dcopSrv = contents.left( pos );
809 d->serverAddr = qstrdup( const_cast<char *>(dcopSrv.data()) );
810 bClearServerAddr =
true;
813 if ((d->iceConn = IceOpenConnection(const_cast<char*>(d->serverAddr),
814 static_cast<IcePointer>(
this), False, d->majorOpcode,
815 sizeof(errBuf), errBuf)) == 0L) {
816 qDebug(
"DCOPClient::attachInternal. Attach failed %s", errBuf);
818 if (bClearServerAddr) {
819 delete [] d->serverAddr;
825 fcntl(
socket(), F_SETFL, FD_CLOEXEC);
827 IceSetShutdownNegotiation(d->iceConn, False);
832 setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode,
833 static_cast<IcePointer>(d),
835 &(d->majorVersion), &(d->minorVersion),
836 &(vendor), &(release), 1024, errBuf);
837 if (vendor) free(vendor);
838 if (release) free(release);
840 if (setupstat == IceProtocolSetupFailure ||
841 setupstat == IceProtocolSetupIOError) {
842 IceCloseConnection(d->iceConn);
844 if (bClearServerAddr) {
845 delete [] d->serverAddr;
850 }
else if (setupstat == IceProtocolAlreadyActive) {
851 if (bClearServerAddr) {
852 delete [] d->serverAddr;
856 emit
attachFailed(TQString::fromLatin1(
"internal error in IceOpenConnection" ));
861 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) {
862 if (bClearServerAddr) {
863 delete [] d->serverAddr;
866 emit
attachFailed(TQString::fromLatin1(
"DCOP server did not accept the connection." ));
871 d->foreign_server = !peerIsUs(
socket());
873 d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr);
875 if (!d->accept_calls_override)
876 d->accept_calls = !d->foreign_server;
880 if ( registerAsAnonymous )
892 IceProtocolShutdown(d->iceConn, d->majorOpcode);
893 status = IceCloseConnection(d->iceConn);
894 if (status != IceClosedNow)
901 unregisterLocalClient(d->appId);
905 d->registered =
false;
906 d->foreign_server =
true;
915 return (IceConnectionStatus(d->iceConn) == IceConnectAccepted);
931 d->accept_calls_override =
true;
936 return d->qt_bridge_enabled;
941 d->qt_bridge_enabled = b;
948 TQCString _appId =
appId;
952 pid.sprintf(
"-%d", getpid());
953 _appId = _appId + pid;
956 if( d->appId == _appId )
959 #if 0 // no need to detach, dcopserver can handle renaming
967 if (!attachInternal(
false ))
968 if (!attachInternal(
false ))
974 TQByteArray data, replyData;
975 TQDataStream arg( data, IO_WriteOnly );
977 if (
call(
"DCOPServer",
"",
"registerAs(TQCString)", data, replyType, replyData ) ) {
978 TQDataStream reply( replyData, IO_ReadOnly );
983 d->registered = !result.isNull();
986 registerLocalClient( d->appId,
this );
993 return d->registered;
1006 return IceConnectionNumber(d->iceConn);
1010 static inline bool isIdentChar(
char x )
1012 return x ==
'_' || (x >=
'0' && x <=
'9') ||
1013 (x >=
'a' && x <=
'z') || (x >=
'A' && x <=
'Z');
1017 if ( fun.isEmpty() )
1019 TQCString result( fun.size() );
1020 char *from =
const_cast<TQCString&
>(fun).data();
1021 char *to = result.data();
1025 while ( *from && isspace(*from) )
1027 if ( last && isIdentChar( last ) && isIdentChar( *from ) )
1029 while ( *from && !isspace(*from) ) {
1036 if ( to > first && *(to-1) == 0x20 )
1039 result.resize( (
int)((
long)to - (
long)result.data()) + 1 );
1051 const TQCString &remFun,
const TQByteArray &data)
1053 if (remApp.isEmpty())
1057 if ( localClient ) {
1058 bool saveTransaction = d->transaction;
1059 TQ_INT32 saveTransactionId = d->transactionId;
1060 TQCString saveSenderId = d->senderId;
1063 TQCString replyType;
1064 TQByteArray replyData;
1065 (void) localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
1067 d->transaction = saveTransaction;
1068 d->transactionId = saveTransactionId;
1069 d->senderId = saveSenderId;
1084 TQDataStream ds(ba, IO_WriteOnly);
1087 IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend,
1088 sizeof(DCOPMsg), DCOPMsg, pMsg);
1091 int datalen = ba.size() + data.size();
1092 pMsg->length += datalen;
1094 IceSendData( d->iceConn, ba.size(),
const_cast<char *
>(ba.data()) );
1095 IceSendData( d->iceConn, data.size(),
const_cast<char *
>(data.data()) );
1099 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
1105 const TQCString &remFun,
const TQString &data)
1108 TQDataStream ds(ba, IO_WriteOnly);
1110 return send(remApp, remObjId, remFun, ba);
1114 const TQCString &remFun,
const TQByteArray &data,
1115 TQCString &foundApp, TQCString &foundObj,
1118 return findObject( remApp, remObj, remFun, data, foundApp, foundObj, useEventLoop, -1 );
1122 const TQCString &remFun,
const TQByteArray &data,
1123 TQCString &foundApp, TQCString &foundObj,
1124 bool useEventLoop,
int timeout)
1126 QCStringList appList;
1127 TQCString app = remApp;
1134 if (app[app.length()-1] ==
'*')
1139 int len = app.length()-1;
1141 for( QCStringList::ConstIterator it = apps.begin();
1145 if ( strncmp( (*it).data(), app.data(), len) == 0)
1146 appList.append(*it);
1151 appList.append(app);
1155 for(
int phase=1; phase <= 2; phase++)
1157 for( QCStringList::ConstIterator it = appList.begin();
1158 it != appList.end();
1161 TQCString remApp = *it;
1162 TQCString replyType;
1163 TQByteArray replyData;
1164 bool result =
false;
1167 if ( (phase == 1) && localClient ) {
1169 bool saveTransaction = d->transaction;
1170 TQ_INT32 saveTransactionId = d->transactionId;
1171 TQCString saveSenderId = d->senderId;
1174 result = localClient->find( remApp, remObj, remFun, data, replyType, replyData );
1180 TQApplication::eventLoop()->processEvents( TQEventLoop::WaitForMore);
1181 }
while( !localClient->isLocalTransactionFinished(
id, replyType, replyData));
1184 d->transaction = saveTransaction;
1185 d->transactionId = saveTransactionId;
1186 d->senderId = saveSenderId;
1188 else if ((phase == 2) && !localClient)
1191 result = callInternal(remApp, remObj, remFun, data,
1192 replyType, replyData, useEventLoop, timeout, DCOPFind);
1197 if (replyType ==
"DCOPRef")
1200 TQDataStream reply( replyData, IO_ReadOnly );
1203 if (ref.app() == remApp)
1206 foundApp = ref.
app();
1207 foundObj = ref.object();
1218 TQCString&, TQByteArray &)
1225 TQCString replyType;
1226 TQByteArray data, replyData;
1227 TQDataStream arg( data, IO_WriteOnly );
1230 if (
call(
"DCOPServer",
"",
"isApplicationRegistered(TQCString)", data, replyType, replyData ) ) {
1231 TQDataStream reply( replyData, IO_ReadOnly );
1239 TQCString replyType;
1240 TQByteArray data, replyData;
1241 QCStringList result;
1242 if (
call(
"DCOPServer",
"",
"registeredApplications()", data, replyType, replyData ) ) {
1243 TQDataStream reply( replyData, IO_ReadOnly );
1251 TQCString replyType;
1252 TQByteArray data, replyData;
1253 QCStringList result;
1256 if (
call( remApp,
"DCOPClient",
"objects()", data, replyType, replyData ) ) {
1257 TQDataStream reply( replyData, IO_ReadOnly );
1267 TQCString replyType;
1268 TQByteArray data, replyData;
1269 QCStringList result;
1272 if (
call( remApp, remObj,
"interfaces()", data, replyType, replyData ) && replyType ==
"QCStringList") {
1273 TQDataStream reply( replyData, IO_ReadOnly );
1283 TQCString replyType;
1284 TQByteArray data, replyData;
1285 QCStringList result;
1288 if (
call( remApp, remObj,
"functions()", data, replyType, replyData ) && replyType ==
"QCStringList") {
1289 TQDataStream reply( replyData, IO_ReadOnly );
1300 TQDataStream ds(data, IO_WriteOnly);
1301 ds << static_cast<TQ_INT8>(enabled);
1303 TQCString replyType;
1305 if (!
call(
"DCOPServer",
"",
"setNotifications( bool )", data, replyType, reply))
1306 qWarning(
"I couldn't enable notifications at the dcopserver!");
1312 TQDataStream ds(data, IO_WriteOnly);
1313 ds << static_cast<TQ_INT8>( daemonMode );
1315 TQCString replyType;
1317 if (!
call(
"DCOPServer",
"",
"setDaemonMode(bool)", data, replyType, reply))
1318 qWarning(
"I couldn't enable daemon mode at the dcopserver!");
1328 static void fillQtObjects( QCStringList& l, TQObject* o, TQCString path )
1330 if ( !path.isEmpty() )
1334 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject();
1335 if ( !list.isEmpty() ) {
1336 TQObjectListIt it( list );
1338 while ( (obj=it.current()) ) {
1340 TQCString n = obj->name();
1341 if ( n ==
"unnamed" || n.isEmpty() )
1343 n.sprintf(
"%p", (
void *) obj);
1344 n = TQString(TQString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1();
1346 TQCString fn = path + n;
1348 if ( !obj->childrenListObject().isEmpty() )
1349 fillQtObjects( l, obj, fn );
1359 O (
const TQCString& str, TQObject* obj ):s(str), o(obj){}
1365 static void fillQtObjectsEx( TQValueList<O>& l, TQObject* o, TQCString path )
1367 if ( !path.isEmpty() )
1371 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject();
1372 if ( !list.isEmpty() ) {
1373 TQObjectListIt it( list );
1375 while ( (obj=it.current()) ) {
1377 TQCString n = obj->name();
1378 if ( n ==
"unnamed" || n.isEmpty() )
1380 n.sprintf(
"%p", (
void *) obj);
1381 n = TQString(TQString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1();
1383 TQCString fn = path + n;
1384 l.append( O( fn, obj ) );
1385 if ( !obj->childrenListObject().isEmpty() )
1386 fillQtObjectsEx( l, obj, fn );
1392 static TQObject* findQtObject( TQCString
id )
1394 TQRegExp expr(
id );
1396 fillQtObjectsEx( l, 0,
"qt" );
1398 TQObject* firstContains = 0L;
1399 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
1400 if ( (*it).s ==
id )
1402 if ( !firstContains && (*it).s.contains( expr ) ) {
1403 firstContains = (*it).o;
1406 return firstContains;
1409 static QCStringList findQtObjects( TQCString
id )
1411 TQRegExp expr(
id );
1413 fillQtObjectsEx( l, 0,
"qt" );
1414 QCStringList result;
1415 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
1416 if ( (*it).s.contains( expr ) )
1422 static bool receiveQtObject(
const TQCString &objId,
const TQCString &fun,
const TQByteArray &data,
1423 TQCString& replyType, TQByteArray &replyData)
1425 if ( objId ==
"qt" ) {
1426 if ( fun ==
"interfaces()" ) {
1427 replyType =
"QCStringList";
1428 TQDataStream reply( replyData, IO_WriteOnly );
1434 }
else if ( fun ==
"functions()" ) {
1435 replyType =
"QCStringList";
1436 TQDataStream reply( replyData, IO_WriteOnly );
1438 l <<
"QCStringList functions()";
1439 l <<
"QCStringList interfaces()";
1440 l <<
"QCStringList objects()";
1441 l <<
"QCStringList find(TQCString)";
1444 }
else if ( fun ==
"objects()" ) {
1445 replyType =
"QCStringList";
1446 TQDataStream reply( replyData, IO_WriteOnly );
1448 fillQtObjects( l, 0,
"qt" );
1451 }
else if ( fun ==
"find(TQCString)" ) {
1452 TQDataStream ds( data, IO_ReadOnly );
1455 replyType =
"QCStringList";
1456 TQDataStream reply( replyData, IO_WriteOnly );
1457 reply << findQtObjects(
id ) ;
1460 }
else if ( objId.left(3) ==
"qt/" ) {
1461 TQObject* o = findQtObject( objId );
1464 if ( fun ==
"functions()" ) {
1465 replyType =
"QCStringList";
1466 TQDataStream reply( replyData, IO_WriteOnly );
1468 l <<
"QCStringList functions()";
1469 l <<
"QCStringList interfaces()";
1470 l <<
"QCStringList properties()";
1471 l <<
"bool setProperty(TQCString,TQVariant)";
1472 l <<
"TQVariant property(TQCString)";
1473 TQStrList lst = o->metaObject()->slotNames(
true );
1475 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) {
1476 if ( o->metaObject()->slot( i++,
true )->tqt_mo_access != TQMetaData::Public )
1478 TQCString slot = it.current();
1479 if ( slot.contains(
"()" ) ) {
1480 slot.prepend(
"void ");
1486 }
else if ( fun ==
"interfaces()" ) {
1487 replyType =
"QCStringList";
1488 TQDataStream reply( replyData, IO_WriteOnly );
1490 TQMetaObject *meta = o->metaObject();
1492 l.prepend( meta->className() );
1493 meta = meta->superClass();
1497 }
else if ( fun ==
"properties()" ) {
1498 replyType =
"QCStringList";
1499 TQDataStream reply( replyData, IO_WriteOnly );
1501 TQStrList lst = o->metaObject()->propertyNames(
true );
1502 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) {
1503 TQMetaObject *mo = o->metaObject();
1504 const TQMetaProperty* p = mo->property( mo->findProperty( it.current(), true ),
true );
1507 TQCString prop = p->type();
1510 if ( !p->writable() )
1511 prop +=
" readonly";
1516 }
else if ( fun ==
"property(TQCString)" ) {
1517 replyType =
"TQVariant";
1518 TQDataStream ds( data, IO_ReadOnly );
1521 TQVariant result = o->property( name );
1522 TQDataStream reply( replyData, IO_WriteOnly );
1525 }
else if ( fun ==
"setProperty(TQCString,TQVariant)" ) {
1526 TQDataStream ds( data, IO_ReadOnly );
1529 ds >> name >> value;
1531 TQDataStream reply( replyData, IO_WriteOnly );
1532 reply << (TQ_INT8) o->setProperty( name, value );
1535 int slot = o->metaObject()->findSlot( fun,
true );
1539 o->qt_invoke( slot, uo );
1556 bool DCOPClient::receive(
const TQCString &,
const TQCString &objId,
1557 const TQCString &fun,
const TQByteArray &data,
1558 TQCString& replyType, TQByteArray &replyData)
1560 d->transaction =
false;
1561 if ( objId ==
"DCOPClient" ) {
1562 if ( fun ==
"objects()" ) {
1563 replyType =
"QCStringList";
1564 TQDataStream reply( replyData, IO_WriteOnly );
1566 if (d->qt_bridge_enabled)
1570 if ( kde_dcopObjMap ) {
1571 TQMap<TQCString, DCOPObject *>::ConstIterator it( kde_dcopObjMap->begin());
1572 for (; it != kde_dcopObjMap->end(); ++it) {
1573 if ( !it.key().isEmpty() ) {
1574 if ( it.key() == d->defaultObject )
1585 if ( objId.isEmpty() || objId ==
"DCOPClient" ) {
1586 if ( fun ==
"applicationRegistered(TQCString)" ) {
1587 TQDataStream ds( data, IO_ReadOnly );
1592 }
else if ( fun ==
"applicationRemoved(TQCString)" ) {
1593 TQDataStream ds( data, IO_ReadOnly );
1600 if (
process( fun, data, replyType, replyData ) )
1604 }
else if (d->qt_bridge_enabled &&
1605 (objId ==
"qt" || objId.left(3) ==
"qt/") ) {
1606 return receiveQtObject( objId, fun, data, replyType, replyData );
1609 if ( objId.isEmpty() || objId ==
"default" ) {
1612 objPtr->setCallingDcopClient(
this);
1613 if (objPtr->
process(fun, data, replyType, replyData))
1621 if (!objId.isEmpty() && ((objId.length()>0)?(objId[objId.length()-1] ==
'*'):0)) {
1624 TQPtrList<DCOPObject> matchList =
1627 objPtr != 0L; objPtr = matchList.next()) {
1628 objPtr->setCallingDcopClient(
this);
1629 if (!objPtr->
process(fun, data, replyType, replyData))
1634 if ( DCOPObjectProxy::proxies ) {
1635 for ( TQPtrListIterator<DCOPObjectProxy> it( *DCOPObjectProxy::proxies ); it.current(); ++it ) {
1637 if ( it.current()->process( objId, fun, data, replyType, replyData ) )
1645 objPtr->setCallingDcopClient(
this);
1646 if (!objPtr->
process(fun, data, replyType, replyData)) {
1658 static bool findResultOk(TQCString &replyType, TQByteArray &replyData)
1661 if (replyType !=
"bool")
return false;
1663 TQDataStream reply( replyData, IO_ReadOnly );
1666 if (!success)
return false;
1672 static bool findSuccess(
const TQCString &app,
const TQCString objId, TQCString &replyType, TQByteArray &replyData)
1675 replyType =
"DCOPRef";
1677 replyData = TQByteArray();
1678 TQDataStream final_reply( replyData, IO_WriteOnly );
1684 bool DCOPClient::find(
const TQCString &app,
const TQCString &objId,
1685 const TQCString &fun,
const TQByteArray &data,
1686 TQCString& replyType, TQByteArray &replyData)
1688 d->transaction =
false;
1689 if ( !app.isEmpty() && app != d->appId && app[app.length()-1] !=
'*') {
1690 qWarning(
"WEIRD! we somehow received a DCOP message w/a different appId");
1694 if (objId.isEmpty() || objId[objId.length()-1] !=
'*')
1699 return findSuccess(app, objId, replyType, replyData);
1703 if (receive(app, objId, fun, data, replyType, replyData))
1705 if (findResultOk(replyType, replyData))
1706 return findSuccess(app, objId, replyType, replyData);
1712 TQPtrList<DCOPObject> matchList =
1715 objPtr != 0L; objPtr = matchList.next())
1718 replyData = TQByteArray();
1720 return findSuccess(app, objPtr->
objId(), replyType, replyData);
1721 objPtr->setCallingDcopClient(
this);
1722 if (objPtr->
process(fun, data, replyType, replyData))
1723 if (findResultOk(replyType, replyData))
1724 return findSuccess(app, objPtr->
objId(), replyType, replyData);
1732 const TQCString &remFun,
const TQByteArray &data,
1733 TQCString& replyType, TQByteArray &replyData,
1736 return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, -1 );
1740 const TQCString &remFun,
const TQByteArray &data,
1741 TQCString& replyType, TQByteArray &replyData,
1742 bool useEventLoop,
int timeout)
1744 if (remApp.isEmpty())
1748 if ( localClient ) {
1749 bool saveTransaction = d->transaction;
1750 TQ_INT32 saveTransactionId = d->transactionId;
1751 TQCString saveSenderId = d->senderId;
1754 bool b = localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
1760 TQApplication::eventLoop()->processEvents( TQEventLoop::WaitForMore);
1761 }
while( !localClient->isLocalTransactionFinished(
id, replyType, replyData));
1764 d->transaction = saveTransaction;
1765 d->transactionId = saveTransactionId;
1766 d->senderId = saveSenderId;
1770 return callInternal(remApp, remObjId, remFun, data,
1771 replyType, replyData, useEventLoop, timeout, DCOPCall);
1774 void DCOPClient::asyncReplyReady()
1776 while( d->asyncReplyQueue.count() )
1778 ReplyStruct *replyStruct = d->asyncReplyQueue.take(0);
1779 handleAsyncReply(replyStruct);
1784 const TQCString &remFun,
const TQByteArray &data,
1785 TQObject *callBackObj,
const char *callBackSlot)
1787 TQCString replyType;
1788 TQByteArray replyData;
1790 ReplyStruct *replyStruct =
new ReplyStruct;
1791 replyStruct->replyType =
new TQCString;
1792 replyStruct->replyData =
new TQByteArray;
1793 replyStruct->replyObject = callBackObj;
1794 replyStruct->replySlot = callBackSlot;
1795 replyStruct->replyId = ++d->transactionId;
1796 if (d->transactionId < 0)
1797 d->transactionId = 0;
1799 bool b = callInternal(remApp, remObjId, remFun, data,
1800 replyStruct,
false, -1, DCOPCall);
1803 delete replyStruct->replyType;
1804 delete replyStruct->replyData;
1809 if (replyStruct->transactionId == 0)
1812 TQTimer::singleShot(0,
this, TQT_SLOT(asyncReplyReady()));
1813 d->asyncReplyQueue.append(replyStruct);
1816 return replyStruct->replyId;
1819 bool DCOPClient::callInternal(
const TQCString &remApp,
const TQCString &remObjId,
1820 const TQCString &remFun,
const TQByteArray &data,
1821 TQCString& replyType, TQByteArray &replyData,
1822 bool useEventLoop,
int timeout,
int minor_opcode)
1824 ReplyStruct replyStruct;
1825 replyStruct.replyType = &replyType;
1826 replyStruct.replyData = &replyData;
1827 return callInternal(remApp, remObjId, remFun, data, &replyStruct, useEventLoop, timeout, minor_opcode);
1830 bool DCOPClient::callInternal(
const TQCString &remApp,
const TQCString &remObjId,
1831 const TQCString &remFun,
const TQByteArray &data,
1832 ReplyStruct *replyStruct,
1833 bool useEventLoop,
int timeout,
int minor_opcode)
1840 CARD32 oldCurrentKey = d->currentKey;
1841 if ( !d->currentKey )
1842 d->currentKey = d->key;
1845 TQDataStream ds(ba, IO_WriteOnly);
1848 IceGetHeader(d->iceConn, d->majorOpcode, minor_opcode,
1849 sizeof(DCOPMsg), DCOPMsg, pMsg);
1851 pMsg->key = d->currentKey;
1852 int datalen = ba.size() + data.size();
1853 pMsg->length += datalen;
1857 IceSendData(d->iceConn, ba.size(),
const_cast<char *
>(ba.data()));
1858 IceSendData(d->iceConn, data.size(),
const_cast<char *
>(data.data()));
1860 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
1863 IceFlush (d->iceConn);
1865 IceReplyWaitInfo waitInfo;
1866 waitInfo.sequence_of_request = IceLastSentSequenceNumber(d->iceConn);
1867 waitInfo.major_opcode_of_request = d->majorOpcode;
1868 waitInfo.minor_opcode_of_request = minor_opcode;
1870 replyStruct->transactionId = -1;
1871 waitInfo.reply =
static_cast<IcePointer
>(replyStruct);
1873 Bool readyRet = False;
1874 IceProcessMessagesStatus s;
1880 gettimeofday( &time_start, NULL );
1881 time_left = timeout;
1884 bool checkMessages =
true;
1886 ? d->notifier != NULL
1888 const int guiTimeout = 100;
1889 checkMessages =
false;
1891 int msecs = useEventLoop
1897 FD_SET(
socket(), &fds );
1898 tv.tv_sec = msecs / 1000;
1899 tv.tv_usec = (msecs % 1000) * 1000;
1900 if ( select(
socket() + 1, &fds, 0, 0, &tv ) <= 0 ) {
1901 if( useEventLoop && (timeout < 0 || time_left > guiTimeout)) {
1904 bool old_lock = d->non_blocking_call_lock;
1906 d->non_blocking_call_lock =
true;
1910 d->eventLoopTimer.start(time_left - guiTimeout,
true);
1911 tqApp->enter_loop();
1912 d->eventLoopTimer.stop();
1914 d->non_blocking_call_lock =
false;
1921 checkMessages =
true;
1927 if( replyStruct->transactionId != -1 )
1929 if (replyStruct->transactionId == 0)
1931 if (!replyStruct->replySlot.isEmpty())
1935 if( checkMessages ) {
1936 s = IceProcessMessages(d->iceConn, &waitInfo,
1938 if (s == IceProcessMessagesIOError) {
1940 d->currentKey = oldCurrentKey;
1945 if( replyStruct->transactionId != -1 )
1947 if (replyStruct->transactionId == 0)
1949 if (!replyStruct->replySlot.isEmpty())
1956 gettimeofday( &time_now, NULL );
1957 time_left = timeout -
1958 ((time_now.tv_sec - time_start.tv_sec) * 1000) -
1959 ((time_now.tv_usec - time_start.tv_usec) / 1000);
1966 useEventLoop =
false;
1969 *(replyStruct->replyType) = TQCString();
1970 *(replyStruct->replyData) = TQByteArray();
1971 replyStruct->status = ReplyStruct::Failed;
1977 if ( d->non_blocking_call_lock ) {
1981 d->currentKey = oldCurrentKey;
1982 return replyStruct->status != ReplyStruct::Failed;
1985 void DCOPClient::eventLoopTimeout()
1996 timeout.tv_usec = 0;
1999 int result = select(fd+1, &fds, 0, 0, &timeout);
2003 if ( d->non_blocking_call_lock ) {
2011 d->notifier->deleteLater();
2013 qWarning(
"received an error processing data from the DCOP server!");
2017 IceProcessMessagesStatus s = IceProcessMessages(d->iceConn, 0, 0);
2019 if (s == IceProcessMessagesIOError) {
2021 qWarning(
"received an error processing data from the DCOP server!");
2028 d->defaultObject = objId;
2034 return d->defaultObject;
2038 DCOPClient::isLocalTransactionFinished(TQ_INT32
id, TQCString &replyType, TQByteArray &replyData)
2040 DCOPClientPrivate::LocalTransactionResult *result = d->localTransActionList.take(
id);
2044 replyType = result->replyType;
2045 replyData = result->replyData;
2051 DCOPClientTransaction *
2054 if (d->opcode == DCOPSend)
2056 if (!d->transactionList)
2057 d->transactionList =
new TQPtrList<DCOPClientTransaction>;
2059 d->transaction =
true;
2060 DCOPClientTransaction *trans =
new DCOPClientTransaction();
2061 trans->senderId = d->senderId;
2062 trans->id = ++d->transactionId;
2063 if (d->transactionId < 0)
2064 d->transactionId = 0;
2065 trans->key = d->currentKey;
2067 d->transactionList->append( trans );
2076 return d->transactionId;
2083 TQByteArray &replyData)
2091 if ( !d->transactionList) {
2092 qWarning(
"Transaction unknown: No pending transactions!");
2096 if ( !d->transactionList->removeRef( trans ) ) {
2097 qWarning(
"Transaction unknown: Not on list of pending transactions!");
2101 if (trans->senderId.isEmpty())
2104 DCOPClientPrivate::LocalTransactionResult *result =
new DCOPClientPrivate::LocalTransactionResult();
2105 result->replyType = replyType;
2106 result->replyData = replyData;
2108 d->localTransActionList.insert(trans->id, result);
2118 TQDataStream ds(ba, IO_WriteOnly);
2119 ds << d->appId << trans->senderId << trans->id << replyType << replyData;
2121 IceGetHeader(d->iceConn, d->majorOpcode, DCOPReplyDelayed,
2122 sizeof(DCOPMsg), DCOPMsg, pMsg);
2123 pMsg->key = trans->key;
2124 pMsg->length += ba.size();
2126 IceSendData( d->iceConn, ba.size(),
const_cast<char *
>(ba.data()) );
2146 const TQCString &signal,
2147 const TQCString &receiverObj,
const TQCString &slot,
bool Volatile)
2149 TQCString replyType;
2150 TQByteArray data, replyData;
2151 TQ_INT8 iVolatile = Volatile ? 1 : 0;
2153 TQDataStream args(data, IO_WriteOnly );
2156 if (!
call(
"DCOPServer", 0,
2157 "connectSignal(TQCString,TQCString,TQCString,TQCString,TQCString,bool)",
2158 data, replyType, replyData))
2163 if (replyType !=
"bool")
2166 TQDataStream reply(replyData, IO_ReadOnly );
2169 return (result != 0);
2174 const TQCString &receiverObj,
const TQCString &slot,
bool Volatile)
2181 const TQCString &signal,
2182 const TQCString &receiverObj,
const TQCString &slot)
2184 TQCString replyType;
2185 TQByteArray data, replyData;
2187 TQDataStream args(data, IO_WriteOnly );
2190 if (!
call(
"DCOPServer", 0,
2191 "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)",
2192 data, replyType, replyData))
2197 if (replyType !=
"bool")
2200 TQDataStream reply(replyData, IO_ReadOnly );
2203 return (result != 0);
2208 const TQCString &receiverObj,
const TQCString &slot)
2214 DCOPClient::setPriorityCall(
bool b)
2218 if (d->currentKey == 2)
2220 d->currentKeySaved = d->currentKey;
2225 if (d->currentKey != 2)
2227 d->currentKey = d->currentKeySaved;
2228 if ( !d->messages.isEmpty() )
2229 d->postMessageTimer.start( 0,
true );
2236 DCOPClient::emergencyClose()
2238 TQPtrList<DCOPClient> list;
2239 client_map_t *map = DCOPClient_CliMap;
2241 TQAsciiDictIterator<DCOPClient> it(*map);
2242 while(it.current()) {
2243 list.removeRef(it.current());
2244 list.append(it.current());
2247 for(
DCOPClient *cl = list.first(); cl; cl = list.next())
2249 if (cl->d->iceConn) {
2250 IceProtocolShutdown(cl->d->iceConn, cl->d->majorOpcode);
2251 IceCloseConnection(cl->d->iceConn);
2252 cl->d->iceConn = 0L;
2258 DCOPClient::postMortemSender()
2260 if (!dcop_main_client)
2262 if (dcop_main_client->d->senderId.isEmpty())
2264 return dcop_main_client->d->senderId.data();
2268 DCOPClient::postMortemObject()
2270 if (!dcop_main_client)
2272 return dcop_main_client->d->objId.data();
2275 DCOPClient::postMortemFunction()
2277 if (!dcop_main_client)
2279 return dcop_main_client->d->function.data();
2282 void DCOPClient::virtual_hook(
int,
void* )
2285 #include <dcopclient.moc>