Committing my current state just in case. Mostly work on qtopia, nothing special
[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     //qDebug() << device->metaObject()->className();
130
131     if (qobject_cast<QAbstractSocket *>(device)!=0)
132     {
133         QObject::connect(qxt_d().m_peer, SIGNAL(connected()), this, SIGNAL(peerConnected()));
134         QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SIGNAL(peerDisconnected()));
135         QObject::connect(qxt_d().m_peer, SIGNAL(disconnected()), this, SLOT(disconnectSender()));
136         QObject::connect(qxt_d().m_peer, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(peerError(QAbstractSocket::SocketError)));
137     }
138     QObject::connect(qxt_d().m_peer, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
139 }
140
141
142 void QxtRPCPeer::setRPCType(RPCTypes type)
143 {
144     if (qxt_d().m_peer->isOpen () || qxt_d().isListening())
145     {
146         qWarning() << "QxtRPCPeer: Cannot change RPC types while connected or listening";
147         return;
148     }
149     qxt_d().m_rpctype = type;
150 }
151
152
153 QxtRPCPeer::RPCTypes QxtRPCPeer::rpcType() const
154 {
155     return (RPCTypes)(qxt_d().m_rpctype);
156 }
157
158
159 void QxtRPCPeer::connect(QHostAddress addr, int port)
160 {
161     if (qxt_d().m_rpctype == Server)
162     {
163         qWarning() << "QxtRPCPeer: Cannot connect outward in Server mode";
164         return;
165     }
166
167     QAbstractSocket * sock  = qobject_cast<QAbstractSocket*>(qxt_d().m_peer);
168     if (!sock)
169     {
170         qWarning("QxtRPCPeer: cannot connect a custom QIODevice");
171         return;
172     }
173
174     if (sock->state()!=QAbstractSocket::UnconnectedState)
175     {
176         qWarning("QxtRPCPeer: Already connected");
177         return;
178     }
179
180     sock->connectToHost(addr, port);
181 }
182
183
184 bool QxtRPCPeer::listen(QHostAddress iface, int port)
185 {
186     if (qxt_d().m_rpctype == Client)
187     {
188         qWarning() << "QxtRPCPeer: Cannot listen in Client mode";
189         return false;
190     }
191     else if (qxt_d().m_rpctype == Peer && qxt_d().m_peer->isOpen ())
192     {
193         qWarning() << "QxtRPCPeer: Cannot listen while connected to a peer";
194         return false;
195     }
196     else if (qxt_d().isListening())
197     {
198         qWarning() << "QxtRPCPeer: Already listening";
199         return false;
200     }
201     return qxt_d().listen(iface, port);
202 }
203
204
205 void QxtRPCPeer::disconnectPeer(quint64 id)
206 {
207     if (qxt_d().m_rpctype == Server && id==(quint64)-1)
208     {
209         qWarning() << "QxtRPCPeer: Server mode does not have a peer";
210         return;
211     }
212     else if (qxt_d().m_rpctype!= Server && id!=(quint64)-1)
213     {
214         qWarning() << "QxtRPCPeer: Must specify a client ID to disconnect";
215         return;
216     }
217     QxtRPCConnection* conn;
218     if (id==(quint64)-1)
219     {
220         qxt_d().m_peer->close();
221         ///hackaround for qt bug
222         QAbstractSocket *s =qobject_cast<QAbstractSocket*>( qxt_d().m_peer);
223         if (s)
224             s->disconnectFromHost();
225
226     }
227     else if ((conn = qxt_d().m_clients.take((QObject*)(id)))!= 0)
228     {
229         conn->socket->disconnectFromHost();
230         conn->socket->deleteLater();
231         delete conn;
232     }
233     else
234     {
235         qWarning() << "QxtRPCPeer: no client with id " << id;
236     }
237 }
238
239
240 void QxtRPCPeer::disconnectAll()
241 {
242     if (qxt_d().m_rpctype!= Server)
243         disconnectPeer();
244     else
245     {
246         for (QxtRPCPeerPrivate::ConnHash::const_iterator i = qxt_d().m_clients.constBegin(); i!= qxt_d().m_clients.constEnd(); i++)
247         {
248             (*i)->socket->deleteLater();
249             delete *i;
250         }
251         qxt_d().m_clients.clear();
252     }
253 }
254
255
256 void QxtRPCPeer::stopListening()
257 {
258     if (!qxt_d().isListening())
259     {
260         qWarning() << "QxtRPCPeer: Not listening";
261         return;
262     }
263     qxt_d().close();
264 }
265
266
267 bool QxtRPCPeer::attachSignal(QObject* sender, const char* signal, const QByteArray& rpcFunction)
268 {
269     const QMetaObject* meta = sender->metaObject();
270     QByteArray sig(meta->normalizedSignature(signal).mid(1));
271     int methodID = meta->indexOfMethod(sig.constData());
272     if (methodID == -1 || meta->method(methodID).methodType() != QMetaMethod::Signal)
273     {
274         qWarning() << "QxtRPCPeer::attachSignal: No such signal " << signal;
275         return false;
276     }
277
278
279     QxtIntrospector* spec = new QxtIntrospector(this, sender, signal);
280     if (!rpcFunction.isEmpty())
281     {
282         if (QxtMetaObject::isSignalOrSlot(rpcFunction.constData()))
283         {
284             spec->rpcFunction = QMetaObject::normalizedSignature(rpcFunction.constData());
285         }
286         else
287         {
288             spec->rpcFunction  = rpcFunction.simplified();
289         }
290     }
291     else
292     {
293         spec->rpcFunction = QMetaObject::normalizedSignature(signal);
294     }
295     qxt_d().attachedSignals.insertMulti(sender, spec);
296     return true;
297 }
298
299
300 bool QxtRPCPeer::attachSlot(const QByteArray& rpcFunction, QObject* recv, const char* slot)
301 {
302     const QMetaObject* meta = recv->metaObject();
303     int methodID = meta->indexOfMethod(meta->normalizedSignature(slot).mid(1));
304     if (methodID == -1 || meta->method(methodID).methodType() == QMetaMethod::Method)
305     {
306         qWarning() << "QxtRPCPeer::attachSlot: No such slot " << slot;
307         return false;
308     }
309
310     QString fn;
311
312     if (QxtMetaObject::isSignalOrSlot(rpcFunction.constData()))
313     {
314         fn = QMetaObject::normalizedSignature(rpcFunction.constData());
315     }
316     else
317     {
318         fn = rpcFunction.simplified();
319     }
320
321     qxt_d().attachedSlots[fn].append(QPair<QObject*, int>(recv, recv->metaObject()->indexOfMethod(recv->metaObject()->normalizedSignature(slot).mid(1))));
322     return true;
323 }
324
325
326 void QxtRPCPeer::detachSender()
327 {
328     detachObject(sender());
329 }
330
331
332 void QxtRPCPeer::detachObject(QObject* obj)
333 {
334     foreach(QxtIntrospector* i, qxt_d().attachedSignals.values(obj)) i->deleteLater();
335     qxt_d().attachedSignals.remove(obj);
336     foreach(QString slot, qxt_d().attachedSlots.keys())
337     {
338         for (QList<QPair<QObject*, int> >::iterator i(qxt_d().attachedSlots[slot].begin());
339                 i!= qxt_d().attachedSlots[slot].end(); )
340         {
341             if ((*i).first == obj)
342                 i = qxt_d().attachedSlots[slot].erase(i);
343             else
344                 i++;
345         }
346     }
347 }
348
349
350 QByteArray QxtRPCPeer::serialize(QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9) const
351 {
352     QByteArray rv;
353     QDataStream str(&rv, QIODevice::WriteOnly);
354     str << fn;
355     unsigned char ct = 9;
356     if (p1.isNull()) ct = 0;
357     else if (p2.isNull()) ct = 1;
358     else if (p3.isNull()) ct = 2;
359     else if (p4.isNull()) ct = 3;
360     else if (p5.isNull()) ct = 4;
361     else if (p6.isNull()) ct = 5;
362     else if (p7.isNull()) ct = 6;
363     else if (p8.isNull()) ct = 7;
364     else if (p9.isNull()) ct = 8;
365     str << ct;
366     if (ct--) str << p1;
367     if (ct--) str << p2;
368     if (ct--) str << p3;
369     if (ct--) str << p4;
370     if (ct--) str << p5;
371     if (ct--) str << p6;
372     if (ct--) str << p7;
373     if (ct--) str << p8;
374     if (ct--) str << p9;
375     rv.replace(QByteArray("\\"), QByteArray("\\\\"));
376     rv.replace(QByteArray("\n"), QByteArray("\\n"));
377     rv.append("\n");
378     return rv;
379 }
380
381
382 void QxtRPCPeer::call(const char * signal , QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8, QVariant p9)
383 {
384
385     QByteArray sig=QMetaObject::normalizedSignature(signal);
386
387     QAbstractSocket * sock  = qobject_cast<QAbstractSocket*>(qxt_d().m_peer);
388     if (!qxt_d().m_peer->isOpen () || ( sock && sock->state()!=QAbstractSocket::ConnectedState ))
389     {
390         qWarning("can't call on a closed device");
391         return;
392     }
393     qxt_d().m_peer->write(serialize(sig, p1, p2, p3, p4, p5, p6, p7, p8, p9));
394 }
395
396
397 void QxtRPCPeer::callClientList(QList<quint64> ids, QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8)
398 {
399     QByteArray c = serialize(fn, p1, p2, p3, p4, p5, p6, p7, p8, QVariant());
400     foreach(quint64 id, ids)
401     {
402         QxtRPCConnection* conn = qxt_d().m_clients.value((QObject*)(id));
403         if (!conn)
404         {
405             qWarning() << "QxtRPCPeer: no client with id" << id;
406         }
407         else
408         {
409             conn->socket->write(c);
410         }
411     }
412 }
413
414
415 void QxtRPCPeer::callClient(quint64 id, QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8)
416 {
417     callClientList(QList<quint64>() << id, fn, p1, p2, p3, p4, p5, p6, p7, p8);
418 }
419
420
421 void QxtRPCPeer::callClientsExcept(quint64 id, QString fn, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8)
422 {
423     QList<quint64> cs = clients();
424     cs.removeAll(id);
425     callClientList(cs, fn, p1, p2, p3, p4, p5, p6, p7, p8);
426 }
427
428 #include <QStringList>
429 #define QXT_ARG(i) ((numParams>i)?QGenericArgument(p ## i .typeName(), p ## i .constData()):QGenericArgument())
430 void QxtRPCPeerPrivate::receivePeerSignal(QString fn, QVariant p0, QVariant p1, QVariant p2, QVariant p3, QVariant p4, QVariant p5, QVariant p6, QVariant p7, QVariant p8) const
431 {
432     QByteArray sig;
433     int numParams;
434     if(!attachedSlots.value(fn).count()) qDebug() << "no attached slot for signal" << fn;// qDebug() << attachedSlots;
435     foreach(QxtRPCPeerPrivate::MethodID i, attachedSlots.value(fn))
436     {
437         sig = i.first->metaObject()->method(i.second).signature();
438         sig = sig.left(sig.indexOf('('));
439         numParams = i.first->metaObject()->method(i.second).parameterTypes().count(); //qDebug() << "calling" << fn << p0 << p1 << p2;
440         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));
441         if(!res) qDebug() << "rpccall failed" << fn << sig << p0 << p1  << p2;
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         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 }
458
459
460 #undef QXT_ARG
461
462 void QxtRPCPeerPrivate::incomingConnection ( int socketDescriptor )
463 {
464     QTcpSocket* next = qxt_p().incomingConnection(socketDescriptor);
465     if (m_rpctype == QxtRPCPeer::Peer)
466     {
467         if (m_peer->isOpen ())
468         {
469             qWarning() << "QxtRPCPeer: Rejected connection from " << next->peerAddress().toString() << "; another peer is connected";
470             next->disconnectFromHost();
471             next->deleteLater();
472         }
473         else
474         {
475             m_peer->deleteLater();
476             m_peer = next;
477             QObject::connect(m_peer, SIGNAL(connected()), &qxt_p(), SIGNAL(peerConnected()));
478             QObject::connect(m_peer, SIGNAL(disconnected()), &qxt_p(), SIGNAL(peerDisconnected()));
479             QObject::connect(m_peer, SIGNAL(disconnected()), &qxt_p(), SLOT(disconnectSender()));
480             QObject::connect(m_peer, SIGNAL(readyRead()), &qxt_p(), SLOT(dataAvailable()));
481             QObject::connect(m_peer, SIGNAL(error(QAbstractSocket::SocketError)), &qxt_p(), SIGNAL(peerError(QAbstractSocket::SocketError)));
482             emit qxt_p().peerConnected();
483         }
484     }
485     else
486     {
487         QxtRPCConnection* conn = new QxtRPCConnection;
488         conn->socket = next;
489         m_clients[next] = conn;
490         QObject::connect(next, SIGNAL(disconnected()), &qxt_p(), SLOT(disconnectSender()));
491         QObject::connect(next, SIGNAL(readyRead()), &qxt_p(), SLOT(dataAvailable()));
492         QObject::connect(next, SIGNAL(error(QAbstractSocket::SocketError)), &qxt_p(), SIGNAL(peerError(QAbstractSocket::SocketError)));
493         emit qxt_p().clientConnected((quint64)(next));
494     }
495 }
496
497
498 void QxtRPCPeer::dataAvailable()
499 {
500     if (qxt_d().m_rpctype!=QxtRPCPeer::Server && qxt_d().m_peer==sender())
501     {
502         qxt_d().m_buffer.append(qxt_d().m_peer->readAll());
503         qxt_d().processInput(qxt_d().m_peer, qxt_d().m_buffer);
504         return;
505     }
506     else
507     {
508         QxtRPCConnection* conn = qxt_d().m_clients.value(sender());
509         if (!conn)
510         {
511             qWarning() << "QxtRPCPeer: Unrecognized client object connected to dataAvailable";
512             return;
513         }
514         conn->buffer.append(conn->socket->readAll());
515         qxt_d().processInput(conn->socket, (conn->buffer));
516         return;
517     }
518     qWarning() << "QxtRPCPeer: Unrecognized peer object connected to dataAvailable";
519 }
520
521
522 void QxtRPCPeer::disconnectSender()
523 {
524     QxtRPCConnection* conn = qxt_d().m_clients.value(sender());
525     if (!conn)
526     {
527         //qDebug() << qxt_d().m_peer->metaObject()->className();
528         if (qxt_d().m_peer!= qobject_cast<QTcpSocket*>(sender()))
529         {
530             qWarning() << "QxtRPCPeer: Unrecognized object connected to disconnectSender";
531             return;
532         }
533         qxt_d().m_buffer.append(qxt_d().m_peer->readAll());
534         qxt_d().m_buffer.append("\n");
535         qxt_d().processInput(qxt_d().m_peer, qxt_d().m_buffer);
536         qxt_d().m_buffer.clear();
537         emit clientDisconnected((quint64)(sender()));
538         return;
539     }
540     conn->buffer.append(conn->socket->readAll());
541     conn->buffer.append("\n");
542     qxt_d().processInput(conn->socket, conn->buffer);
543     conn->socket->deleteLater();
544     delete conn;
545     qxt_d().m_clients.remove(sender());
546 }
547
548
549 void QxtRPCPeerPrivate::processInput(QIODevice* socket, QByteArray& buffer)
550 {
551     while (qxt_p().canDeserialize(buffer))
552     {
553         QPair<QString, QList<QVariant> > sig = qxt_p().deserialize(buffer);
554         if (sig.first.isEmpty())
555         {
556             if (sig.second.count())
557             {
558                 qWarning() << "QxtRPCPeer: Invalid data received; disconnecting";
559                 if (socket == m_peer)
560                     qxt_p().disconnectPeer();
561                 else
562                     qxt_p().disconnectPeer((quint64)(socket));
563                 return;
564             }
565             continue;
566         }
567         while (sig.second.count() < 9) sig.second << QVariant();
568         if (socket == m_peer)
569         {
570             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]);
571         }
572         else
573         {
574             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]);
575         }
576     }
577 }
578
579
580 QList<quint64> QxtRPCPeer::clients() const
581 {
582     QList<quint64> rv;
583     QList<QObject*> cs = qxt_d().m_clients.keys();
584     foreach(QObject* id, cs) rv << (const quint64)(id);
585     return rv;
586 }
587
588
589 QxtIntrospector::QxtIntrospector(QxtRPCPeer* parent, QObject* source, const char* signal): QObject(parent)
590 {
591     peer = parent;
592     QByteArray sig_ba = QMetaObject::normalizedSignature(QByteArray(signal).mid(1));
593     const char * sig=sig_ba.constData();
594     int idx = source->metaObject()->indexOfSignal(sig);
595     if (idx<0)
596         qWarning("no such signal: %s",sig_ba.constData());
597
598 // Our "method" will have the first ID not used by the superclass.
599     QMetaObject::connect(source, idx, this, QObject::staticMetaObject.methodCount());
600     QObject::connect(source, SIGNAL(destroyed()), peer, SLOT(detachSender()));
601     QList<QByteArray> p = source->metaObject()->method(idx).parameterTypes();
602     int ct = p.count();
603     for (int i=0; i<ct; i++) argTypes.append(QMetaType::type(p.value(i).constData()));
604 }
605
606
607 int QxtIntrospector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
608 {
609     _id = QObject::qt_metacall(_c, _id, _a);
610     if (_id < 0)
611         return _id;
612     if (_c == QMetaObject::InvokeMetaMethod)
613     {
614         if (_id==0)
615         {
616             QVariant v[9];
617             int n = argTypes.size();
618             for (int i=0; i<n; i++) v[i] = QVariant(argTypes[i], _a[i+1]);
619             peer->call(rpcFunction.toUtf8().constData(), v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
620         }
621         _id -= 1;
622     }
623     return _id;
624 }
625
626
627 QPair<QString, QList<QVariant> > QxtRPCPeer::deserialize(QByteArray& data)
628 {
629     QByteArray cmd;
630     int pos = data.indexOf('\n');
631     cmd = data.left(pos-1);
632     data = data.mid(pos+1);
633     if (cmd.length()==0) return qMakePair(QString(), QList<QVariant>());
634     cmd.replace(QByteArray("\\n"), QByteArray("\n"));
635     cmd.replace(QByteArray("\\\\"), QByteArray("\\"));
636     QDataStream str(cmd);
637     QString signal;
638     unsigned char argCount;
639     QList<QVariant> v;
640     QVariant t;
641     str >> signal >> argCount;
642
643     if (str.status() == QDataStream::ReadCorruptData)
644     {
645         v << QVariant();
646         return qMakePair(QString(), v);
647     }
648
649     for (int i=0; i<argCount; i++)
650     {
651         str >> t;
652         v << t;
653     }
654     return qMakePair(signal, v);
655 }
656
657
658 bool QxtRPCPeer::canDeserialize(const QByteArray& buffer) const
659 {
660     if (buffer.indexOf('\n') == -1)
661     {
662         return false;
663     }
664     return true;
665
666 }
667
668
669
670
671 QIODevice * QxtRPCPeer::socket()
672 {
673     if (qxt_d().m_rpctype == Server)return 0;
674     return qxt_d().m_peer;
675 }
676
677
678
679
680 QTcpSocket * QxtRPCPeer::incomingConnection ( int socketDescriptor )
681 {
682     QTcpSocket * t = new QTcpSocket;
683     t->setSocketDescriptor (socketDescriptor);
684     return t;
685 }
686
687
688
689
690 const QTcpSocket * QxtRPCPeer::clientSocket(quint64 id) const
691     {
692     if (qxt_d().m_rpctype != Server)
693         return 0;
694
695     return  qxt_d().m_clients[(QTcpSocket*)(id)]->socket;
696     }
697 QList<quint64> QxtRPCPeer::clients()
698     {
699     QList<quint64> list;
700     foreach(QObject * o,qxt_d().m_clients.keys ())
701         {
702         list.append((quint64)o);
703         }
704     return list;
705     }
706
707
708