1 /*******************************************************************************
2 Copyright(c) 2016 Jasem Mutlaq. All rights reserved.
3
4 INDI Qt Client
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 *******************************************************************************/
20
21 #include "baseclientqt.h"
22
23 #include "base64.h"
24 #include "basedevice.h"
25 #include "locale_compat.h"
26 #include "indistandardproperty.h"
27
28 #include <iostream>
29 #include <string>
30 #include <algorithm>
31
32 #include <cstdlib>
33
34 #define MAXINDIBUF 49152
35
36 #if defined(_MSC_VER)
37 #define snprintf _snprintf
38 #pragma warning(push)
39 ///@todo Introduce plattform indipendent safe functions as macros to fix this
40 #pragma warning(disable : 4996)
41 #endif
42
BaseClientQt(QObject * parent)43 INDI::BaseClientQt::BaseClientQt(QObject *parent) : QObject(parent), cServer("localhost"), cPort(7624)
44 {
45 sConnected = false;
46 verbose = false;
47 lillp = nullptr;
48
49 timeout_sec = 3;
50 timeout_us = 0;
51
52 connect(&client_socket, SIGNAL(readyRead()), this, SLOT(listenINDI()));
53 connect(&client_socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
54 SLOT(processSocketError(QAbstractSocket::SocketError)));
55 }
56
~BaseClientQt()57 INDI::BaseClientQt::~BaseClientQt()
58 {
59 clear();
60 }
61
clear()62 void INDI::BaseClientQt::clear()
63 {
64 while (!cDevices.empty())
65 {
66 delete cDevices.back();
67 cDevices.pop_back();
68 }
69 cDevices.clear();
70 while (!blobModes.empty())
71 {
72 delete blobModes.back();
73 blobModes.pop_back();
74 }
75 blobModes.clear();
76 }
77
setServer(const char * hostname,unsigned int port)78 void INDI::BaseClientQt::setServer(const char *hostname, unsigned int port)
79 {
80 cServer = hostname;
81 cPort = port;
82 }
83
watchDevice(const char * deviceName)84 void INDI::BaseClientQt::watchDevice(const char *deviceName)
85 {
86 // Watch for duplicates. Should have used std::set from the beginning but let's
87 // avoid changing API now.
88 if (std::find(cDeviceNames.begin(), cDeviceNames.end(), deviceName) != cDeviceNames.end())
89 return;
90
91 cDeviceNames.push_back(deviceName);
92 }
93
watchProperty(const char * deviceName,const char * propertyName)94 void INDI::BaseClientQt::watchProperty(const char *deviceName, const char *propertyName)
95 {
96 watchDevice(deviceName);
97 cWatchProperties[deviceName].insert(propertyName);
98 }
99
connectServer()100 bool INDI::BaseClientQt::connectServer()
101 {
102 client_socket.connectToHost(cServer.c_str(), cPort);
103
104 if (client_socket.waitForConnected(timeout_sec * 1000) == false)
105 {
106 sConnected = false;
107 return false;
108 }
109
110 clear();
111
112 lillp = newLilXML();
113
114 sConnected = true;
115
116 serverConnected();
117
118 AutoCNumeric locale;
119
120 QString getProp;
121 if (cDeviceNames.empty())
122 {
123 getProp = QString("<getProperties version='%1'/>\n").arg(QString::number(INDIV));
124
125 client_socket.write(getProp.toLatin1());
126
127 if (verbose)
128 std::cerr << getProp.toLatin1().constData() << std::endl;
129 }
130 else
131 {
132 for (auto &str : cDeviceNames)
133 {
134 getProp =
135 QString("<getProperties version='%1' device='%2'/>\n").arg(QString::number(INDIV)).arg(str.c_str());
136
137 client_socket.write(getProp.toLatin1());
138 if (verbose)
139 std::cerr << getProp.toLatin1().constData() << std::endl;
140 }
141 }
142
143 return true;
144 }
145
disconnectServer()146 bool INDI::BaseClientQt::disconnectServer()
147 {
148 if (sConnected == false)
149 return true;
150
151 sConnected = false;
152
153 client_socket.close();
154 if (lillp)
155 {
156 delLilXML(lillp);
157 lillp = nullptr;
158 }
159
160 clear();
161
162 cDeviceNames.clear();
163
164 serverDisconnected(0);
165
166 return true;
167 }
168
connectDevice(const char * deviceName)169 void INDI::BaseClientQt::connectDevice(const char *deviceName)
170 {
171 setDriverConnection(true, deviceName);
172 }
173
disconnectDevice(const char * deviceName)174 void INDI::BaseClientQt::disconnectDevice(const char *deviceName)
175 {
176 setDriverConnection(false, deviceName);
177 }
178
setDriverConnection(bool status,const char * deviceName)179 void INDI::BaseClientQt::setDriverConnection(bool status, const char *deviceName)
180 {
181 INDI::BaseDevice *drv = getDevice(deviceName);
182 ISwitchVectorProperty *drv_connection = nullptr;
183
184 if (drv == nullptr)
185 {
186 IDLog("INDI::BaseClientQt: Error. Unable to find driver %s\n", deviceName);
187 return;
188 }
189
190 drv_connection = drv->getSwitch(INDI::SP::CONNECTION);
191
192 if (drv_connection == nullptr)
193 return;
194
195 // If we need to connect
196 if (status)
197 {
198 // If there is no need to do anything, i.e. already connected.
199 if (drv_connection->sp[0].s == ISS_ON)
200 return;
201
202 IUResetSwitch(drv_connection);
203 drv_connection->s = IPS_BUSY;
204 drv_connection->sp[0].s = ISS_ON;
205 drv_connection->sp[1].s = ISS_OFF;
206
207 sendNewSwitch(drv_connection);
208 }
209 else
210 {
211 // If there is no need to do anything, i.e. already disconnected.
212 if (drv_connection->sp[1].s == ISS_ON)
213 return;
214
215 IUResetSwitch(drv_connection);
216 drv_connection->s = IPS_BUSY;
217 drv_connection->sp[0].s = ISS_OFF;
218 drv_connection->sp[1].s = ISS_ON;
219
220 sendNewSwitch(drv_connection);
221 }
222 }
223
getDevice(const char * deviceName)224 INDI::BaseDevice *INDI::BaseClientQt::getDevice(const char *deviceName)
225 {
226 for (auto &dev : cDevices)
227 {
228 if (!strcmp(deviceName, dev->getDeviceName()))
229 return dev;
230 }
231 return nullptr;
232 }
233
listenHelper(void * context)234 void *INDI::BaseClientQt::listenHelper(void *context)
235 {
236 (static_cast<INDI::BaseClientQt *>(context))->listenINDI();
237 return nullptr;
238 }
239
listenINDI()240 void INDI::BaseClientQt::listenINDI()
241 {
242 char buffer[MAXINDIBUF];
243 char errorMsg[MAXRBUF];
244 int err_code = 0;
245
246 XMLEle **nodes;
247 int inode = 0;
248
249 if (sConnected == false)
250 return;
251
252 while (client_socket.bytesAvailable() > 0)
253 {
254 qint64 readBytes = client_socket.read(buffer, MAXINDIBUF - 1);
255 if (readBytes > 0)
256 buffer[readBytes] = '\0';
257
258 nodes = parseXMLChunk(lillp, buffer, readBytes, errorMsg);
259 if (!nodes)
260 {
261 if (errorMsg[0])
262 {
263 fprintf(stderr, "Bad XML from %s/%ud: %s\n%s\n", cServer.c_str(), cPort, errorMsg, buffer);
264 return;
265 }
266 return;
267 }
268 XMLEle *root = nodes[inode];
269 while (root)
270 {
271 if (verbose)
272 prXMLEle(stderr, root, 0);
273
274 if ((err_code = dispatchCommand(root, errorMsg)) < 0)
275 {
276 // Silenty ignore property duplication errors
277 if (err_code != INDI_PROPERTY_DUPLICATED)
278 {
279 IDLog("Dispatch command error(%d): %s\n", err_code, errorMsg);
280 prXMLEle(stderr, root, 0);
281 }
282 }
283
284 delXMLEle(root); // not yet, delete and continue
285 inode++;
286 root = nodes[inode];
287 }
288 free(nodes);
289 inode = 0;
290 }
291 }
292
dispatchCommand(XMLEle * root,char * errmsg)293 int INDI::BaseClientQt::dispatchCommand(XMLEle *root, char *errmsg)
294 {
295 if (!strcmp(tagXMLEle(root), "message"))
296 return messageCmd(root, errmsg);
297 else if (!strcmp(tagXMLEle(root), "delProperty"))
298 return delPropertyCmd(root, errmsg);
299 // Just ignore any getProperties we might get
300 else if (!strcmp(tagXMLEle(root), "getProperties"))
301 return INDI_PROPERTY_DUPLICATED;
302
303 /* Get the device, if not available, create it */
304 INDI::BaseDevice *dp = findDev(root, 1, errmsg);
305 if (dp == nullptr)
306 {
307 strcpy(errmsg, "No device available and none was created");
308 return INDI_DEVICE_NOT_FOUND;
309 }
310
311 // Ignore echoed newXXX
312 if (strstr(tagXMLEle(root), "new"))
313 return 0;
314
315 // If device is set to BLOB_ONLY, we ignore everything else
316 // not related to blobs
317 if (getBLOBMode(dp->getDeviceName()) == B_ONLY)
318 {
319 if (!strcmp(tagXMLEle(root), "defBLOBVector"))
320 return dp->buildProp(root, errmsg);
321 else if (!strcmp(tagXMLEle(root), "setBLOBVector"))
322 return dp->setValue(root, errmsg);
323
324 // Ignore everything else
325 return 0;
326 }
327
328 // If we are asked to watch for specific properties only, we ignore everything else
329 if (cWatchProperties.size() > 0)
330 {
331 const char *device = findXMLAttValu(root, "device");
332 const char *name = findXMLAttValu(root, "name");
333 if (device && name)
334 {
335 if (cWatchProperties.find(device) == cWatchProperties.end() ||
336 cWatchProperties[device].find(name) == cWatchProperties[device].end())
337 return 0;
338 }
339 }
340
341 if ((!strcmp(tagXMLEle(root), "defTextVector")) || (!strcmp(tagXMLEle(root), "defNumberVector")) ||
342 (!strcmp(tagXMLEle(root), "defSwitchVector")) || (!strcmp(tagXMLEle(root), "defLightVector")) ||
343 (!strcmp(tagXMLEle(root), "defBLOBVector")))
344 return dp->buildProp(root, errmsg);
345 else if (!strcmp(tagXMLEle(root), "setTextVector") || !strcmp(tagXMLEle(root), "setNumberVector") ||
346 !strcmp(tagXMLEle(root), "setSwitchVector") || !strcmp(tagXMLEle(root), "setLightVector") ||
347 !strcmp(tagXMLEle(root), "setBLOBVector"))
348 return dp->setValue(root, errmsg);
349
350 return INDI_DISPATCH_ERROR;
351 }
352
353 /* delete the property in the given device, including widgets and data structs.
354 * when last property is deleted, delete the device too.
355 * if no property name attribute at all, delete the whole device regardless.
356 * return 0 if ok, else -1 with reason in errmsg[].
357 */
delPropertyCmd(XMLEle * root,char * errmsg)358 int INDI::BaseClientQt::delPropertyCmd(XMLEle *root, char *errmsg)
359 {
360 XMLAtt *ap;
361 INDI::BaseDevice *dp;
362
363 /* dig out device and optional property name */
364 dp = findDev(root, 0, errmsg);
365 if (!dp)
366 return INDI_DEVICE_NOT_FOUND;
367
368 dp->checkMessage(root);
369
370 ap = findXMLAtt(root, "name");
371
372 /* Delete property if it exists, otherwise, delete the whole device */
373 if (ap)
374 {
375 INDI::Property *rProp = dp->getProperty(valuXMLAtt(ap));
376 if (rProp == nullptr)
377 {
378 snprintf(errmsg, MAXRBUF, "Cannot delete property %s as it is not defined yet. Check driver.", valuXMLAtt(ap));
379 return -1;
380 }
381
382 removeProperty(rProp);
383 int errCode = dp->removeProperty(valuXMLAtt(ap), errmsg);
384
385 return errCode;
386 }
387 // delete the whole device
388 else
389 return deleteDevice(dp->getDeviceName(), errmsg);
390 }
391
deleteDevice(const char * devName,char * errmsg)392 int INDI::BaseClientQt::deleteDevice(const char *devName, char *errmsg)
393 {
394 std::vector<INDI::BaseDevice *>::iterator devicei;
395
396 for (devicei = cDevices.begin(); devicei != cDevices.end();)
397 {
398 if (!strcmp(devName, (*devicei)->getDeviceName()))
399 {
400 removeDevice(*devicei);
401 delete *devicei;
402 devicei = cDevices.erase(devicei);
403 return 0;
404 }
405 else
406 ++devicei;
407 }
408
409 snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
410 return INDI_DEVICE_NOT_FOUND;
411 }
412
findDev(const char * devName,char * errmsg)413 INDI::BaseDevice *INDI::BaseClientQt::findDev(const char *devName, char *errmsg)
414 {
415 std::vector<INDI::BaseDevice *>::const_iterator devicei;
416
417 for (devicei = cDevices.begin(); devicei != cDevices.end(); devicei++)
418 {
419 if (!strcmp(devName, (*devicei)->getDeviceName()))
420 return (*devicei);
421 }
422
423 snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
424 return nullptr;
425 }
426
427 /* add new device */
addDevice(XMLEle * dep,char * errmsg)428 INDI::BaseDevice *INDI::BaseClientQt::addDevice(XMLEle *dep, char *errmsg)
429 {
430 //devicePtr dp(new INDI::BaseDriver());
431 INDI::BaseDevice *dp = new INDI::BaseDevice();
432 XMLAtt *ap;
433 char *device_name;
434
435 /* allocate new INDI::BaseDriver */
436 ap = findXMLAtt(dep, "device");
437 if (!ap)
438 {
439 strncpy(errmsg, "Unable to find device attribute in XML element. Cannot add device.", MAXRBUF);
440 return nullptr;
441 }
442
443 device_name = valuXMLAtt(ap);
444
445 dp->setMediator(this);
446 dp->setDeviceName(device_name);
447
448 cDevices.push_back(dp);
449
450 newDevice(dp);
451
452 /* ok */
453 return dp;
454 }
455
findDev(XMLEle * root,int create,char * errmsg)456 INDI::BaseDevice *INDI::BaseClientQt::findDev(XMLEle *root, int create, char *errmsg)
457 {
458 XMLAtt *ap;
459 INDI::BaseDevice *dp;
460 char *dn;
461
462 /* get device name */
463 ap = findXMLAtt(root, "device");
464 if (!ap)
465 {
466 snprintf(errmsg, MAXRBUF, "No device attribute found in element %s", tagXMLEle(root));
467 return (nullptr);
468 }
469
470 dn = valuXMLAtt(ap);
471
472 if (*dn == '\0')
473 {
474 snprintf(errmsg, MAXRBUF, "Device name is empty! %s", tagXMLEle(root));
475 return (nullptr);
476 }
477
478 dp = findDev(dn, errmsg);
479
480 if (dp)
481 return dp;
482
483 /* not found, create if ok */
484 if (create)
485 return (addDevice(root, errmsg));
486
487 snprintf(errmsg, MAXRBUF, "INDI: <%s> no such device %s", tagXMLEle(root), dn);
488 return nullptr;
489 }
490
491 /* a general message command received from the device.
492 * return 0 if ok, else -1 with reason in errmsg[].
493 */
messageCmd(XMLEle * root,char * errmsg)494 int INDI::BaseClientQt::messageCmd(XMLEle *root, char *errmsg)
495 {
496 INDI::BaseDevice *dp = findDev(root, 0, errmsg);
497
498 if (dp)
499 dp->checkMessage(root);
500
501 return (0);
502 }
503
sendNewText(ITextVectorProperty * tvp)504 void INDI::BaseClientQt::sendNewText(ITextVectorProperty *tvp)
505 {
506 AutoCNumeric locale;
507
508 tvp->s = IPS_BUSY;
509
510 QString prop;
511
512 prop += QString("<newTextVector\n");
513 prop += QString(" device='%1'\n").arg(tvp->device);
514 prop += QString(" name='%1'\n>").arg(tvp->name);
515
516 for (int i = 0; i < tvp->ntp; i++)
517 {
518 prop += QString(" <oneText\n");
519 prop += QString(" name='%1'>\n").arg(tvp->tp[i].name);
520 prop += QString(" %1\n").arg(tvp->tp[i].text);
521 prop += QString(" </oneText>\n");
522 }
523 prop += QString("</newTextVector>\n");
524
525 client_socket.write(prop.toLatin1());
526 }
527
sendNewText(const char * deviceName,const char * propertyName,const char * elementName,const char * text)528 void INDI::BaseClientQt::sendNewText(const char *deviceName, const char *propertyName, const char *elementName,
529 const char *text)
530 {
531 INDI::BaseDevice *drv = getDevice(deviceName);
532
533 if (drv == nullptr)
534 return;
535
536 ITextVectorProperty *tvp = drv->getText(propertyName);
537
538 if (tvp == nullptr)
539 return;
540
541 IText *tp = IUFindText(tvp, elementName);
542
543 if (tp == nullptr)
544 return;
545
546 IUSaveText(tp, text);
547
548 sendNewText(tvp);
549 }
550
sendNewNumber(INumberVectorProperty * nvp)551 void INDI::BaseClientQt::sendNewNumber(INumberVectorProperty *nvp)
552 {
553 AutoCNumeric locale;
554
555 nvp->s = IPS_BUSY;
556
557 QString prop;
558
559 prop += QString("<newNumberVector\n");
560 prop += QString(" device='%1'\n").arg(nvp->device);
561 prop += QString(" name='%1'\n>").arg(nvp->name);
562
563 for (int i = 0; i < nvp->nnp; i++)
564 {
565 prop += QString(" <oneNumber\n");
566 prop += QString(" name='%1'>\n").arg(nvp->np[i].name);
567 prop += QString(" %1\n").arg(QString::number(nvp->np[i].value));
568 prop += QString(" </oneNumber>\n");
569 }
570 prop += QString("</newNumberVector>\n");
571
572 client_socket.write(prop.toLatin1());
573 }
574
sendNewNumber(const char * deviceName,const char * propertyName,const char * elementName,double value)575 void INDI::BaseClientQt::sendNewNumber(const char *deviceName, const char *propertyName, const char *elementName,
576 double value)
577 {
578 INDI::BaseDevice *drv = getDevice(deviceName);
579
580 if (drv == nullptr)
581 return;
582
583 INumberVectorProperty *nvp = drv->getNumber(propertyName);
584
585 if (nvp == nullptr)
586 return;
587
588 INumber *np = IUFindNumber(nvp, elementName);
589
590 if (np == nullptr)
591 return;
592
593 np->value = value;
594
595 sendNewNumber(nvp);
596 }
597
sendNewSwitch(ISwitchVectorProperty * svp)598 void INDI::BaseClientQt::sendNewSwitch(ISwitchVectorProperty *svp)
599 {
600 svp->s = IPS_BUSY;
601 ISwitch *onSwitch = IUFindOnSwitch(svp);
602
603 QString prop;
604
605 prop += QString("<newSwitchVector\n");
606
607 prop += QString(" device='%1'\n").arg(svp->device);
608 prop += QString(" name='%1'>\n").arg(svp->name);
609
610 if (svp->r == ISR_1OFMANY && onSwitch)
611 {
612 prop += QString(" <oneSwitch\n");
613 prop += QString(" name='%1'>\n").arg(onSwitch->name);
614 prop += QString(" %1\n").arg((onSwitch->s == ISS_ON) ? "On" : "Off");
615 prop += QString(" </oneSwitch>\n");
616 }
617 else
618 {
619 for (int i = 0; i < svp->nsp; i++)
620 {
621 prop += QString(" <oneSwitch\n");
622 prop += QString(" name='%1'>\n").arg(svp->sp[i].name);
623 prop += QString(" %1\n").arg((svp->sp[i].s == ISS_ON) ? "On" : "Off");
624 prop += QString(" </oneSwitch>\n");
625 }
626 }
627
628 prop += QString("</newSwitchVector>\n");
629
630 client_socket.write(prop.toLatin1());
631 }
632
sendNewSwitch(const char * deviceName,const char * propertyName,const char * elementName)633 void INDI::BaseClientQt::sendNewSwitch(const char *deviceName, const char *propertyName, const char *elementName)
634 {
635 INDI::BaseDevice *drv = getDevice(deviceName);
636
637 if (drv == nullptr)
638 return;
639
640 ISwitchVectorProperty *svp = drv->getSwitch(propertyName);
641
642 if (svp == nullptr)
643 return;
644
645 ISwitch *sp = IUFindSwitch(svp, elementName);
646
647 if (sp == nullptr)
648 return;
649
650 sp->s = ISS_ON;
651
652 sendNewSwitch(svp);
653 }
654
startBlob(const char * devName,const char * propName,const char * timestamp)655 void INDI::BaseClientQt::startBlob(const char *devName, const char *propName, const char *timestamp)
656 {
657 QString prop;
658
659 prop += QString("<newBLOBVector\n");
660 prop += QString(" device='%1'\n").arg(devName);
661 prop += QString(" name='%1'\n").arg(propName);
662 prop += QString(" timestamp='%1'>\n").arg(timestamp);
663
664 client_socket.write(prop.toLatin1());
665 }
666
sendOneBlob(IBLOB * bp)667 void INDI::BaseClientQt::sendOneBlob(IBLOB *bp)
668 {
669 QString prop;
670 unsigned char *encblob;
671 int l;
672
673 encblob = static_cast<unsigned char *>(malloc(4 * bp->size / 3 + 4));
674 l = to64frombits(encblob, reinterpret_cast<const unsigned char *>(bp->blob), bp->size);
675
676 prop += QString(" <oneBLOB\n");
677 prop += QString(" name='%1'\n").arg(bp->name);
678 prop += QString(" size='%1'\n").arg(QString::number(bp->size));
679 prop += QString(" enclen='%1'\n").arg(QString::number(l));
680 prop += QString(" format='%1'>\n").arg(bp->format);
681
682 client_socket.write(prop.toLatin1());
683
684 size_t written = 0;
685 size_t towrite = l;
686
687 while ((int)written < l)
688 {
689 towrite = ((l - written) > 72) ? 72 : l - written;
690 size_t wr = client_socket.write(reinterpret_cast<const char *>(encblob + written), towrite);
691 if (wr > 0)
692 written += wr;
693 if ((written % 72) == 0)
694 client_socket.write("\n");
695 }
696
697 if ((written % 72) != 0)
698 client_socket.write("\n");
699
700 free(encblob);
701
702 client_socket.write(" </oneBLOB>\n");
703 }
704
sendOneBlob(const char * blobName,unsigned int blobSize,const char * blobFormat,void * blobBuffer)705 void INDI::BaseClientQt::sendOneBlob(const char *blobName, unsigned int blobSize, const char *blobFormat,
706 void *blobBuffer)
707 {
708 unsigned char *encblob;
709 int l;
710
711 encblob = static_cast<unsigned char *>(malloc(4 * blobSize / 3 + 4));
712 l = to64frombits(encblob, reinterpret_cast<const unsigned char *>(blobBuffer), blobSize);
713
714 QString prop;
715
716 prop += QString(" <oneBLOB\n");
717 prop += QString(" name='%1'\n").arg(blobName);
718 prop += QString(" size='%1'\n").arg(QString::number(blobSize));
719 prop += QString(" enclen='%1'\n").arg(QString::number(l));
720 prop += QString(" format='%1'>\n").arg(blobFormat);
721
722 client_socket.write(prop.toLatin1());
723
724 size_t written = 0;
725 size_t towrite = l;
726
727 while ((int)written < l)
728 {
729 towrite = ((l - written) > 72) ? 72 : l - written;
730 size_t wr = client_socket.write(reinterpret_cast<const char *>(encblob + written), towrite);
731 if (wr > 0)
732 written += wr;
733 if ((written % 72) == 0)
734 client_socket.write("\n");
735 }
736
737 if ((written % 72) != 0)
738 client_socket.write("\n");
739
740 free(encblob);
741
742 client_socket.write(" </oneBLOB>\n");
743 }
744
finishBlob()745 void INDI::BaseClientQt::finishBlob()
746 {
747 client_socket.write("</newBLOBVector>\n");
748 }
749
setBLOBMode(BLOBHandling blobH,const char * dev,const char * prop)750 void INDI::BaseClientQt::setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop)
751 {
752 if (!dev[0])
753 return;
754
755 BLOBMode *bMode = findBLOBMode(std::string(dev), prop ? std::string(prop) : std::string());
756
757 if (bMode == nullptr)
758 {
759 BLOBMode *newMode = new BLOBMode();
760 newMode->device = std::string(dev);
761 newMode->property = (prop ? std::string(prop) : std::string());
762 newMode->blobMode = blobH;
763 blobModes.push_back(newMode);
764 }
765 else
766 {
767 // If nothing changed, nothing to to do
768 if (bMode->blobMode == blobH)
769 return;
770
771 bMode->blobMode = blobH;
772 }
773
774 QString blobOpenTag;
775 QString blobEnableTag;
776 if (prop != nullptr)
777 blobOpenTag = QString("<enableBLOB device='%1' name='%2'>").arg(dev).arg(prop);
778 else
779 blobOpenTag = QString("<enableBLOB device='%1'>").arg(dev);
780
781 switch (blobH)
782 {
783 case B_NEVER:
784 blobEnableTag = QString("%1Never</enableBLOB>\n").arg(blobOpenTag);
785 break;
786 case B_ALSO:
787 blobEnableTag = QString("%1Also</enableBLOB>\n").arg(blobOpenTag);
788 break;
789 case B_ONLY:
790 blobEnableTag = QString("%1Only</enableBLOB>\n").arg(blobOpenTag);
791 break;
792 }
793
794 client_socket.write(blobEnableTag.toLatin1());
795 }
796
getBLOBMode(const char * dev,const char * prop)797 BLOBHandling INDI::BaseClientQt::getBLOBMode(const char *dev, const char *prop)
798 {
799 BLOBHandling bHandle = B_ALSO;
800
801 BLOBMode *bMode = findBLOBMode(dev, (prop ? std::string(prop) : std::string()));
802
803 if (bMode)
804 bHandle = bMode->blobMode;
805
806 return bHandle;
807 }
808
findBLOBMode(const std::string & device,const std::string & property)809 INDI::BaseClientQt::BLOBMode *INDI::BaseClientQt::findBLOBMode(const std::string &device, const std::string &property)
810 {
811 for (auto &blob : blobModes)
812 {
813 if (blob->device == device && blob->property == property)
814 return blob;
815 }
816
817 return nullptr;
818 }
819
processSocketError(QAbstractSocket::SocketError socketError)820 void INDI::BaseClientQt::processSocketError(QAbstractSocket::SocketError socketError)
821 {
822 if (sConnected == false)
823 return;
824
825 // TODO Handle what happens on socket failure!
826 INDI_UNUSED(socketError);
827 IDLog("Socket Error: %s\n", client_socket.errorString().toLatin1().constData());
828 fprintf(stderr, "INDI server %s/%d disconnected.\n", cServer.c_str(), cPort);
829 delLilXML(lillp);
830 client_socket.close();
831 // Let client handle server disconnection
832 serverDisconnected(-1);
833 }
834
getDevices(std::vector<INDI::BaseDevice * > & deviceList,uint16_t driverInterface)835 bool INDI::BaseClientQt::getDevices(std::vector<INDI::BaseDevice *> &deviceList, uint16_t driverInterface )
836 {
837 for (INDI::BaseDevice *device : cDevices)
838 {
839 if (device->getDriverInterface() & driverInterface)
840 deviceList.push_back(device);
841 }
842
843 return (deviceList.size() > 0);
844 }
845
isServerConnected() const846 bool INDI::BaseClientQt::isServerConnected() const
847 {
848 return sConnected;
849 }
850
851 #if defined(_MSC_VER)
852 #undef snprintf
853 #pragma warning(pop)
854 #endif
855