Ok, the long awaited config wizard is here (at least in a very basic state). There...
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / network / qxtrpcpeer.cpp
1 /****************************************************************************
2  **
3  ** Copyright (C) Qxt Foundation. Some rights reserved.
4  **
5  ** This file is part of the QxtNetwork module of the Qt eXTension library
6  **
7  ** This library is free software; you can redistribute it and/or modify it
8  ** under the terms of th Common Public License, version 1.0, as published by
9  ** IBM.
10  **
11  ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12  ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13  ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14  ** FITNESS FOR A PARTICULAR PURPOSE.
15  **
16  ** You should have received a copy of the CPL along with this file.
17  ** See the LICENSE file and the cpl1.0.txt file included with the source
18  ** distribution for more information. If you did not receive a copy of the
19  ** license, contact the Qxt Foundation.
20  **
21  ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22  **
23  ****************************************************************************/
24
25 #include "qxtrpcpeer.h"
26 #include <QObject>
27 #include <QTcpSocket>
28 #include <QTcpServer>
29 #include <QMultiHash>
30 #include <QDebug>
31 #include <QMetaMethod>
32 #include <cassert>
33 #include "qxtmetaobject.h"
34 #include <QStack>
35
36 class QxtIntrospector: public QObject
37 {
38 // This class MANUALLY implements the necessary parts of QObject.
39 // Do NOT add the Q_OBJECT macro. As this class isn't intended
40 // for direct use, it doesn't offer any sort of useful meta-object.
41 public:
42     QxtIntrospector(QxtRPCPeer* parent, QObject* source, const char* signal);
43
44     int qt_metacall(QMetaObject::Call _c, int _id, void **_a);
45
46     QString rpcFunction;
47
48 private:
49     QxtRPCPeer* peer;
50     QList<int> argTypes;
51 };
52
53 struct QxtRPCConnection
54 {
55     QTcpSocket* socket;
56     QByteArray buffer;
57     QString lastMethod;
58 };
59
60 class QxtRPCPeerPrivate : public QxtPrivate<QxtRPCPeer>, public QTcpServer
61 {
62 public:
63     QXT_DECLARE_PUBLIC(QxtRPCPeer);
64
65     void incomingConnection ( int socketDescriptor );
66
67
68     void receivePeerSignal(QString fn, QVariant p0 = QVariant(), QVariant p1 = QVariant(), QVariant p2 = QVariant(), QVariant p3 = QVariant(),
69                            QVariant p4 = QVariant(), QVariant p5 = QVariant(), QVariant p6 = QVariant(), QVariant p7 = QVariant(), QVariant p8 = QVariant()) const;
70     void receiveClientSignal(quint64 id, QString fn, QVariant p0 = QVariant(), QVariant p1 = QVariant(), QVariant p2 = QVariant(), QVariant p3 = QVariant(),
71                              QVariant p4 = QVariant(), QVariant p5 = QVariant(), QVariant p6 = QVariant(), QVariant p7 = QVariant()) const;
72
73     void processInput(QIODevice* socket, QByteArray& buffer);
74
75     // Object -> introspector for each signal
76     QMultiHash<QObject*, QxtIntrospector*> attachedSignals;
77     // RPC function -> (object, slot ID)
78     typedef QPair<QObject*, int> MethodID;
79     QHash<QString, QList<MethodID> > attachedSlots;
80
81     typedef QHash<QObject*, QxtRPCConnection*> ConnHash;
82     ConnHash m_clients;
83     QIODevice* m_peer;
84
85     QByteArray m_buffer;
86     int m_rpctype;
87
88
89     QStack<QTcpSocket*> pending_connections;
90
91 };
92
93 QxtRPCPeer::QxtRPCPeer(QObject* parent) : QObject(parent)
94 {
95     QXT_INIT_PRIVATE(QxtRPCPeer);
96     qxt_d().m_rpctype = Peer;
97     qxt_d().m_peer = new QTcpSocket(this);
98     QObject::connect(qxt_d().m_peer, SIGNAL(connected()), this, SIGNAL(peerConnected()));
99     QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SIGNAL(peerDisconnected()));
100     QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SLOT(disconnectSender()));
101     QObject::connect(qxt_d().m_peer, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
102     QObject::connect(qxt_d().m_peer, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(peerError(QAbstractSocket::SocketError)));
103 }
104
105
106 QxtRPCPeer::QxtRPCPeer(RPCTypes type, QObject* parent) : QObject(parent)
107 {
108     QXT_INIT_PRIVATE(QxtRPCPeer);
109     qxt_d().m_rpctype = type;
110     qxt_d().m_peer = new QTcpSocket(this);
111     QObject::connect(qxt_d().m_peer, SIGNAL(connected()), this, SIGNAL(peerConnected()));
112     QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SIGNAL(peerDisconnected()));
113     QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SLOT(disconnectSender()));
114     QObject::connect(qxt_d().m_peer, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
115     QObject::connect(qxt_d().m_peer, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(peerError(QAbstractSocket::SocketError)));
116 }
117
118
119 QxtRPCPeer::QxtRPCPeer(QIODevice* device, RPCTypes type, QObject* parent) : QObject(parent)
120 {
121     if (!device->isOpen())
122     {
123         qWarning("QxtRPCPeer::the device you passed is not open!");
124     }
125
126     QXT_INIT_PRIVATE(QxtRPCPeer);
127     qxt_d().m_rpctype = type;
128     qxt_d().m_peer = device;
129
130     if (qobject_cast<QAbstractSocket *>(device)!=0)
131     {
132         QObject::connect(qxt_d().m_peer, SIGNAL(connected()), this, SIGNAL(peerConnected()));
133         QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SIGNAL(peerDisconnected()));
134         QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SLOT(disconnectSender()));
135         QObject::connect(qxt_d().m_peer, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(peerError(QAbstractSocket::SocketError)));
136     }
137     QObject::connect(qxt_d().m_peer, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
138 }
139
140
141 void QxtRPCPeer::setRPCType(RPCTypes type)
142 {
143     if (qxt_d().m_peer->isOpen () || qxt_d().isListening())
144     {
145         qWarning() << "QxtRPCPeer: Cannot change RPC types while connected or listening";
146         return;
147     }
148     qxt_d().m_rpctype = type;
149 }
150
151
152 QxtRPCPeer::RPCTypes QxtRPCPeer::rpcType() const
153 {
154     return (RPCTypes)(qxt_d().m_rpctype);
155 }
156
157
158 void QxtRPCPeer::connect(QHostAddress addr, int port)
159 {
160     if (qxt_d().m_rpctype == Server)
161     {
162         qWarning() << "QxtRPCPeer: Cannot connect outward in Server mode";
163         return;
164     }
165
166     QAbstractSocket * sock  = qobject_cast<QAbstractSocket*>(qxt_d().m_peer);
167     if (!sock)
168     {
169         qWarning("QxtRPCPeer: cannot connect a custom QIODevice");
170         return;
171     }
172
173     if (sock->state()!=QAbstractSocket::UnconnectedState)
174     {
175         qWarning("QxtRPCPeer: Already connected");
176         return;
177     }
178
179     sock->connectToHost(addr, port);
180 }
181
182
183 bool QxtRPCPeer::listen(QHostAddress iface, int port)
184 {
185     if (qxt_d().m_rpctype == Client)
186     {
187         qWarning() << "QxtRPCPeer: Cannot listen in Client mode";
188         return false;
189     }
190     else if (qxt_d().m_rpctype == Peer && qxt_d().m_peer->isOpen ())
191     {
192         qWarning() << "QxtRPCPeer: Cannot listen while connected to a peer";
193         return false;
194     }
195     else if (qxt_d().isListening())
196     {
197         qWarning() << "QxtRPCPeer: Already listening";
198         return false;
199     }
200     return qxt_d().listen(iface, port);
201 }
202
203
204 void QxtRPCPeer::disconnectPeer(quint64 id)
205 {
206     if (qxt_d().m_rpctype == Server && id==(quint64)-1)
207     {
208         qWarning() << "QxtRPCPeer: Server mode does not have a peer";
209         return;
210     }
211     else if (qxt_d().m_rpctype!= Server && id!=(quint64)-1)
212     {
213         qWarning() << "QxtRPCPeer: Must specify a client ID to disconnect";
214         return;
215     }
216     QxtRPCConnection* conn;
217     if (id==(quint64)-1)
218     {
219         qxt_d().m_peer->close();
220         ///hackaround for qt bug
221         QAbstractSocket *s =qobject_cast<QAbstractSocket*>( qxt_d().m_peer);
222         if (s)
223             s->disconnectFromHost();
224
225     }
226     else if ((conn = qxt_d().m_clients.take((QObject*)(id)))!= 0)
227     {
228         conn->socket->disconnectFromHost();
229         conn->socket->deleteLater();
230         delete conn;
231     }
232     else
233     {
234         qWarning() << "QxtRPCPeer: no client with id " << id;
235     }
236 }
237
238
239 void QxtRPCPeer::disconnectAll()
240 {
241     if (qxt_d().m_rpctype!= Server)
242         disconnectPeer();
243     else
244     {
245         for (QxtRPCPeerPrivate::ConnHash::const_iterator i = qxt_d().m_clients.constBegin(); i!= qxt_d().m_clients.constEnd(); i++)
246         {
247             (*i)->socket->deleteLater();
248             delete *i;
249         }
250         qxt_d().m_clients.clear();
251     }
252 }
253
254
255 void QxtRPCPeer::stopListening()
256 {
257     if (!qxt_d().isListening())
258     {
259         qWarning() << "QxtRPCPeer: Not listening";
260         return;
261     }
262     qxt_d().close();
263 }
264
265
266 bool QxtRPCPeer::attachSignal(QObject* sender, const char* signal, const QByteArray& rpcFunction)
267 {
268     const QMetaObject* meta = sender->metaObject();
269     QByteArray sig(meta->normalizedSignature(signal).mid(1));
270     int methodID = meta->indexOfMethod(sig.constData());
271     if (methodID == -1 || meta->method(methodID).methodType() != QMetaMethod::Signal)
272     {
273         qWarning() << "QxtRPCPeer::attachSignal: No such signal " << signal;
274         return false;
275     }
276
277
278     QxtIntrospector* spec = new QxtIntrospector(this, sender, signal);
279     if (!rpcFunction.isEmpty())
280     {
281         if (QxtMetaObject::isSignalOrSlot(rpcFunction.constData()))
282         {
283             spec->rpcFunction = QMetaObject::normalizedSignature(rpcFunction);
284         }
285         else
286         {
287             spec->rpcFunction  = rpcFunction.simplified();
288         }
289     }
290     else
291     {
292         spec->rpcFunction = QMetaObject::normalizedSignature(signal);
293     }
294     qxt_d().attachedSignals.insertMulti(sender, spec);
295     return true;
296 }
297
298
299 bool QxtRPCPeer::attachSlot(const QByteArray& rpcFunction, QObject* recv, const char* slot)
300 {
301     const QMetaObject* meta = recv->metaObject();
302     int methodID = meta->indexOfMethod(meta->normalizedSignature(slot).mid(1));
303     if (methodID == -1 || meta->method(methodID).methodType() == QMetaMethod::Method)
304     {
305         qWarning() << "QxtRPCPeer::attachSlot: No such slot " << slot;
306         return false;
307     }
308
309     QString fn;
310
311     if (QxtMetaObject::isSignalOrSlot(rpcFunction.constData()))
312     {
313         fn = QMetaObject::normalizedSignature(rpcFunction.constData());
314     }
315     else
316     {
317         fn = rpcFunction.simplified();
318     }
319
320     qxt_d().attachedSlots[fn].append(QPair<QObject*, int>(recv, recv->metaObject()->indexOfMethod(recv->metaObject()->normalizedSignature(slot).mid(1))));
321     return true;
322 }
323
324
325 void QxtRPCPeer::detachSender()
326 {
327     detachObject(sender());
328 }
329
330
331 void QxtRPCPeer::detachObject(QObject* obj)
332 {
333     foreach(QxtIntrospector* i, qxt_d().attachedSignals.values(obj)) i->deleteLater();
334     qxt_d().attachedSignals.remove(obj);
335     foreach(QString slot, qxt_d().attachedSlots.keys())
336     {
337         for (QList<QPair<QObject*, int> >::iterator i(qxt_d().attachedSlots[slot].begin());
338                 i!= qxt_d().attachedSlots[slot].end(); )
339         {
340             if ((*i).first == obj)
341                 i = qxt_d().attachedSlots[slot].erase(i);
342             else
343                 i++;
344         }
345     }
346 }
347
348
349 QByteArray QxtRPCPeer::serialize(QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9) const
350 {
351     QByteArray rv;
352     QDataStream str(&rv, QIODevice::WriteOnly);
353     str << fn;
354     unsigned char ct = 9;
355     if (p1.isNull()) ct = 0;
356     else if (p2.isNull()) ct = 1;
357     else if (p3.isNull()) ct = 2;
358     else if (p4.isNull()) ct = 3;
359     else if (p5.isNull()) ct = 4;
360     else if (p6.isNull()) ct = 5;
361     else if (p7.isNull()) ct = 6;
362     else if (p8.isNull()) ct = 7;
363     else if (p9.isNull()) ct = 8;
364     str << ct;
365     if (ct-- >0 ) str << p1;
366     if (ct-- >0) str << p2;
367     if (ct-- >0) str << p3;
368     if (ct-- >0) str << p4;
369     if (ct-- >0) str << p5;
370     if (ct-- >0) str << p6;
371     if (ct-- >0) str << p7;
372     if (ct-- >0) str << p8;
373     if (ct-- >0) str << p9;
374     rv.replace(QByteArray("\\"), QByteArray("\\\\"));
375     rv.replace(QByteArray("\n"), QByteArray("\\n"));
376     rv.append("\n");
377     return rv;
378 }
379
380
381 void QxtRPCPeer::call(const char * signal , QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9)
382 {
383
384     QByteArray sig=QMetaObject::normalizedSignature(signal);
385
386     QAbstractSocket * sock  = qobject_cast<QAbstractSocket*>(qxt_d().m_peer);
387     if (!qxt_d().m_peer->isOpen () || ( sock && sock->state()!=QAbstractSocket::ConnectedState ))
388     {
389         qWarning("can't call on a closed device");
390         return;
391     }
392     qxt_d().m_peer->write(serialize(sig, p1, p2, p3, p4, p5, p6, p7, p8, p9));
393 }
394
395
396 void QxtRPCPeer::callClientList(QList<quint64> ids, QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8)
397 {
398     QByteArray c = serialize(fn, p1, p2, p3, p4, p5, p6, p7, p8, QVariant());
399     foreach(quint64 id, ids)
400     {
401         QxtRPCConnection* conn = qxt_d().m_clients.value((QObject*)(id));
402         if (!conn)
403         {
404             qWarning() << "QxtRPCPeer: no client with id" << id;
405         }
406         else
407         {
408             conn->socket->write(c);
409         }
410     }
411 }
412
413
414 void QxtRPCPeer::callClient(quint64 id, QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8)
415 {
416     callClientList(QList<quint64>() << id, fn, p1, p2, p3, p4, p5, p6, p7, p8);
417 }
418
419
420 void QxtRPCPeer::callClientsExcept(quint64 id, QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8)
421 {
422     QList<quint64> cs = clients();
423     cs.removeAll(id);
424     callClientList(cs, fn, p1, p2, p3, p4, p5, p6, p7, p8);
425 }
426
427
428 #define QXT_ARG(i) ((numParams>i)?QGenericArgument(p ## i .typeName(), p ## i .constData()):QGenericArgument())
429 void QxtRPCPeerPrivate::receivePeerSignal(QString fn, QVariant p0, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8) const
430 {
431     QByteArray sig;
432     int numParams;
433     foreach(QxtRPCPeerPrivate::MethodID i, attachedSlots.value(fn))
434     {
435         sig = i.first->metaObject()->method(i.second).signature();
436         sig = sig.left(sig.indexOf('('));
437         numParams = i.first->metaObject()->method(i.second).parameterTypes().count();
438         if(!QMetaObject::invokeMethod(i.first, sig, QXT_ARG(0), QXT_ARG(1), QXT_ARG(2), QXT_ARG(3), QXT_ARG(4), QXT_ARG(5), QXT_ARG(6), QXT_ARG(7), QXT_ARG(8)))
439         {
440             qWarning("QxtRPCPeerPrivate::receivePeerSignal: invokeMethod for \"%s\" failed ",sig.constData());
441         }
442     }
443 }
444
445
446 void QxtRPCPeerPrivate::receiveClientSignal(quint64 id, QString fn, QVariant p0, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7) const
447 {
448     QByteArray sig;
449     int numParams;
450     foreach(QxtRPCPeerPrivate::MethodID i, attachedSlots.value(fn))
451     {
452         sig = i.first->metaObject()->method(i.second).signature();
453         sig = sig.left(sig.indexOf('('));
454         numParams = i.first->metaObject()->method(i.second).parameterTypes().count();
455         if(!QMetaObject::invokeMethod(i.first, sig, Q_ARG(quint64, id), QXT_ARG(0), QXT_ARG(1), QXT_ARG(2), QXT_ARG(3), QXT_ARG(4), QXT_ARG(5), QXT_ARG(6), QXT_ARG(7)))
456         {
457             qWarning("QxtRPCPeerPrivate::receiveClientSignal: invokeMethod for \"%s\" failed ",sig.constData());
458         }
459     }
460 }
461
462
463 #undef QXT_ARG
464
465 void QxtRPCPeerPrivate::incomingConnection ( int socketDescriptor )
466 {
467     QTcpSocket* next = qxt_p().incomingConnection(socketDescriptor);
468     if (m_rpctype == QxtRPCPeer::Peer)
469     {
470         if (m_peer->isOpen ())
471         {
472             qWarning() << "QxtRPCPeer: Rejected connection from " << next->peerAddress().toString() << "; another peer is connected";
473             next->disconnectFromHost();
474             next->deleteLater();
475         }
476         else
477         {
478             m_peer->deleteLater();
479             m_peer = next;
480             QObject::connect(m_peer, SIGNAL(connected()), &qxt_p(), SIGNAL(peerConnected()));
481             QObject::connect(m_peer, SIGNAL(disconnected()), &qxt_p(), SIGNAL(peerDisconnected()));
482             QObject::connect(m_peer, SIGNAL(disconnected()), &qxt_p(), SLOT(disconnectSender()));
483             QObject::connect(m_peer, SIGNAL(readyRead()), &qxt_p(), SLOT(dataAvailable()));
484             QObject::connect(m_peer, SIGNAL(error(QAbstractSocket::SocketError)), &qxt_p(), SIGNAL(peerError(QAbstractSocket::SocketError)));
485             emit qxt_p().peerConnected();
486         }
487     }
488     else
489     {
490         QxtRPCConnection* conn = new QxtRPCConnection;
491         conn->socket = next;
492         m_clients[next] = conn;
493         QObject::connect(next, SIGNAL(disconnected()), &qxt_p(), SLOT(disconnectSender()));
494         QObject::connect(next, SIGNAL(readyRead()), &qxt_p(), SLOT(dataAvailable()));
495         QObject::connect(next, SIGNAL(error(QAbstractSocket::SocketError)), &qxt_p(), SIGNAL(peerError(QAbstractSocket::SocketError)));
496         emit qxt_p().clientConnected((quint64)(next));
497     }
498 }
499
500
501 void QxtRPCPeer::dataAvailable()
502 {
503     if (qxt_d().m_rpctype!=QxtRPCPeer::Server && qxt_d().m_peer==sender())
504     {
505         qxt_d().m_buffer.append(qxt_d().m_peer->readAll());
506         qxt_d().processInput(qxt_d().m_peer, qxt_d().m_buffer);
507         return;
508     }
509     else
510     {
511         QxtRPCConnection* conn = qxt_d().m_clients.value(sender());
512         if (!conn)
513         {
514             qWarning() << "QxtRPCPeer: Unrecognized client object connected to dataAvailable";
515             return;
516         }
517         conn->buffer.append(conn->socket->readAll());
518         qxt_d().processInput(conn->socket, (conn->buffer));
519         return;
520     }
521     qWarning() << "QxtRPCPeer: Unrecognized peer object connected to dataAvailable";
522 }
523
524
525 void QxtRPCPeer::disconnectSender()
526 {
527     QxtRPCConnection* conn = qxt_d().m_clients.value(sender());
528     if (!conn)
529     {
530         if (qxt_d().m_peer!= qobject_cast<QIODevice*>(sender()))
531         {
532             qWarning() << "QxtRPCPeer: Unrecognized object connected to disconnectSender";
533             return;
534         }
535         qxt_d().m_buffer.append(qxt_d().m_peer->readAll());
536         qxt_d().m_buffer.append("\n");
537         qxt_d().processInput(qxt_d().m_peer, qxt_d().m_buffer);
538         qxt_d().m_buffer.clear();
539         emit clientDisconnected((quint64)(sender()));
540         return;
541     }
542     conn->buffer.append(conn->socket->readAll());
543     conn->buffer.append("\n");
544     qxt_d().processInput(conn->socket, conn->buffer);
545     conn->socket->deleteLater();
546     delete conn;
547     qxt_d().m_clients.remove(sender());
548 }
549
550
551 void QxtRPCPeerPrivate::processInput(QIODevice* socket, QByteArray& buffer)
552 {
553     while (qxt_p().canDeserialize(buffer))
554     {
555         QPair<QString, QList<QVariant> > sig = qxt_p().deserialize(buffer);
556         if (sig.first.isEmpty())
557         {
558             if (sig.second.count())
559             {
560                 qWarning() << "QxtRPCPeer: Invalid data received; disconnecting";
561                 if (socket == m_peer)
562                     qxt_p().disconnectPeer();
563                 else
564                     qxt_p().disconnectPeer((quint64)(socket));
565                 return;
566             }
567             continue;
568         }
569         while (sig.second.count() < 9) sig.second << QVariant();
570         if (socket == m_peer)
571         {
572             receivePeerSignal(sig.first, sig.second[0], sig.second[1], sig.second[2], sig.second[3], sig.second[4], sig.second[5], sig.second[6], sig.second[7], sig.second[8]);
573         }
574         else
575         {
576             receiveClientSignal((quint64)(socket), sig.first, sig.second[0], sig.second[1], sig.second[2], sig.second[3], sig.second[4], sig.second[5], sig.second[6], sig.second[7]);
577         }
578     }
579 }
580
581
582 QList<quint64> QxtRPCPeer::clients() const
583 {
584     QList<quint64> rv;
585     QList<QObject*> cs = qxt_d().m_clients.keys();
586     foreach(QObject* id, cs) rv << (const quint64)(id);
587     return rv;
588 }
589
590
591 QxtIntrospector::QxtIntrospector(QxtRPCPeer* parent, QObject* source, const char* signal): QObject(parent)
592 {
593     peer = parent;
594     QByteArray sig_ba = QMetaObject::normalizedSignature(QByteArray(signal).mid(1));
595     const char * sig=sig_ba.constData();
596     int idx = source->metaObject()->indexOfSignal(sig);
597     if (idx<0)
598         qWarning("no such signal: %s",sig_ba.constData());
599
600 // Our "method" will have the first ID not used by the superclass.
601     QMetaObject::connect(source, idx, this, QObject::staticMetaObject.methodCount());
602     QObject::connect(source, SIGNAL(destroyed()), peer, SLOT(detachSender()));
603     QList<QByteArray> p = source->metaObject()->method(idx).parameterTypes();
604     int ct = p.count();
605     for (int i=0; i<ct; i++) argTypes.append(QMetaType::type(p.value(i).constData()));
606 }
607
608
609 int QxtIntrospector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
610 {
611     _id = QObject::qt_metacall(_c, _id, _a);
612     if (_id < 0)
613         return _id;
614     if (_c == QMetaObject::InvokeMetaMethod)
615     {
616         if (_id==0)
617         {
618             QVariant v[9];
619             int n = argTypes.size();
620             for (int i=0; i<n; i++) v[i] = QVariant(argTypes[i], _a[i+1]);
621             peer->call(rpcFunction.toUtf8().constData(), v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
622         }
623         _id -= 1;
624     }
625     return _id;
626 }
627
628
629 QPair<QString, QList<QVariant> > QxtRPCPeer::deserialize(QByteArray& data)
630 {
631     QByteArray cmd;
632     int pos = data.indexOf('\n');
633     cmd = data.left(pos-1);
634     data = data.mid(pos+1);
635     if (cmd.length()==0) return qMakePair(QString(), QList<QVariant>());
636     cmd.replace(QByteArray("\\n"), QByteArray("\n"));
637     cmd.replace(QByteArray("\\\\"), QByteArray("\\"));
638     QDataStream str(cmd);
639     QString signal;
640     unsigned char argCount;
641     QList<QVariant> v;
642     QVariant t;
643     str >> signal >> argCount;
644
645     if (str.status() == QDataStream::ReadCorruptData)
646     {
647         v << QVariant();
648         return qMakePair(QString(), v);
649     }
650
651     for (int i=0; i<argCount; i++)
652     {
653         str >> t;
654         v << t;
655     }
656     return qMakePair(signal, v);
657 }
658
659
660 bool QxtRPCPeer::canDeserialize(const QByteArray& buffer) const
661 {
662     if (buffer.indexOf('\n') == -1)
663     {
664         return false;
665     }
666     return true;
667
668 }
669
670
671
672
673 QIODevice * QxtRPCPeer::socket()
674 {
675     if (qxt_d().m_rpctype == Server)return 0;
676     return qxt_d().m_peer;
677 }
678
679
680
681
682 QTcpSocket * QxtRPCPeer::incomingConnection ( int socketDescriptor )
683 {
684     QTcpSocket * t = new QTcpSocket;
685     t->setSocketDescriptor (socketDescriptor);
686     return t;
687 }
688
689
690
691
692 const QTcpSocket * QxtRPCPeer::clientSocket(quint64 id) const
693     {
694     if (qxt_d().m_rpctype != Server)
695         return 0;
696
697     return  qxt_d().m_clients[(QTcpSocket*)(id)]->socket;
698     }
699 QList<quint64> QxtRPCPeer::clients()
700     {
701     QList<quint64> list;
702     foreach(QObject * o,qxt_d().m_clients.keys ())
703         {
704         list.append((quint64)o);
705         }
706     return list;
707     }
708
709
710