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 #include <tqguardedptr.h>
54 #include <tqtextstream.h>
57 #include <tqapplication.h>
58 #include <tqsocketnotifier.h>
61 #include <tqucomextra_p.h>
63 #include <dcopglobal.h>
64 #include <dcopclient.h>
65 #include <dcopobject.h>
67 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
71 #include <KDE-ICE/ICElib.h>
72 #include <KDE-ICE/ICEutil.h>
73 #include <KDE-ICE/ICEmsg.h>
74 #include <KDE-ICE/ICEproto.h>
79 extern TQMap<TQCString, DCOPObject *> * kde_dcopObjMap;
84 typedef TQAsciiDict<DCOPClient> client_map_t;
85 static client_map_t *DCOPClient_CliMap = 0;
88 client_map_t *cliMap()
90 if (!DCOPClient_CliMap)
91 DCOPClient_CliMap =
new client_map_t;
92 return DCOPClient_CliMap;
97 return cliMap()->find(_appId.data());
101 void registerLocalClient(
const TQCString &_appId,
DCOPClient *client )
103 cliMap()->replace(_appId.data(), client);
107 void unregisterLocalClient(
const TQCString &_appId )
109 client_map_t *map = cliMap();
110 map->remove(_appId.data());
114 template class TQPtrList<DCOPObjectProxy>;
115 template class TQPtrList<DCOPClientTransaction>;
116 template class TQPtrList<_IceConn>;
118 struct DCOPClientMessage
125 class DCOPClient::ReplyStruct
128 enum ReplyStatus { Pending, Ok, Failed };
138 TQCString* replyType;
139 TQByteArray* replyData;
141 TQ_INT32 transactionId;
143 TQGuardedPtr<TQObject> replyObject;
147 class DCOPClientPrivate
155 int majorVersion, minorVersion;
157 static const char* serverAddr;
158 TQSocketNotifier *notifier;
159 bool non_blocking_call_lock;
163 bool accept_calls_override;
164 bool qt_bridge_enabled;
170 TQCString defaultObject;
171 TQPtrList<DCOPClientTransaction> *transactionList;
173 TQ_INT32 transactionId;
183 CARD32 currentKeySaved;
185 TQTimer postMessageTimer;
186 TQPtrList<DCOPClientMessage> messages;
188 TQPtrList<DCOPClient::ReplyStruct> pendingReplies;
189 TQPtrList<DCOPClient::ReplyStruct> asyncReplyQueue;
191 struct LocalTransactionResult
194 TQByteArray replyData;
197 TQIntDict<LocalTransactionResult> localTransActionList;
199 TQTimer eventLoopTimer;
202 class DCOPClientTransaction
216 ret = SearchPathA(NULL,
"iceauth.exe",NULL,
sizeof(szPath)/
sizeof(szPath[0]),szPath,&pszFilePart);
218 return TQCString(szPath);
220 TQCString path = ::getenv(
"PATH");
222 path =
"/bin:/usr/bin";
223 path +=
":/usr/bin/X11:/usr/X11/bin:/usr/X11R6/bin";
224 TQCString fPath = strtok(path.data(),
":\b");
225 while (!fPath.isNull())
228 if (access(fPath.data(), X_OK) == 0)
233 fPath = strtok(NULL,
":\b");
239 static TQCString dcopServerFile(
const TQCString &hostname,
bool old)
241 TQCString fName = ::getenv(
"DCOPAUTHORITY");
242 if (!old && !fName.isEmpty())
245 fName = TQFile::encodeName( TQDir::homeDirPath() );
249 fprintf(stderr,
"Aborting. $HOME is not set.\n");
253 TQCString disp = getenv(
"DISPLAY");
254 #elif defined(Q_WS_QWS)
255 TQCString disp = getenv(
"QWS_DISPLAY");
263 if((i = disp.findRev(
'.')) > disp.findRev(KPATH_SEPARATOR) && i >= 0)
268 while( (i = disp.find(KPATH_SEPARATOR)) >= 0)
272 fName +=
"/.DCOPserver_";
273 if (hostname.isEmpty())
277 if (getenv(
"XAUTHLOCALHOSTNAME"))
278 fName += getenv(
"XAUTHLOCALHOSTNAME");
279 else if (gethostname(hostName,
sizeof(hostName)))
281 fName +=
"localhost";
285 hostName[
sizeof(hostName)-1] =
'\0';
301 return ::dcopServerFile(hostname,
false);
308 return ::dcopServerFile(hostname,
true);
312 const char* DCOPClientPrivate::serverAddr = 0;
314 static void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const TQByteArray& dataReceived,
bool canPost );
316 void DCOPClient::handleAsyncReply(ReplyStruct *replyStruct)
318 if (replyStruct->replyObject)
320 TQObject::connect(
this, TQT_SIGNAL(callBack(
int,
const TQCString&,
const TQByteArray &)),
321 replyStruct->replyObject, replyStruct->replySlot);
322 emit callBack(replyStruct->replyId, *(replyStruct->replyType), *(replyStruct->replyData));
323 TQObject::disconnect(
this, TQT_SIGNAL(callBack(
int,
const TQCString&,
const TQByteArray &)),
324 replyStruct->replyObject, replyStruct->replySlot);
332 static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject,
333 int opcode,
unsigned long length, Bool ,
334 IceReplyWaitInfo *replyWait,
338 DCOPClientPrivate *d = static_cast<DCOPClientPrivate *>(clientObject);
339 DCOPClient::ReplyStruct *replyStruct = replyWait ? static_cast<DCOPClient::ReplyStruct*>(replyWait->reply) : 0;
341 IceReadMessageHeader(iceConn,
sizeof(DCOPMsg), DCOPMsg, pMsg);
342 CARD32
key = pMsg->key;
346 TQByteArray dataReceived( length );
347 IceReadData(iceConn, length, dataReceived.data() );
352 case DCOPReplyFailed:
354 replyStruct->status = DCOPClient::ReplyStruct::Failed;
355 replyStruct->transactionId = 0;
356 *replyWaitRet = True;
359 tqWarning(
"Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!");
364 TQByteArray* b = replyStruct->replyData;
365 TQCString* t = replyStruct->replyType;
366 replyStruct->status = DCOPClient::ReplyStruct::Ok;
367 replyStruct->transactionId = 0;
369 TQCString calledApp, app;
370 TQDataStream ds( dataReceived, IO_ReadOnly );
371 ds >> calledApp >> app >> *t >> *b;
373 *replyWaitRet = True;
376 tqWarning(
"Very strange! got a DCOPReply opcode, but we were not waiting for a reply!");
381 TQCString calledApp, app;
383 TQDataStream ds( dataReceived, IO_ReadOnly );
384 ds >> calledApp >> app >> id;
385 replyStruct->transactionId = id;
386 replyStruct->calledApp = calledApp;
387 d->pendingReplies.append(replyStruct);
388 *replyWaitRet = True;
391 tqWarning(
"Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!");
394 case DCOPReplyDelayed:
396 TQDataStream ds( dataReceived, IO_ReadOnly );
397 TQCString calledApp, app;
400 ds >> calledApp >> app >> id;
401 if (replyStruct && (
id == replyStruct->transactionId) && (calledApp == replyStruct->calledApp))
403 *replyWaitRet = True;
406 for(DCOPClient::ReplyStruct *rs = d->pendingReplies.first(); rs;
407 rs = d->pendingReplies.next())
409 if ((rs->transactionId ==
id) && (rs->calledApp == calledApp))
411 d->pendingReplies.remove();
412 TQByteArray* b = rs->replyData;
413 TQCString* t = rs->replyType;
416 rs->status = DCOPClient::ReplyStruct::Ok;
417 rs->transactionId = 0;
418 if (!rs->replySlot.isEmpty())
420 d->parent->handleAsyncReply(rs);
426 tqWarning(
"Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!");
431 DCOPProcessInternal( d, opcode, key, dataReceived,
true );
435 void DCOPClient::processPostedMessagesInternal()
437 if ( d->messages.isEmpty() )
439 TQPtrListIterator<DCOPClientMessage> it (d->messages );
440 DCOPClientMessage* msg ;
441 while ( ( msg = it.current() ) ) {
443 if ( d->currentKey && msg->key != d->currentKey )
445 d->messages.removeRef( msg );
446 d->opcode = msg->opcode;
447 DCOPProcessInternal( d, msg->opcode, msg->key, msg->data,
false );
450 if ( !d->messages.isEmpty() )
451 d->postMessageTimer.start( 100,
true );
457 void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const TQByteArray& dataReceived,
bool canPost )
459 if (!d->accept_calls && (opcode == DCOPSend))
462 IceConn iceConn = d->iceConn;
465 TQDataStream ds( dataReceived, IO_ReadOnly );
469 if (fromApp.isEmpty())
472 if (!d->accept_calls)
475 TQDataStream replyStream( reply, IO_WriteOnly );
477 replyStream << d->appId << fromApp;
478 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
479 sizeof(DCOPMsg), DCOPMsg, pMsg );
480 int datalen = reply.size();
482 pMsg->length += datalen;
483 IceSendData( iceConn, datalen, reply.data());
487 TQCString app, objId, fun;
489 ds >> app >> objId >> fun >> data;
490 d->senderId = fromApp;
496 if ( canPost && d->currentKey && key != d->currentKey ) {
497 DCOPClientMessage* msg =
new DCOPClientMessage;
498 msg->opcode = opcode;
500 msg->data = dataReceived;
501 d->messages.append( msg );
502 d->postMessageTimer.start( 0,
true );
510 TQByteArray replyData;
512 CARD32 oldCurrentKey = d->currentKey;
513 if ( opcode != DCOPSend )
516 if ( opcode == DCOPFind )
517 b = c->find(app, objId, fun, data, replyType, replyData );
519 b = c->receive( app, objId, fun, data, replyType, replyData );
522 if ( opcode == DCOPSend )
525 if ((d->currentKey == key) || (oldCurrentKey != 2))
526 d->currentKey = oldCurrentKey;
529 TQDataStream replyStream( reply, IO_WriteOnly );
534 replyStream << d->appId << fromApp << id;
536 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait,
537 sizeof(DCOPMsg), DCOPMsg, pMsg );
539 pMsg->length += reply.size();
540 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
547 replyStream << d->appId << fromApp;
548 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
549 sizeof(DCOPMsg), DCOPMsg, pMsg );
550 int datalen = reply.size();
552 pMsg->length += datalen;
553 IceSendData( iceConn, datalen, const_cast<char *>(reply.data()));
558 replyStream << d->appId << fromApp << replyType << replyData.size();
562 IceGetHeader( iceConn, d->majorOpcode,
DCOPReply,
563 sizeof(DCOPMsg), DCOPMsg, pMsg );
564 int datalen = reply.size() + replyData.size();
566 pMsg->length += datalen;
569 IceSendData( iceConn, reply.size(), const_cast<char *>(reply.data()));
570 IceSendData( iceConn, replyData.size(), const_cast<char *>(replyData.data()));
575 static IcePoVersionRec DCOPClientVersions[] = {
576 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
584 return dcop_main_client;
589 dcop_main_client = client;
595 d =
new DCOPClientPrivate;
603 d->non_blocking_call_lock =
false;
604 d->registered =
false;
605 d->foreign_server =
true;
606 d->accept_calls =
true;
607 d->accept_calls_override =
false;
608 d->qt_bridge_enabled =
true;
609 d->transactionList = 0L;
610 d->transactionId = 0;
611 TQObject::connect( &d->postMessageTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( processPostedMessagesInternal() ) );
612 TQObject::connect( &d->eventLoopTimer, TQT_SIGNAL( timeout() ),
this, TQT_SLOT( eventLoopTimeout() ) );
620 #ifdef DCOPCLIENT_DEBUG
621 tqWarning(
"d->messages.count() = %d", d->messages.count());
622 TQPtrListIterator<DCOPClientMessage> it (d->messages );
623 DCOPClientMessage* msg ;
624 while ( ( msg = it.current() ) ) {
626 d->messages.removeRef( msg );
627 tqWarning(
"DROPPING UNHANDLED DCOP MESSAGE:");
628 tqWarning(
" opcode = %d key = %d", msg->opcode, msg->key);
629 TQDataStream ds( msg->data, IO_ReadOnly );
631 TQCString fromApp, app, objId, fun;
632 ds >> fromApp >> app >> objId >> fun;
633 tqWarning(
" from = %s", fromApp.data());
634 tqWarning(
" to = %s / %s / %s", app.data(), objId.data(), fun.data());
639 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
643 unregisterLocalClient( d->appId );
646 delete d->transactionList;
647 d->messages.setAutoDelete(
true);
656 TQCString env =
"DCOPSERVER=" + addr;
657 putenv(strdup(env.data()));
658 delete [] DCOPClientPrivate::serverAddr;
659 DCOPClientPrivate::serverAddr = tqstrdup( addr.data() );
664 if (!attachInternal(
true ))
665 if (!attachInternal(
true ))
670 void DCOPClient::bindToApp()
677 d->notifier =
new TQSocketNotifier(
socket(),
678 TQSocketNotifier::Read, 0, 0);
679 TQObject::connect(d->notifier, TQT_SIGNAL(activated(
int)),
686 #ifdef Q_WS_WIN //TODO: remove (win32 ports sometimes do not create notifiers)
691 d->notifier->setEnabled(
false);
696 #ifdef Q_WS_WIN //TODO: remove
701 d->notifier->setEnabled(
true);
706 #if defined(Q_WS_WIN) || defined(Q_WS_MAC) //TODO: REMOVE
710 return !d->notifier->isEnabled();
715 static bool peerIsUs(
int sockfd)
717 #if defined(__OpenBSD__)
718 struct sockpeercred cred;
722 socklen_t siz =
sizeof(cred);
723 if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0)
725 return (cred.uid == getuid());
729 static bool isServerSocketOwnedByUser(
const char*server)
732 if (strncmp(server,
"tcp/", 4) != 0)
737 if (strncmp(server,
"local/", 6) != 0)
739 const char *path = strchr(server, KPATH_SEPARATOR);
744 struct stat stat_buf;
745 if (stat(path, &stat_buf) != 0)
748 return (stat_buf.st_uid == getuid());
754 bool DCOPClient::attachInternal(
bool registerAsAnonymous )
761 if ((d->majorOpcode = IceRegisterForProtocolSetup(const_cast<char *>(
"DCOP"),
762 const_cast<char *>(DCOPVendorString),
763 const_cast<char *>(DCOPReleaseString),
764 1, DCOPClientVersions,
766 const_cast<char **>(DCOPAuthNames),
767 DCOPClientAuthProcs, 0L)) < 0) {
768 emit
attachFailed(TQString::fromLatin1(
"Communications could not be established." ));
772 bool bClearServerAddr =
false;
774 if (!d->serverAddr) {
778 dcopSrv = ::getenv(
"DCOPSERVER");
779 if (dcopSrv.isEmpty()) {
781 TQFile f(TQFile::decodeName(fName));
782 if (!f.open(IO_ReadOnly)) {
783 emit
attachFailed(TQString::fromLatin1(
"Could not read network connection list.\n" )+TQFile::decodeName(fName));
786 int size = TQMIN( (qint64)1024, f.size() );
787 TQCString contents( size+1 );
788 if ( f.readBlock( contents.data(), size ) != size )
790 tqDebug(
"Error reading from %s, didn't read the expected %d bytes", fName.data(), size);
793 contents[size] =
'\0';
794 int pos = contents.find(
'\n');
797 tqDebug(
"Only one line in dcopserver file !: %s", contents.data());
802 if(contents[pos - 1] ==
'\r')
804 dcopSrv = contents.left( pos );
810 d->serverAddr = tqstrdup( const_cast<char *>(dcopSrv.data()) );
811 bClearServerAddr =
true;
814 if ((d->iceConn = IceOpenConnection(const_cast<char*>(d->serverAddr),
815 static_cast<IcePointer>(
this), False, d->majorOpcode,
816 sizeof(errBuf), errBuf)) == 0L) {
817 tqDebug(
"DCOPClient::attachInternal. Attach failed %s", errBuf);
819 if (bClearServerAddr) {
820 delete [] d->serverAddr;
826 fcntl(
socket(), F_SETFL, FD_CLOEXEC);
828 IceSetShutdownNegotiation(d->iceConn, False);
833 setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode,
834 static_cast<IcePointer>(d),
836 &(d->majorVersion), &(d->minorVersion),
837 &(vendor), &(release), 1024, errBuf);
838 if (vendor) free(vendor);
839 if (release) free(release);
841 if (setupstat == IceProtocolSetupFailure ||
842 setupstat == IceProtocolSetupIOError) {
843 IceCloseConnection(d->iceConn);
845 if (bClearServerAddr) {
846 delete [] d->serverAddr;
851 }
else if (setupstat == IceProtocolAlreadyActive) {
852 if (bClearServerAddr) {
853 delete [] d->serverAddr;
857 emit
attachFailed(TQString::fromLatin1(
"internal error in IceOpenConnection" ));
862 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) {
863 if (bClearServerAddr) {
864 delete [] d->serverAddr;
867 emit
attachFailed(TQString::fromLatin1(
"DCOP server did not accept the connection." ));
872 d->foreign_server = !peerIsUs(
socket());
874 d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr);
876 if (!d->accept_calls_override)
877 d->accept_calls = !d->foreign_server;
881 if ( registerAsAnonymous )
893 IceProtocolShutdown(d->iceConn, d->majorOpcode);
894 status = IceCloseConnection(d->iceConn);
895 if (status != IceClosedNow)
902 unregisterLocalClient(d->appId);
906 d->registered =
false;
907 d->foreign_server =
true;
916 return (IceConnectionStatus(d->iceConn) == IceConnectAccepted);
932 d->accept_calls_override =
true;
937 return d->qt_bridge_enabled;
942 d->qt_bridge_enabled = b;
949 TQCString _appId =
appId;
953 pid.sprintf(
"-%d", getpid());
954 _appId = _appId + pid;
957 if( d->appId == _appId )
960 #if 0 // no need to detach, dcopserver can handle renaming
968 if (!attachInternal(
false ))
969 if (!attachInternal(
false ))
975 TQByteArray data, replyData;
976 TQDataStream arg( data, IO_WriteOnly );
978 if (
call(
"DCOPServer",
"",
"registerAs(TQCString)", data, replyType, replyData ) ) {
979 TQDataStream reply( replyData, IO_ReadOnly );
984 d->registered = !result.isNull();
987 registerLocalClient( d->appId,
this );
994 return d->registered;
1007 return IceConnectionNumber(d->iceConn);
1011 static inline bool isIdentChar(
char x )
1013 return x ==
'_' || (x >=
'0' && x <=
'9') ||
1014 (x >=
'a' && x <=
'z') || (x >=
'A' && x <=
'Z');
1018 if ( fun.isEmpty() )
1020 TQCString result( fun.size() );
1021 char *from = const_cast<TQCString&>(fun).data();
1022 char *to = result.data();
1026 while ( *from && isspace(*from) )
1028 if ( last && isIdentChar( last ) && isIdentChar( *from ) )
1030 while ( *from && !isspace(*from) ) {
1037 if ( to > first && *(to-1) == 0x20 )
1040 result.resize( (
int)((
long)to - (
long)result.data()) + 1 );
1052 const TQCString &remFun,
const TQByteArray &data)
1054 if (remApp.isEmpty())
1058 if ( localClient ) {
1059 bool saveTransaction = d->transaction;
1060 TQ_INT32 saveTransactionId = d->transactionId;
1061 TQCString saveSenderId = d->senderId;
1064 TQCString replyType;
1065 TQByteArray replyData;
1066 (void) localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
1068 d->transaction = saveTransaction;
1069 d->transactionId = saveTransactionId;
1070 d->senderId = saveSenderId;
1085 TQDataStream ds(ba, IO_WriteOnly);
1088 IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend,
1089 sizeof(DCOPMsg), DCOPMsg, pMsg);
1092 int datalen = ba.size() + data.size();
1093 pMsg->length += datalen;
1095 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
1096 IceSendData( d->iceConn, data.size(), const_cast<char *>(data.data()) );
1100 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
1106 const TQCString &remFun,
const TQString &data)
1109 TQDataStream ds(ba, IO_WriteOnly);
1111 return send(remApp, remObjId, remFun, ba);
1115 const TQCString &remFun,
const TQByteArray &data,
1116 TQCString &foundApp, TQCString &foundObj,
1119 return findObject( remApp, remObj, remFun, data, foundApp, foundObj, useEventLoop, -1 );
1123 const TQCString &remFun,
const TQByteArray &data,
1124 TQCString &foundApp, TQCString &foundObj,
1125 bool useEventLoop,
int timeout)
1127 QCStringList appList;
1128 TQCString app = remApp;
1135 if (app[app.length()-1] ==
'*')
1140 int len = app.length()-1;
1142 for( QCStringList::ConstIterator it = apps.begin();
1146 if ( strncmp( (*it).data(), app.data(), len) == 0)
1147 appList.append(*it);
1152 appList.append(app);
1156 for(
int phase=1; phase <= 2; phase++)
1158 for( QCStringList::ConstIterator it = appList.begin();
1159 it != appList.end();
1162 TQCString remApp = *it;
1163 TQCString replyType;
1164 TQByteArray replyData;
1165 bool result =
false;
1168 if ( (phase == 1) && localClient ) {
1170 bool saveTransaction = d->transaction;
1171 TQ_INT32 saveTransactionId = d->transactionId;
1172 TQCString saveSenderId = d->senderId;
1175 result = localClient->find( remApp, remObj, remFun, data, replyType, replyData );
1181 TQApplication::eventLoop()->processEvents( TQEventLoop::WaitForMore);
1182 }
while( !localClient->isLocalTransactionFinished(
id, replyType, replyData));
1185 d->transaction = saveTransaction;
1186 d->transactionId = saveTransactionId;
1187 d->senderId = saveSenderId;
1189 else if ((phase == 2) && !localClient)
1192 result = callInternal(remApp, remObj, remFun, data,
1193 replyType, replyData, useEventLoop, timeout, DCOPFind);
1198 if (replyType ==
"DCOPRef")
1201 TQDataStream reply( replyData, IO_ReadOnly );
1204 if (ref.app() == remApp)
1207 foundApp = ref.
app();
1208 foundObj = ref.object();
1219 TQCString&, TQByteArray &)
1226 TQCString replyType;
1227 TQByteArray data, replyData;
1228 TQDataStream arg( data, IO_WriteOnly );
1231 if (
call(
"DCOPServer",
"",
"isApplicationRegistered(TQCString)", data, replyType, replyData ) ) {
1232 TQDataStream reply( replyData, IO_ReadOnly );
1240 TQCString replyType;
1241 TQByteArray data, replyData;
1242 QCStringList result;
1243 if (
call(
"DCOPServer",
"",
"registeredApplications()", data, replyType, replyData ) ) {
1244 TQDataStream reply( replyData, IO_ReadOnly );
1252 TQCString replyType;
1253 TQByteArray data, replyData;
1254 QCStringList result;
1257 if (
call( remApp,
"DCOPClient",
"objects()", data, replyType, replyData ) ) {
1258 TQDataStream reply( replyData, IO_ReadOnly );
1268 TQCString replyType;
1269 TQByteArray data, replyData;
1270 QCStringList result;
1273 if (
call( remApp, remObj,
"interfaces()", data, replyType, replyData ) && replyType ==
"QCStringList") {
1274 TQDataStream reply( replyData, IO_ReadOnly );
1284 TQCString replyType;
1285 TQByteArray data, replyData;
1286 QCStringList result;
1289 if (
call( remApp, remObj,
"functions()", data, replyType, replyData ) && replyType ==
"QCStringList") {
1290 TQDataStream reply( replyData, IO_ReadOnly );
1301 TQDataStream ds(data, IO_WriteOnly);
1302 ds << static_cast<TQ_INT8>(enabled);
1304 TQCString replyType;
1306 if (!
call(
"DCOPServer",
"",
"setNotifications( bool )", data, replyType, reply))
1307 tqWarning(
"I couldn't enable notifications at the dcopserver!");
1313 TQDataStream ds(data, IO_WriteOnly);
1314 ds << static_cast<TQ_INT8>( daemonMode );
1316 TQCString replyType;
1318 if (!
call(
"DCOPServer",
"",
"setDaemonMode(bool)", data, replyType, reply))
1319 tqWarning(
"I couldn't enable daemon mode at the dcopserver!");
1329 static void fillQtObjects( QCStringList& l, TQObject* o, TQCString path )
1331 if ( !path.isEmpty() )
1335 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject();
1336 if ( !list.isEmpty() ) {
1337 TQObjectListIt it( list );
1339 while ( (obj=it.current()) ) {
1341 TQCString n = obj->name();
1342 if ( n ==
"unnamed" || n.isEmpty() )
1344 n.sprintf(
"%p", (
void *) obj);
1345 n = TQString(TQString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1();
1347 TQCString fn = path + n;
1349 if ( !obj->childrenListObject().isEmpty() )
1350 fillQtObjects( l, obj, fn );
1360 O (
const TQCString& str, TQObject* obj ):s(str), o(obj){}
1366 static void fillQtObjectsEx( TQValueList<O>& l, TQObject* o, TQCString path )
1368 if ( !path.isEmpty() )
1372 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject();
1373 if ( !list.isEmpty() ) {
1374 TQObjectListIt it( list );
1376 while ( (obj=it.current()) ) {
1378 TQCString n = obj->name();
1379 if ( n ==
"unnamed" || n.isEmpty() )
1381 n.sprintf(
"%p", (
void *) obj);
1382 n = TQString(TQString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1();
1384 TQCString fn = path + n;
1385 l.append( O( fn, obj ) );
1386 if ( !obj->childrenListObject().isEmpty() )
1387 fillQtObjectsEx( l, obj, fn );
1393 static TQObject* findQtObject( TQCString
id )
1395 TQRegExp expr(
id );
1397 fillQtObjectsEx( l, 0,
"qt" );
1399 TQObject* firstContains = 0L;
1400 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
1401 if ( (*it).s ==
id )
1403 if ( !firstContains && (*it).s.contains( expr ) ) {
1404 firstContains = (*it).o;
1407 return firstContains;
1410 static QCStringList findQtObjects( TQCString
id )
1412 TQRegExp expr(
id );
1414 fillQtObjectsEx( l, 0,
"qt" );
1415 QCStringList result;
1416 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
1417 if ( (*it).s.contains( expr ) )
1423 static bool receiveQtObject(
const TQCString &objId,
const TQCString &fun,
const TQByteArray &data,
1424 TQCString& replyType, TQByteArray &replyData)
1426 if ( objId ==
"qt" ) {
1427 if ( fun ==
"interfaces()" ) {
1428 replyType =
"QCStringList";
1429 TQDataStream reply( replyData, IO_WriteOnly );
1435 }
else if ( fun ==
"functions()" ) {
1436 replyType =
"QCStringList";
1437 TQDataStream reply( replyData, IO_WriteOnly );
1439 l <<
"QCStringList functions()";
1440 l <<
"QCStringList interfaces()";
1441 l <<
"QCStringList objects()";
1442 l <<
"QCStringList find(TQCString)";
1445 }
else if ( fun ==
"objects()" ) {
1446 replyType =
"QCStringList";
1447 TQDataStream reply( replyData, IO_WriteOnly );
1449 fillQtObjects( l, 0,
"qt" );
1452 }
else if ( fun ==
"find(TQCString)" ) {
1453 TQDataStream ds( data, IO_ReadOnly );
1456 replyType =
"QCStringList";
1457 TQDataStream reply( replyData, IO_WriteOnly );
1458 reply << findQtObjects(
id ) ;
1461 }
else if ( objId.left(3) ==
"qt/" ) {
1462 TQObject* o = findQtObject( objId );
1465 if ( fun ==
"functions()" ) {
1466 replyType =
"QCStringList";
1467 TQDataStream reply( replyData, IO_WriteOnly );
1469 l <<
"QCStringList functions()";
1470 l <<
"QCStringList interfaces()";
1471 l <<
"QCStringList properties()";
1472 l <<
"bool setProperty(TQCString,TQVariant)";
1473 l <<
"TQVariant property(TQCString)";
1474 TQStrList lst = o->metaObject()->slotNames(
true );
1476 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) {
1477 if ( o->metaObject()->slot( i++,
true )->tqt_mo_access != TQMetaData::Public )
1479 TQCString slot = it.current();
1480 if ( slot.contains(
"()" ) ) {
1481 slot.prepend(
"void ");
1487 }
else if ( fun ==
"interfaces()" ) {
1488 replyType =
"QCStringList";
1489 TQDataStream reply( replyData, IO_WriteOnly );
1491 TQMetaObject *meta = o->metaObject();
1493 l.prepend( meta->className() );
1494 meta = meta->superClass();
1498 }
else if ( fun ==
"properties()" ) {
1499 replyType =
"QCStringList";
1500 TQDataStream reply( replyData, IO_WriteOnly );
1502 TQStrList lst = o->metaObject()->propertyNames(
true );
1503 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) {
1504 TQMetaObject *mo = o->metaObject();
1505 const TQMetaProperty* p = mo->property( mo->findProperty( it.current(), true ),
true );
1508 TQCString prop = p->type();
1511 if ( !p->writable() )
1512 prop +=
" readonly";
1517 }
else if ( fun ==
"property(TQCString)" ) {
1518 replyType =
"TQVariant";
1519 TQDataStream ds( data, IO_ReadOnly );
1522 TQVariant result = o->property( name );
1523 TQDataStream reply( replyData, IO_WriteOnly );
1526 }
else if ( fun ==
"setProperty(TQCString,TQVariant)" ) {
1527 TQDataStream ds( data, IO_ReadOnly );
1530 ds >>
name >> value;
1532 TQDataStream reply( replyData, IO_WriteOnly );
1533 reply << (TQ_INT8) o->setProperty( name, value );
1536 int slot = o->metaObject()->findSlot( fun,
true );
1540 o->tqt_invoke( slot, uo );
1557 bool DCOPClient::receive(
const TQCString &,
const TQCString &objId,
1558 const TQCString &fun,
const TQByteArray &data,
1559 TQCString& replyType, TQByteArray &replyData)
1561 d->transaction =
false;
1562 if ( objId ==
"DCOPClient" ) {
1563 if ( fun ==
"objects()" ) {
1564 replyType =
"QCStringList";
1565 TQDataStream reply( replyData, IO_WriteOnly );
1567 if (d->qt_bridge_enabled)
1571 if ( kde_dcopObjMap ) {
1572 TQMap<TQCString, DCOPObject *>::ConstIterator it( kde_dcopObjMap->begin());
1573 for (; it != kde_dcopObjMap->end(); ++it) {
1574 if ( !it.key().isEmpty() ) {
1575 if ( it.key() == d->defaultObject )
1586 if ( objId.isEmpty() || objId ==
"DCOPClient" ) {
1587 if ( fun ==
"applicationRegistered(TQCString)" ) {
1588 TQDataStream ds( data, IO_ReadOnly );
1593 }
else if ( fun ==
"applicationRemoved(TQCString)" ) {
1594 TQDataStream ds( data, IO_ReadOnly );
1601 if (
process( fun, data, replyType, replyData ) )
1605 }
else if (d->qt_bridge_enabled &&
1606 (objId ==
"qt" || objId.left(3) ==
"qt/") ) {
1607 return receiveQtObject( objId, fun, data, replyType, replyData );
1610 if ( objId.isEmpty() || objId ==
"default" ) {
1613 objPtr->setCallingDcopClient(
this);
1614 if (objPtr->
process(fun, data, replyType, replyData))
1622 if (!objId.isEmpty() && ((objId.length()>0)?(objId[objId.length()-1] ==
'*'):0)) {
1625 TQPtrList<DCOPObject> matchList =
1628 objPtr != 0L; objPtr = matchList.next()) {
1629 objPtr->setCallingDcopClient(
this);
1630 if (!objPtr->
process(fun, data, replyType, replyData))
1635 if ( DCOPObjectProxy::proxies ) {
1636 for ( TQPtrListIterator<DCOPObjectProxy> it( *DCOPObjectProxy::proxies ); it.current(); ++it ) {
1638 if ( it.current()->process( objId, fun, data, replyType, replyData ) )
1646 objPtr->setCallingDcopClient(
this);
1647 if (!objPtr->
process(fun, data, replyType, replyData)) {
1659 static bool findResultOk(TQCString &replyType, TQByteArray &replyData)
1662 if (replyType !=
"bool")
return false;
1664 TQDataStream reply( replyData, IO_ReadOnly );
1667 if (!success)
return false;
1673 static bool findSuccess(
const TQCString &app,
const TQCString objId, TQCString &replyType, TQByteArray &replyData)
1676 replyType =
"DCOPRef";
1678 replyData = TQByteArray();
1679 TQDataStream final_reply( replyData, IO_WriteOnly );
1685 bool DCOPClient::find(
const TQCString &app,
const TQCString &objId,
1686 const TQCString &fun,
const TQByteArray &data,
1687 TQCString& replyType, TQByteArray &replyData)
1689 d->transaction =
false;
1690 if ( !app.isEmpty() && app != d->appId && app[app.length()-1] !=
'*') {
1691 tqWarning(
"WEIRD! we somehow received a DCOP message w/a different appId");
1695 if (objId.isEmpty() || objId[objId.length()-1] !=
'*')
1700 return findSuccess(app, objId, replyType, replyData);
1704 if (receive(app, objId, fun, data, replyType, replyData))
1706 if (findResultOk(replyType, replyData))
1707 return findSuccess(app, objId, replyType, replyData);
1713 TQPtrList<DCOPObject> matchList =
1716 objPtr != 0L; objPtr = matchList.next())
1719 replyData = TQByteArray();
1721 return findSuccess(app, objPtr->
objId(), replyType, replyData);
1722 objPtr->setCallingDcopClient(
this);
1723 if (objPtr->
process(fun, data, replyType, replyData))
1724 if (findResultOk(replyType, replyData))
1725 return findSuccess(app, objPtr->
objId(), replyType, replyData);
1733 const TQCString &remFun,
const TQByteArray &data,
1734 TQCString& replyType, TQByteArray &replyData,
1737 return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, -1,
false );
1741 const TQCString &remFun,
const TQByteArray &data,
1742 TQCString& replyType, TQByteArray &replyData,
1743 bool useEventLoop,
int timeout)
1745 return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, timeout,
false );
1749 const TQCString &remFun,
const TQByteArray &data,
1750 TQCString& replyType, TQByteArray &replyData,
1751 bool useEventLoop,
int timeout,
bool forceRemote)
1753 if (remApp.isEmpty())
1757 if ( localClient && !forceRemote ) {
1758 bool saveTransaction = d->transaction;
1759 TQ_INT32 saveTransactionId = d->transactionId;
1760 TQCString saveSenderId = d->senderId;
1763 bool b = localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
1769 TQApplication::eventLoop()->processEvents(TQEventLoop::WaitForMore);
1770 }
while( !localClient->isLocalTransactionFinished(
id, replyType, replyData));
1773 d->transaction = saveTransaction;
1774 d->transactionId = saveTransactionId;
1775 d->senderId = saveSenderId;
1779 return callInternal(remApp, remObjId, remFun, data,
1780 replyType, replyData, useEventLoop, timeout, DCOPCall);
1783 void DCOPClient::asyncReplyReady()
1785 while( d->asyncReplyQueue.count() )
1787 ReplyStruct *replyStruct = d->asyncReplyQueue.take(0);
1788 handleAsyncReply(replyStruct);
1793 const TQCString &remFun,
const TQByteArray &data,
1794 TQObject *callBackObj,
const char *callBackSlot)
1796 TQCString replyType;
1797 TQByteArray replyData;
1799 ReplyStruct *replyStruct =
new ReplyStruct;
1800 replyStruct->replyType =
new TQCString;
1801 replyStruct->replyData =
new TQByteArray;
1802 replyStruct->replyObject = callBackObj;
1803 replyStruct->replySlot = callBackSlot;
1804 replyStruct->replyId = ++d->transactionId;
1805 if (d->transactionId < 0)
1806 d->transactionId = 0;
1808 bool b = callInternal(remApp, remObjId, remFun, data,
1809 replyStruct,
false, -1, DCOPCall);
1812 delete replyStruct->replyType;
1813 delete replyStruct->replyData;
1818 if (replyStruct->transactionId == 0)
1821 TQTimer::singleShot(0,
this, TQT_SLOT(asyncReplyReady()));
1822 d->asyncReplyQueue.append(replyStruct);
1825 return replyStruct->replyId;
1828 bool DCOPClient::callInternal(
const TQCString &remApp,
const TQCString &remObjId,
1829 const TQCString &remFun,
const TQByteArray &data,
1830 TQCString& replyType, TQByteArray &replyData,
1831 bool useEventLoop,
int timeout,
int minor_opcode)
1833 ReplyStruct replyStruct;
1834 replyStruct.replyType = &replyType;
1835 replyStruct.replyData = &replyData;
1836 return callInternal(remApp, remObjId, remFun, data, &replyStruct, useEventLoop, timeout, minor_opcode);
1839 bool DCOPClient::callInternal(
const TQCString &remApp,
const TQCString &remObjId,
1840 const TQCString &remFun,
const TQByteArray &data,
1841 ReplyStruct *replyStruct,
1842 bool useEventLoop,
int timeout,
int minor_opcode)
1849 CARD32 oldCurrentKey = d->currentKey;
1850 if ( !d->currentKey )
1851 d->currentKey = d->key;
1854 TQDataStream ds(ba, IO_WriteOnly);
1857 IceGetHeader(d->iceConn, d->majorOpcode, minor_opcode,
1858 sizeof(DCOPMsg), DCOPMsg, pMsg);
1860 pMsg->key = d->currentKey;
1861 int datalen = ba.size() + data.size();
1862 pMsg->length += datalen;
1866 IceSendData(d->iceConn, ba.size(), const_cast<char *>(ba.data()));
1867 IceSendData(d->iceConn, data.size(), const_cast<char *>(data.data()));
1869 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
1872 IceFlush (d->iceConn);
1874 IceReplyWaitInfo waitInfo;
1875 waitInfo.sequence_of_request = IceLastSentSequenceNumber(d->iceConn);
1876 waitInfo.major_opcode_of_request = d->majorOpcode;
1877 waitInfo.minor_opcode_of_request = minor_opcode;
1879 replyStruct->transactionId = -1;
1880 waitInfo.reply = static_cast<IcePointer>(replyStruct);
1882 Bool readyRet = False;
1883 IceProcessMessagesStatus s;
1889 gettimeofday( &time_start, NULL );
1890 time_left = timeout;
1893 bool checkMessages =
true;
1895 ? d->notifier != NULL
1897 const int guiTimeout = 100;
1898 checkMessages =
false;
1900 int msecs = useEventLoop
1906 FD_SET(
socket(), &fds );
1907 tv.tv_sec = msecs / 1000;
1908 tv.tv_usec = (msecs % 1000) * 1000;
1909 if ( select(
socket() + 1, &fds, 0, 0, &tv ) <= 0 ) {
1910 if( useEventLoop && (timeout < 0 || time_left > guiTimeout)) {
1913 bool old_lock = d->non_blocking_call_lock;
1915 d->non_blocking_call_lock =
true;
1919 d->eventLoopTimer.start(time_left - guiTimeout,
true);
1920 tqApp->enter_loop();
1921 d->eventLoopTimer.stop();
1923 d->non_blocking_call_lock =
false;
1930 checkMessages =
true;
1936 if( replyStruct->transactionId != -1 )
1938 if (replyStruct->transactionId == 0)
1940 if (!replyStruct->replySlot.isEmpty())
1944 if( checkMessages ) {
1945 s = IceProcessMessages(d->iceConn, &waitInfo,
1947 if (s == IceProcessMessagesIOError) {
1949 d->currentKey = oldCurrentKey;
1954 if( replyStruct->transactionId != -1 )
1956 if (replyStruct->transactionId == 0)
1958 if (!replyStruct->replySlot.isEmpty())
1965 gettimeofday( &time_now, NULL );
1966 time_left = timeout -
1967 ((time_now.tv_sec - time_start.tv_sec) * 1000) -
1968 ((time_now.tv_usec - time_start.tv_usec) / 1000);
1975 useEventLoop =
false;
1978 *(replyStruct->replyType) = TQCString();
1979 *(replyStruct->replyData) = TQByteArray();
1980 replyStruct->status = ReplyStruct::Failed;
1986 if ( d->non_blocking_call_lock ) {
1990 d->currentKey = oldCurrentKey;
1991 return replyStruct->status != ReplyStruct::Failed;
1994 void DCOPClient::eventLoopTimeout()
2005 timeout.tv_usec = 0;
2008 int result = select(fd+1, &fds, 0, 0, &timeout);
2012 if ( d->non_blocking_call_lock ) {
2020 d->notifier->deleteLater();
2022 tqWarning(
"received an error processing data from the DCOP server!");
2026 IceProcessMessagesStatus s = IceProcessMessages(d->iceConn, 0, 0);
2028 if (s == IceProcessMessagesIOError) {
2030 tqWarning(
"received an error processing data from the DCOP server!");
2037 d->defaultObject = objId;
2043 return d->defaultObject;
2047 DCOPClient::isLocalTransactionFinished(TQ_INT32
id, TQCString &replyType, TQByteArray &replyData)
2049 DCOPClientPrivate::LocalTransactionResult *result = d->localTransActionList.take(
id);
2053 replyType = result->replyType;
2054 replyData = result->replyData;
2060 DCOPClientTransaction *
2063 if (d->opcode == DCOPSend)
2065 if (!d->transactionList)
2066 d->transactionList =
new TQPtrList<DCOPClientTransaction>;
2068 d->transaction =
true;
2069 DCOPClientTransaction *trans =
new DCOPClientTransaction();
2070 trans->senderId = d->senderId;
2071 trans->id = ++d->transactionId;
2072 if (d->transactionId < 0)
2073 d->transactionId = 0;
2074 trans->key = d->currentKey;
2076 d->transactionList->append( trans );
2085 return d->transactionId;
2092 TQByteArray &replyData)
2100 if ( !d->transactionList) {
2101 tqWarning(
"Transaction unknown: No pending transactions!");
2105 if ( !d->transactionList->removeRef( trans ) ) {
2106 tqWarning(
"Transaction unknown: Not on list of pending transactions!");
2110 if (trans->senderId.isEmpty())
2113 DCOPClientPrivate::LocalTransactionResult *result =
new DCOPClientPrivate::LocalTransactionResult();
2114 result->replyType = replyType;
2115 result->replyData = replyData;
2117 d->localTransActionList.insert(trans->id, result);
2127 TQDataStream ds(ba, IO_WriteOnly);
2128 ds << d->appId << trans->senderId << trans->id << replyType << replyData;
2130 IceGetHeader(d->iceConn, d->majorOpcode, DCOPReplyDelayed,
2131 sizeof(DCOPMsg), DCOPMsg, pMsg);
2132 pMsg->key = trans->key;
2133 pMsg->length += ba.size();
2135 IceSendData( d->iceConn, ba.size(), const_cast<char *>(ba.data()) );
2155 const TQCString &signal,
2156 const TQCString &receiverObj,
const TQCString &slot,
bool Volatile)
2158 TQCString replyType;
2159 TQByteArray data, replyData;
2160 TQ_INT8 iVolatile = Volatile ? 1 : 0;
2162 TQDataStream args(data, IO_WriteOnly );
2165 if (!
call(
"DCOPServer", 0,
2166 "connectSignal(TQCString,TQCString,TQCString,TQCString,TQCString,bool)",
2167 data, replyType, replyData))
2172 if (replyType !=
"bool")
2175 TQDataStream reply(replyData, IO_ReadOnly );
2178 return (result != 0);
2183 const TQCString &receiverObj,
const TQCString &slot,
bool Volatile)
2190 const TQCString &signal,
2191 const TQCString &receiverObj,
const TQCString &slot)
2193 TQCString replyType;
2194 TQByteArray data, replyData;
2196 TQDataStream args(data, IO_WriteOnly );
2199 if (!
call(
"DCOPServer", 0,
2200 "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)",
2201 data, replyType, replyData))
2206 if (replyType !=
"bool")
2209 TQDataStream reply(replyData, IO_ReadOnly );
2212 return (result != 0);
2217 const TQCString &receiverObj,
const TQCString &slot)
2223 DCOPClient::setPriorityCall(
bool b)
2227 if (d->currentKey == 2)
2229 d->currentKeySaved = d->currentKey;
2234 if (d->currentKey != 2)
2236 d->currentKey = d->currentKeySaved;
2237 if ( !d->messages.isEmpty() )
2238 d->postMessageTimer.start( 0,
true );
2245 DCOPClient::emergencyClose()
2247 TQPtrList<DCOPClient> list;
2248 client_map_t *map = DCOPClient_CliMap;
2250 TQAsciiDictIterator<DCOPClient> it(*map);
2251 while(it.current()) {
2252 list.removeRef(it.current());
2253 list.append(it.current());
2256 for(
DCOPClient *cl = list.first(); cl; cl = list.next())
2258 if (cl->d->iceConn) {
2259 IceProtocolShutdown(cl->d->iceConn, cl->d->majorOpcode);
2260 IceCloseConnection(cl->d->iceConn);
2261 cl->d->iceConn = 0L;
2267 DCOPClient::postMortemSender()
2269 if (!dcop_main_client)
2271 if (dcop_main_client->d->senderId.isEmpty())
2273 return dcop_main_client->d->senderId.data();
2277 DCOPClient::postMortemObject()
2279 if (!dcop_main_client)
2281 return dcop_main_client->d->objId.data();
2284 DCOPClient::postMortemFunction()
2286 if (!dcop_main_client)
2288 return dcop_main_client->d->function.data();
2291 void DCOPClient::virtual_hook(
int,
void* )
2294 #include <dcopclient.moc>