YES! We finally have dynamic signals between Core and Client, meaning that arbitrary
[quassel.git] / src / contrib / qxt / 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.constData());
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--) str << p1;
366     if (ct--) str << p2;
367     if (ct--) str << p3;
368     if (ct--) str << p4;
369     if (ct--) str << p5;
370     if (ct--) str << p6;
371     if (ct--) str << p7;
372     if (ct--) str << p8;
373     if (ct--) 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 #include <QStringList>
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     if(!attachedSlots.value(fn).count()) qDebug() << "no attached slot for signal" << fn;// qDebug() << attachedSlots;
434     foreach(QxtRPCPeerPrivate::MethodID i, attachedSlots.value(fn))
435     {
436         sig = i.first->metaObject()->method(i.second).signature();
437         sig = sig.left(sig.indexOf('('));
438         numParams = i.first->metaObject()->method(i.second).parameterTypes().count(); //qDebug() << "calling" << fn << p0 << p1 << p2;
439         bool res = 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));
440         if(!res) qDebug() << "rpccall failed" << fn << sig << p0 << p1  << p2;
441     }
442 }
443
444
445 void QxtRPCPeerPrivate::receiveClientSignal(quint64 id, QString fn, QVariant p0, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7) const
446 {
447     QByteArray sig;
448     int numParams;
449     foreach(QxtRPCPeerPrivate::MethodID i, attachedSlots.value(fn))
450     {
451         sig = i.first->metaObject()->method(i.second).signature();
452         sig = sig.left(sig.indexOf('('));
453         numParams = i.first->metaObject()->method(i.second).parameterTypes().count();
454         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));
455     }
456 }
457
458
459 #undef QXT_ARG
460
461 void QxtRPCPeerPrivate::incomingConnection ( int socketDescriptor )
462 {
463     QTcpSocket* next = qxt_p().incomingConnection(socketDescriptor);
464     if (m_rpctype == QxtRPCPeer::Peer)
465     {
466         if (m_peer->isOpen ())
467         {
468             qWarning() << "QxtRPCPeer: Rejected connection from " << next->peerAddress().toString() << "; another peer is connected";
469             next->disconnectFromHost();
470             next->deleteLater();
471         }
472         else
473         {
474             m_peer->deleteLater();
475             m_peer = next;
476             QObject::connect(m_peer, SIGNAL(connected()), &qxt_p(), SIGNAL(peerConnected()));
477             QObject::connect(m_peer, SIGNAL(disconnected()), &qxt_p(), SIGNAL(peerDisconnected()));
478             QObject::connect(m_peer, SIGNAL(disconnected()), &qxt_p(), SLOT(disconnectSender()));
479             QObject::connect(m_peer, SIGNAL(readyRead()), &qxt_p(), SLOT(dataAvailable()));
480             QObject::connect(m_peer, SIGNAL(error(QAbstractSocket::SocketError)), &qxt_p(), SIGNAL(peerError(QAbstractSocket::SocketError)));
481             emit qxt_p().peerConnected();
482         }
483     }
484     else
485     {
486         QxtRPCConnection* conn = new QxtRPCConnection;
487         conn->socket = next;
488         m_clients[next] = conn;
489         QObject::connect(next, SIGNAL(disconnected()), &qxt_p(), SLOT(disconnectSender()));
490         QObject::connect(next, SIGNAL(readyRead()), &qxt_p(), SLOT(dataAvailable()));
491         QObject::connect(next, SIGNAL(error(QAbstractSocket::SocketError)), &qxt_p(), SIGNAL(peerError(QAbstractSocket::SocketError)));
492         emit qxt_p().clientConnected((quint64)(next));
493     }
494 }
495
496
497 void QxtRPCPeer::dataAvailable()
498 {
499     if (qxt_d().m_rpctype!=QxtRPCPeer::Server && qxt_d().m_peer==sender())
500     {
501         qxt_d().m_buffer.append(qxt_d().m_peer->readAll());
502         qxt_d().processInput(qxt_d().m_peer, qxt_d().m_buffer);
503         return;
504     }
505     else
506     {
507         QxtRPCConnection* conn = qxt_d().m_clients.value(sender());
508         if (!conn)
509         {
510             qWarning() << "QxtRPCPeer: Unrecognized client object connected to dataAvailable";
511             return;
512         }
513         conn->buffer.append(conn->socket->readAll());
514         qxt_d().processInput(conn->socket, (conn->buffer));
515         return;
516     }
517     qWarning() << "QxtRPCPeer: Unrecognized peer object connected to dataAvailable";
518 }
519
520
521 void QxtRPCPeer::disconnectSender()
522 {
523     QxtRPCConnection* conn = qxt_d().m_clients.value(sender());
524     if (!conn)
525     {
526         if (qxt_d().m_peer!= qobject_cast<QAbstractSocket*>(sender()))  // SPUT: why not QTcpSocket*?
527         {
528             qWarning() << "QxtRPCPeer: Unrecognized object connected to disconnectSender";
529             return;
530         }
531         qxt_d().m_buffer.append(qxt_d().m_peer->readAll());
532         qxt_d().m_buffer.append("\n");
533         qxt_d().processInput(qxt_d().m_peer, qxt_d().m_buffer);
534         qxt_d().m_buffer.clear();
535         emit clientDisconnected((quint64)(sender()));
536         return;
537     }
538     conn->buffer.append(conn->socket->readAll());
539     conn->buffer.append("\n");
540     qxt_d().processInput(conn->socket, conn->buffer);
541     conn->socket->deleteLater();
542     delete conn;
543     qxt_d().m_clients.remove(sender());
544 }
545
546
547 void QxtRPCPeerPrivate::processInput(QIODevice* socket, QByteArray& buffer)
548 {
549     while (qxt_p().canDeserialize(buffer))
550     {
551         QPair<QString, QList<QVariant> > sig = qxt_p().deserialize(buffer);
552         if (sig.first.isEmpty())
553         {
554             if (sig.second.count())
555             {
556                 qWarning() << "QxtRPCPeer: Invalid data received; disconnecting";
557                 if (socket == m_peer)
558                     qxt_p().disconnectPeer();
559                 else
560                     qxt_p().disconnectPeer((quint64)(socket));
561                 return;
562             }
563             continue;
564         }
565         while (sig.second.count() < 9) sig.second << QVariant();
566         if (socket == m_peer)
567         {
568             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]);
569         }
570         else
571         {
572             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]);
573         }
574     }
575 }
576
577
578 QList<quint64> QxtRPCPeer::clients() const
579 {
580     QList<quint64> rv;
581     QList<QObject*> cs = qxt_d().m_clients.keys();
582     foreach(QObject* id, cs) rv << (const quint64)(id);
583     return rv;
584 }
585
586
587 QxtIntrospector::QxtIntrospector(QxtRPCPeer* parent, QObject* source, const char* signal): QObject(parent)
588 {
589     peer = parent;
590     QByteArray sig_ba = QMetaObject::normalizedSignature(QByteArray(signal).mid(1));
591     const char * sig=sig_ba.constData();
592     int idx = source->metaObject()->indexOfSignal(sig);
593     if (idx<0)
594         qWarning("no such signal: %s",sig_ba.constData());
595
596 // Our "method" will have the first ID not used by the superclass.
597     QMetaObject::connect(source, idx, this, QObject::staticMetaObject.methodCount());
598     QObject::connect(source, SIGNAL(destroyed()), peer, SLOT(detachSender()));
599     QList<QByteArray> p = source->metaObject()->method(idx).parameterTypes();
600     int ct = p.count();
601     for (int i=0; i<ct; i++) argTypes.append(QMetaType::type(p.value(i).constData()));
602 }
603
604
605 int QxtIntrospector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
606 {
607     _id = QObject::qt_metacall(_c, _id, _a);
608     if (_id < 0)
609         return _id;
610     if (_c == QMetaObject::InvokeMetaMethod)
611     {
612         if (_id==0)
613         {
614             QVariant v[9];
615             int n = argTypes.size();
616             for (int i=0; i<n; i++) v[i] = QVariant(argTypes[i], _a[i+1]);
617             peer->call(rpcFunction.toUtf8().constData(), v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
618         }
619         _id -= 1;
620     }
621     return _id;
622 }
623
624
625 QPair<QString, QList<QVariant> > QxtRPCPeer::deserialize(QByteArray& data)
626 {
627     QByteArray cmd;
628     int pos = data.indexOf('\n');
629     cmd = data.left(pos-1);
630     data = data.mid(pos+1);
631     if (cmd.length()==0) return qMakePair(QString(), QList<QVariant>());
632     cmd.replace(QByteArray("\\n"), QByteArray("\n"));
633     cmd.replace(QByteArray("\\\\"), QByteArray("\\"));
634     QDataStream str(cmd);
635     QString signal;
636     unsigned char argCount;
637     QList<QVariant> v;
638     QVariant t;
639     str >> signal >> argCount;
640
641     if (str.status() == QDataStream::ReadCorruptData)
642     {
643         v << QVariant();
644         return qMakePair(QString(), v);
645     }
646
647     for (int i=0; i<argCount; i++)
648     {
649         str >> t;
650         v << t;
651     }
652     return qMakePair(signal, v);
653 }
654
655
656 bool QxtRPCPeer::canDeserialize(const QByteArray& buffer) const
657 {
658     if (buffer.indexOf('\n') == -1)
659     {
660         return false;
661     }
662     return true;
663
664 }
665
666
667
668
669 QIODevice * QxtRPCPeer::socket()
670 {
671     if (qxt_d().m_rpctype == Server)return 0;
672     return qxt_d().m_peer;
673 }
674
675
676
677
678 QTcpSocket * QxtRPCPeer::incomingConnection ( int socketDescriptor )
679 {
680     QTcpSocket * t = new QTcpSocket;
681     t->setSocketDescriptor (socketDescriptor);
682     return t;
683 }
684
685
686
687
688 const QTcpSocket * QxtRPCPeer::clientSocket(quint64 id) const
689     {
690     if (qxt_d().m_rpctype != Server)
691         return 0;
692
693     return  qxt_d().m_clients[(QTcpSocket*)(id)]->socket;
694     }
695 QList<quint64> QxtRPCPeer::clients()
696     {
697     QList<quint64> list;
698     foreach(QObject * o,qxt_d().m_clients.keys ())
699         {
700         list.append((quint64)o);
701         }
702     return list;
703     }
704
705
706