1 /*
2     SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "clientmanager.h"
8 
9 #include "deviceinfo.h"
10 #include "drivermanager.h"
11 #include "guimanager.h"
12 #include "indilistener.h"
13 #include "Options.h"
14 #include "servermanager.h"
15 
16 #include <indi_debug.h>
17 
isDriverManaged(DriverInfo * di)18 bool ClientManager::isDriverManaged(DriverInfo *di)
19 {
20     foreach (DriverInfo *dv, managedDrivers)
21     {
22         if (dv == di)
23             return true;
24     }
25 
26     return false;
27 }
28 
newDevice(INDI::BaseDevice * dp)29 void ClientManager::newDevice(INDI::BaseDevice *dp)
30 {
31     //setBLOBMode(B_ALSO, dp->getDeviceName());
32     // JM 2018.09.27: ClientManager will no longer handle BLOB, just messages.
33     // We relay the BLOB handling to BLOB Manager to better manage concurrent connections with large data
34     setBLOBMode(B_NEVER, dp->getDeviceName());
35 
36     DriverInfo *deviceDriver = nullptr;
37 
38     if (QString(dp->getDeviceName()).isEmpty())
39     {
40         qCWarning(KSTARS_INDI) << "Received invalid device with empty name! Ignoring the device...";
41         return;
42     }
43 
44     qCDebug(KSTARS_INDI) << "Received new device" << dp->getDeviceName();
45 
46     // First iteration find unique matches
47     for (auto &oneDriverInfo : managedDrivers)
48     {
49         if (oneDriverInfo->getUniqueLabel() == QString(dp->getDeviceName()))
50         {
51             deviceDriver = oneDriverInfo;
52             break;
53         }
54     }
55 
56     // Second iteration find partial matches
57     if (deviceDriver == nullptr)
58     {
59         for (auto &oneDriverInfo : managedDrivers)
60         {
61             QString dvName = oneDriverInfo->getName();
62             dvName         = oneDriverInfo->getName().split(' ').first();
63             if (dvName.isEmpty())
64                 dvName = oneDriverInfo->getName();
65             if (/*dv->getUniqueLabel() == dp->getDeviceName() ||*/
66                 QString(dp->getDeviceName()).startsWith(dvName, Qt::CaseInsensitive) ||
67                 ((oneDriverInfo->getDriverSource() == HOST_SOURCE || oneDriverInfo->getDriverSource() == GENERATED_SOURCE)))
68             {
69                 deviceDriver = oneDriverInfo;
70                 break;
71             }
72         }
73     }
74 
75     if (deviceDriver == nullptr)
76         return;
77 
78     deviceDriver->setUniqueLabel(dp->getDeviceName());
79 
80     DeviceInfo *devInfo = new DeviceInfo(deviceDriver, dp);
81     deviceDriver->addDevice(devInfo);
82     emit newINDIDevice(devInfo);
83 }
84 
newProperty(INDI::Property * pprop)85 void ClientManager::newProperty(INDI::Property *pprop)
86 {
87     INDI::Property prop(*pprop);
88 
89     // Do not emit the signal if the server is disconnected or disconnecting (deadlock between signals)
90     if (!isServerConnected())
91     {
92         IDLog("Received new property %s for disconnected device %s, discarding\n", prop.getName(), prop.getDeviceName());
93         return;
94     }
95 
96     //IDLog("Received new property %s for device %s\n", prop->getName(), prop->getgetDeviceName());
97     emit newINDIProperty(prop);
98 
99     // Only handle RW and RO BLOB properties
100     if (prop.getType() == INDI_BLOB && prop.getPermission() != IP_WO)
101     {
102         QPointer<BlobManager> bm = new BlobManager(getHost(), getPort(), prop.getBaseDevice()->getDeviceName(), prop.getName());
103         connect(bm.data(), &BlobManager::newINDIBLOB, this, &ClientManager::newINDIBLOB);
104         connect(bm.data(), &BlobManager::connected, this, [prop, this]()
105         {
106             if (prop && prop.getRegistered())
107                 emit newBLOBManager(prop->getBaseDevice()->getDeviceName(), prop);
108         });
109         blobManagers.append(bm);
110     }
111 }
112 
removeProperty(INDI::Property * prop)113 void ClientManager::removeProperty(INDI::Property *prop)
114 {
115     const QString name = prop->getName();
116     const QString device = prop->getDeviceName();
117     emit removeINDIProperty(device, name);
118 
119     // If BLOB property is removed, remove its corresponding property if one exists.
120     if (blobManagers.empty() == false && prop->getType() == INDI_BLOB && prop->getPermission() != IP_WO)
121     {
122         for (QPointer<BlobManager> bm : blobManagers)
123         {
124             const QString bProperty = bm.data()->property("property").toString();
125             const QString bDevice = bm.data()->property("device").toString();
126             if (bDevice == device && bProperty == name)
127             {
128                 blobManagers.removeOne(bm);
129                 bm.data()->disconnectServer();
130                 bm->deleteLater();
131                 break;
132             }
133         }
134     }
135 }
136 
disconnectAll()137 void ClientManager::disconnectAll()
138 {
139     disconnectServer();
140     for (auto &oneManager : blobManagers)
141         oneManager->disconnectServer();
142 }
143 
removeDevice(INDI::BaseDevice * dp)144 void ClientManager::removeDevice(INDI::BaseDevice *dp)
145 {
146     QString deviceName = dp->getDeviceName();
147 
148     QMutableListIterator<QPointer<BlobManager>> it(blobManagers);
149     while (it.hasNext())
150     {
151         QPointer<BlobManager> &oneManager = it.next();
152         if (oneManager->property("device").toString() == deviceName)
153         {
154             oneManager->disconnect();
155             it.remove();
156         }
157     }
158 
159     for (auto driverInfo : managedDrivers)
160     {
161         for (auto deviceInfo : driverInfo->getDevices())
162         {
163             if (deviceInfo->getDeviceName() == deviceName)
164             {
165                 qCDebug(KSTARS_INDI) << "Removing device" << deviceName;
166 
167                 emit removeINDIDevice(deviceName);
168 
169                 driverInfo->removeDevice(deviceInfo);
170 
171                 if (driverInfo->isEmpty())
172                 {
173                     managedDrivers.removeOne(driverInfo);
174                     if (driverInfo->getDriverSource() == GENERATED_SOURCE)
175                         driverInfo->deleteLater();
176                 }
177 
178                 return;
179             }
180         }
181     }
182 }
183 
newBLOB(IBLOB * bp)184 void ClientManager::newBLOB(IBLOB *bp)
185 {
186     emit newINDIBLOB(bp);
187 }
188 
newSwitch(ISwitchVectorProperty * svp)189 void ClientManager::newSwitch(ISwitchVectorProperty *svp)
190 {
191     emit newINDISwitch(svp);
192 }
193 
newNumber(INumberVectorProperty * nvp)194 void ClientManager::newNumber(INumberVectorProperty *nvp)
195 {
196     emit newINDINumber(nvp);
197 }
198 
newText(ITextVectorProperty * tvp)199 void ClientManager::newText(ITextVectorProperty *tvp)
200 {
201     emit newINDIText(tvp);
202 }
203 
newLight(ILightVectorProperty * lvp)204 void ClientManager::newLight(ILightVectorProperty *lvp)
205 {
206     emit newINDILight(lvp);
207 }
208 
newMessage(INDI::BaseDevice * dp,int messageID)209 void ClientManager::newMessage(INDI::BaseDevice *dp, int messageID)
210 {
211     emit newINDIMessage(dp, messageID);
212 }
213 
214 #if INDI_VERSION_MAJOR >= 1 && INDI_VERSION_MINOR >= 5
newUniversalMessage(std::string message)215 void ClientManager::newUniversalMessage(std::string message)
216 {
217     emit newINDIUniversalMessage(QString::fromStdString(message));
218 }
219 #endif
220 
appendManagedDriver(DriverInfo * dv)221 void ClientManager::appendManagedDriver(DriverInfo *dv)
222 {
223     qCDebug(KSTARS_INDI) << "Adding managed driver" << dv->getName();
224 
225     managedDrivers.append(dv);
226 
227     dv->setClientManager(this);
228 
229     sManager = dv->getServerManager();
230 }
231 
removeManagedDriver(DriverInfo * dv)232 void ClientManager::removeManagedDriver(DriverInfo *dv)
233 {
234     qCDebug(KSTARS_INDI) << "Removing managed driver" << dv->getName();
235 
236     dv->setClientState(false);
237     managedDrivers.removeOne(dv);
238 
239     for (auto di : dv->getDevices())
240     {
241         // #1 Remove from GUI Manager
242         GUIManager::Instance()->removeDevice(di->getDeviceName());
243 
244         // #2 Remove from INDI Listener
245         INDIListener::Instance()->removeDevice(di->getDeviceName());
246 
247         // #3 Remove device from Driver Info
248         dv->removeDevice(di);
249     }
250 
251     if (dv->getDriverSource() == GENERATED_SOURCE)
252         dv->deleteLater();
253 }
254 
serverConnected()255 void ClientManager::serverConnected()
256 {
257     qCDebug(KSTARS_INDI) << "INDI server connected.";
258 
259     for (auto &oneDriverInfo : managedDrivers)
260     {
261         oneDriverInfo->setClientState(true);
262         if (sManager)
263             oneDriverInfo->setHostParameters(sManager->getHost(), sManager->getPort());
264     }
265 }
266 
serverDisconnected(int exit_code)267 void ClientManager::serverDisconnected(int exit_code)
268 {
269     qCDebug(KSTARS_INDI) << "INDI server disconnected. Exit code:" << exit_code;
270 
271     for (auto &oneDriverInfo : managedDrivers)
272     {
273         oneDriverInfo->setClientState(false);
274         oneDriverInfo->reset();
275     }
276 
277     if (exit_code < 0)
278         emit connectionFailure(this);
279 }
getManagedDrivers() const280 QList<DriverInfo *> ClientManager::getManagedDrivers() const
281 {
282     return managedDrivers;
283 }
284 
findDriverInfoByName(const QString & name)285 DriverInfo *ClientManager::findDriverInfoByName(const QString &name)
286 {
287     auto pos = std::find_if(managedDrivers.begin(), managedDrivers.end(), [name](DriverInfo * oneDriverInfo)
288     {
289         return oneDriverInfo->getName() == name;
290     });
291 
292     if (pos != managedDrivers.end())
293         return *pos;
294     else
295         return nullptr;
296 }
297 
findDriverInfoByLabel(const QString & label)298 DriverInfo *ClientManager::findDriverInfoByLabel(const QString &label)
299 {
300     auto pos = std::find_if(managedDrivers.begin(), managedDrivers.end(), [label](DriverInfo * oneDriverInfo)
301     {
302         return oneDriverInfo->getLabel() == label;
303     });
304 
305     if (pos != managedDrivers.end())
306         return *pos;
307     else
308         return nullptr;
309 }
310 
setBLOBEnabled(bool enabled,const QString & device,const QString & property)311 void ClientManager::setBLOBEnabled(bool enabled, const QString &device, const QString &property)
312 {
313     for(QPointer<BlobManager> bm : blobManagers)
314     {
315         if (bm->property("device") == device && (property.isEmpty() || bm->property("property") == property))
316         {
317             bm->setEnabled(enabled);
318             return;
319         }
320     }
321 }
322 
isBLOBEnabled(const QString & device,const QString & property)323 bool ClientManager::isBLOBEnabled(const QString &device, const QString &property)
324 {
325     for(QPointer<BlobManager> bm : blobManagers)
326     {
327         if (bm->property("device") == device && bm->property("property") == property)
328             return bm->property("enabled").toBool();
329     }
330 
331     return false;
332 }
333