public void Init(DeviceDescriptionHolder devHolder, NvtSessionFactory sessionFactory, IUnityContainer container)
        {
            this.container = container;
            //Add device section (all devices must have this section)
            parent.Title = devHolder.Name;

            //Display progress bar
            devicePanel.Content = new ProgressView("Loading ...");

            //Begin load device section
            disposables.Add(SectionDevice.Load(devHolder, sessionFactory)
                            .ObserveOnCurrentDispatcher()
                            .Subscribe(
                                args => {
                invtSession = args.nvtSession;

                SectionDevice devView = container.Resolve <SectionDevice>();
                disposables.Add(devView);
                devView.Init(args);
                devicePanel.Content = devView;

                //Load sections
                LoadSections(args);
            },
                                err => {
                ErrorView errorView = new ErrorView(err);
                disposables.Add(errorView);

                devicePanel.Content = errorView;
            }
                                ));
        }
Esempio n. 2
0
        static IEnumerable <FSharpAsync <Unit> > LoadImpl(DeviceDescriptionHolder devHolder, NvtSessionFactory sessionFactory, DeviceViewArgs args)
        {
            yield return(sessionFactory.CreateSession(devHolder.Uris).Select(f => { args.nvtSession = f; return (Unit)null; }));

            args.odmSession = new OdmSession(args.nvtSession);
            yield return(args.nvtSession.GetAllCapabilities().Select(caps => { args.capabilities = caps; return (Unit)null; }));
        }
Esempio n. 3
0
        void DeviceSelectedPublish(DeviceDescriptionHolder dev, NvtSessionFactory sessionFactory)
        {
            var evargs = new DeviceSelectedEventArgs();

            evargs.sessionFactory = sessionFactory;
            evargs.devHolder      = dev;
            eventAggregator.GetEvent <DeviceSelectedEvent>().Publish(evargs);
        }
Esempio n. 4
0
 void ManualSessionProcess(DeviceDescriptionHolder devHolder)
 {
     IdentitySubscriptions.Add(sessionFactory.CreateSession(devHolder.Uris)
                               .ObserveOnCurrentDispatcher()
                               .Subscribe(isession => {
         ManualInitDeviceHolder(isession, devHolder);
     }, err => {
         dbg.Error(err);
     }));
 }
Esempio n. 5
0
        public static FSharpAsync <DeviceViewArgs> Load(DeviceDescriptionHolder devHolder, NvtSessionFactory sessionFactory)
        {
            DeviceViewArgs args = new DeviceViewArgs();

            args.deviceIconUri = devHolder.DeviceIconUri;
            args.deviceModel   = devHolder.DeviceModel;
            args.manufacturer  = devHolder.Manufacturer;

            return(Apm.Iterate(LoadImpl(devHolder, sessionFactory, args)).Select(f => { return args; }));
        }
Esempio n. 6
0
 void SessionProcess(DeviceDescriptionHolder devHolder, bool publishEvent)
 {
     IdentitySubscriptions.Add(sessionFactory.CreateSession(devHolder.Uris)
                               .ObserveOnCurrentDispatcher()
                               .Subscribe(isession => {
         InitDeviceHolder(isession, devHolder, publishEvent);
     }, err => {
         //dbg.Error(err);
         InitDeviceHolder(sessionFactory.CreateSession(devHolder.Uris[devHolder.Uris.Count() - 1]), devHolder, publishEvent);
     }));
 }
Esempio n. 7
0
        void ManualEdit(DeviceDescriptionHolder dhold)
        {
            ManualUri manUri = new ManualUri(LocalTitles.instance.manualEdit, ManualUri.ManualType.EDIT, dhold.ManualDevice.DevUri);

            manUri.Owner = Application.Current.MainWindow;

            if (manUri.ShowDialog().Value == true)
            {
                var ret = manUri.devUri;
                Devices.Remove(dhold);
                ManualLoaded(ret);
            }
        }
Esempio n. 8
0
        void OnNodeLoaded(INvtNode node)
        {
            if (node.identity.uris.Count() != 0)
            {
                try {
                    DeviceDescriptionHolder devHolder = new DeviceDescriptionHolder();
                    var scopes = node.identity.scopes.Select(x => x.OriginalString);
                    devHolder.Uris = node.identity.uris;

                    devHolder.Address = "";

                    devHolder.Uris.ForEach(x => {
                        if (x.IsAbsoluteUri)
                        {
                            devHolder.Address += x.DnsSafeHost + "; ";
                        }
                        else
                        {
                            dbg.Error("Uri not supported");
                        }
                    });
                    devHolder.Address = devHolder.Address.TrimEnd(new Char[] { ';', ' ' });
                    if (devHolder.Address == "")
                    {
                        devHolder.IsInvalidUris = true;
                        devHolder.Address       = "Invalid Uri";
                    }
                    devHolder.Name          = ScopeHelper.GetName(scopes);
                    devHolder.Location      = ScopeHelper.GetLocation(scopes);
                    devHolder.DeviceIconUri = ScopeHelper.GetDeviceIconUri(scopes);
                    devHolder.Account       = GetCurrentAccount();
                    SessionProcess(devHolder, false);

                    Devices.Add(devHolder);

                    subscriptions.Add(node.RegisterRemovalHandler(() => {
                        currentDispatcher.BeginInvoke(() => {
                            if (devHolder == SelectedDevice)
                            {
                                //Publish release ui event
                                PublishRefresh();
                            }
                            Devices.Remove(devHolder);
                        });
                    }));
                } catch (Exception err) {
                    dbg.Error(err);
                }
            }
        }
Esempio n. 9
0
        void ManualInitDeviceHolder(INvtSession session, DeviceDescriptionHolder devHolder)
        {
            devHolder.session = session;

            facade = new OdmSession(session);
            var model = new IdentificationModel();

            IdentitySubscriptions.Add(
                facade.GetIdentity(() => model)
                .ObserveOnCurrentDispatcher()
                .Subscribe(mod => {
                devHolder.Init(mod);
            }, err => {
                //dbg.Error(err);
                //MessageBox.Show(err.Message);
            })
                );
        }
Esempio n. 10
0
        void ManualLoaded(string struri)
        {
            if (!Uri.IsWellFormedUriString(struri, UriKind.Absolute))
            {
                return;
            }

            Uri uri;

            if (!Uri.TryCreate(struri, UriKind.Absolute, out uri))
            {
                return;
            }

            DeviceDescriptionHolder devHolder = new DeviceDescriptionHolder();

            //scopes
            //var scopes = node.identity.scopes.Select(x => x.OriginalString);

            devHolder.Uris = new Uri[] { uri };
            devHolder.Uris.ForEach(x => { devHolder.Address += x.DnsSafeHost + "; "; });
            devHolder.Address = devHolder.Address.TrimEnd(new Char[] { ';', ' ' });

            devHolder.Account = GetCurrentAccount();

            ManualSessionProcess(devHolder);

            devHolder.IsManual     = true;
            devHolder.ManualDevice = new ManualDevice()
            {
                DevUri = struri
            };
            devHolder.FillCommands(ddell => {
                ManualDelete(ddell);
            }, dedit => {
                ManualEdit(dedit);
            });


            Devices.Add(devHolder);
            SaveManualList();
        }
Esempio n. 11
0
        void InitDeviceHolder(INvtSession session, DeviceDescriptionHolder devHolder, bool publish)
        {
            devHolder.session = session;
            facade            = new OdmSession(session);
            var model = new IdentificationModel();

            IdentitySubscriptions.Add(
                facade.GetIdentity(() => model)
                .ObserveOnCurrentDispatcher()
                .Subscribe(mod => {
                devHolder.Init(mod);
                if (publish)
                {
                    DeviceSelectedPublish(devHolder, sessionFactory);
                }
            }, err => {
                //dbg.Error(err);
                //MessageBox.Show(err.Message);
            })
                );
        }
Esempio n. 12
0
        private void LoadJson(string sPhysicalFilePath, string sBuffer, string sHttpVersion, ref HttpRequest req)
        {
            var cmd = GetVar(sPhysicalFilePath, "cmd");

            var r = ServerRoot;
#if DEBUG
            r = @"D:\Projects\iSpy\iSpyPRO\iSpyPRO\WebServerRoot\";
#endif
            int ot, oid;

            int.TryParse(GetVar(sPhysicalFilePath, "ot"), out ot);
            int.TryParse(GetVar(sPhysicalFilePath, "oid"), out oid);

            ISpyControl io = null;
            CameraWindow cw;
            VolumeLevel vl;

            if (oid > -1)
                io = MainForm.InstanceReference.GetISpyControl(ot, oid);

            var resp = "";
            const string commandExecuted = "{\"status\":\"ok\"}";
            const string commandFailed = "{{\"status\":\"{0}\"}}";
            var t = "";
            string template = "{{\"text\":\"{0}\",\"value\":\"{1}\"}},";
            string sd, ed;
            long sdl = 0, edl = 0;
            int total = 0;
            var ptzid = -1;
            bool success;
            switch (cmd)
            {
                case "querylevel":
                {
                    float fLevel = 0;
                    switch (ot)
                    {
                        case 1:
                            vl = MainForm.InstanceReference.GetVolumeLevel(oid);
                            if (vl != null)
                            {
                                var v = vl.Levels;
                                if (v == null)
                                    fLevel = 0;
                                else
                                {
                                    fLevel = vl.Levels.Max();
                                    fLevel = Math.Min(1, fLevel/vl.Micobject.detector.gain);
                                }
                            }
                            break;
                        case 2:
                            cw = MainForm.InstanceReference.GetCameraWindow(oid);
                            if (cw?.Camera != null)
                            {
                                fLevel = cw.Camera.MotionLevel;
                                fLevel = Math.Min(1, (fLevel/cw.Camobject.detector.gain));
                            }
                            break;
                    }
                    resp = "{\"level\":" + fLevel.ToString(CultureInfo.InvariantCulture) + "}";
                }
                    break;
                case "adddevice":
                    var stid = Convert.ToInt32(GetVar(sPhysicalFilePath, "sourceTypeID"));
                    switch (ot)
                    {
                        case 1:
                            oid = MainForm.NextMicrophoneId;
                            break;
                        case 2:
                            oid = MainForm.NextCameraId;
                            break;
                    }
                    MainForm.InstanceReference.AddObjectExternal(ot,stid,320,240,"","");
                    resp = "{\"actionResult\":\"editsource\",\"typeID\":" + ot + ",\"ID\":" + oid + "}";
                    break;
                case "createfromwizard":
                    {
                        switch (ot)
                        {
                            case 2:
                                int channel = Convert.ToInt32(GetVar(sPhysicalFilePath, "channel"));
                                string url = GetVar(sPhysicalFilePath, "url");
                                string username = GetVar(sPhysicalFilePath, "username");
                                string password = GetVar(sPhysicalFilePath, "password");
                                string make = GetVar(sPhysicalFilePath, "make");
                                string model = GetVar(sPhysicalFilePath, "model");

                                int mmid = Convert.ToInt32(GetVar(sPhysicalFilePath, "mmid"));
                                Uri origUri;
                                if (!Uri.TryCreate(url, UriKind.Absolute, out origUri))
                                    break;
                                var source = MainForm.Sources.FirstOrDefault(p => p.url.Any(q => q.id == mmid));
                                var mmurl = source?.url.FirstOrDefault(p => p.id == mmid);
                                if (mmurl == null)
                                    break;

                                string audioUri = "";
                                int audioSourceTypeID = -1;
                                if (!string.IsNullOrEmpty(mmurl.AudioSource))
                                {
                                    audioUri = Conf.GetAddr(mmurl, origUri, channel, username, password, true).ToString();
                                    audioSourceTypeID = Conf.GetSourceType(mmurl.AudioSource, 1);
                                }

                                int sourceTypeID = Conf.GetSourceType(mmurl.Source, 2);
                                string sourceUri = Conf.GetAddr(mmurl, origUri, channel, username, password).ToString();


                                oid = MainForm.NextCameraId;
                                
                                cw = (CameraWindow) MainForm.InstanceReference.AddObjectExternal(2, sourceTypeID,320,240,"",sourceUri);
                                    
                                cw.Camobject.settings.videosourcestring = sourceUri;
                                cw.Camobject.settings.cookies = mmurl.cookies;
                                cw.Camobject.settings.login = username;
                                cw.Camobject.settings.password = password;

                                if (!string.IsNullOrEmpty(mmurl.flags))
                                {
                                    string[] flags = mmurl.flags.Split(',');
                                    foreach (string f in flags)
                                    {
                                        if (!string.IsNullOrEmpty(f))
                                        {
                                            switch (f.ToUpper())
                                            {
                                                case "FBA":
                                                    cw.Camobject.settings.forcebasic = true;
                                                    break;
                                            }
                                        }
                                    }
                                }

                                int ptzentryid = 0;

                                if (!mmurl.@fixed)
                                {
                                    string modellc = model.ToLower();
                                    string n = make.ToLower();
                                    bool quit = false;
                                    foreach (var ptz in MainForm.PTZs)
                                    {
                                        int j = 0;
                                        foreach (var m in ptz.Makes)
                                        {
                                            if (m.Name.ToLower() == n)
                                            {
                                                ptzid = ptz.id;
                                                ptzentryid = j;
                                                string mdl = m.Model.ToLower();
                                                if (mdl == modellc || mmurl.version.ToLower() == mdl)
                                                {
                                                    ptzid = ptz.id;
                                                    ptzentryid = j;
                                                    quit = true;
                                                    break;
                                                }
                                            }
                                            j++;
                                        }
                                        if (quit)
                                            break;
                                    }
                                }

                                if (ptzid > -1)
                                {
                                    cw.Camobject.ptz = ptzid;
                                    cw.Camobject.ptzentryindex = ptzentryid;
                                    cw.Camobject.settings.ptzchannel = channel.ToString(CultureInfo.InvariantCulture);
                                    cw.Camobject.settings.ptzusername = username;
                                    cw.Camobject.settings.ptzpassword = password;
                                    cw.Camobject.settings.ptzurlbase = MainForm.PTZs.Single(p => p.id == ptzid).CommandURL;
                                }

                                if (!string.IsNullOrEmpty(mmurl.AudioModel))
                                {
                                    var audUri = new Uri(cw.Camobject.settings.videosourcestring);
                                    if (!string.IsNullOrEmpty(audUri.DnsSafeHost))
                                    {
                                        cw.Camobject.settings.audioip = audUri.DnsSafeHost;
                                    }
                                    cw.Camobject.settings.audiomodel = mmurl.AudioModel;
                                    cw.Camobject.settings.audioport = audUri.Port;
                                    cw.Camobject.settings.audiousername = username;
                                    cw.Camobject.settings.audiopassword = password;
                                }

                                if (audioSourceTypeID > -1)
                                {
                                    var vc = cw.VolumeControl;
                                    if (vc == null)
                                    {
                                        vc = MainForm.InstanceReference.AddCameraMicrophone(cw.Camobject.id, cw.Camobject.name + " mic");
                                        vc.Micobject.alerts.active = false;
                                        vc.Micobject.detector.recordonalert = false;
                                        vc.Micobject.detector.recordondetect = false;
                                        cw.SetVolumeLevel(vc.Micobject.id);
                                    }
                                    vc.Disable();
                                    vc.Micobject.settings.typeindex = audioSourceTypeID;
                                    vc.Micobject.settings.sourcename = audioUri;
                                    vc.Micobject.settings.needsupdate = true;
                                }
                                cw.Enable();

                                break;
                        }
                    }
                    resp = "{\"actionResult\":\"waiteditobjectnew\",\"typeID\":" + ot + ",\"ID\":" + oid + "}";
                    break;
                case "scannetwork":
                    {
                        string[] sports = GetVar(sPhysicalFilePath, "ports").Split(',');
                        bool full = GetVar(sPhysicalFilePath, "full") == "true";
                        var ports = new List<int>();
                        foreach (var s in sports)
                        {
                            int i;
                            if (int.TryParse(s, out i))
                            {
                                ports.Add(i);
                            }
                        }
                        if (ports.Count > 0)
                        {

                            NetworkDeviceList.RefreshARP();
                            var lip = new List<IPAddress>();
                            foreach (var ip in NetworkDeviceList.ARPList)
                            {
                                IPAddress ipa;
                                if (IPAddress.TryParse(ip.Key, out ipa))
                                {
                                    lip.Add(ipa);
                                }
                            }
                            if (lip.Count > 0)
                            {
                                _scanResults = new List<NetworkDevice>();
                                _scanner = new Scanner();
                                _scanner.DeviceFound += ScannerDeviceFound;
                                _scanner.ScanFinished += ScannerScanFinished;
                                Thread manager;
                                if (full)
                                {
                                    var ipranges = MainForm.AddressListIPv4.Select(ip => ip.ToString()).Select(subnet => subnet.Substring(0, subnet.LastIndexOf(".", StringComparison.Ordinal) + 1) + "x").ToList();
                                    manager = new Thread(p => _scanner.PortScannerManager(ipranges, ports))
                                    {
                                        Name ="Port Scanner",
                                        IsBackground=true,
                                        Priority=ThreadPriority.Normal
                                    };
                                }
                                else
                                {
                                    manager = new Thread(p => _scanner.ARPScannerManager(lip, ports))
                                    {
                                        Name = "ARP Scanner",
                                        IsBackground = true,
                                        Priority =ThreadPriority.Normal
                                    };
                                }
                                manager.Start();
                            }
                        }
                        resp = "{\"running\":true}";

                    }
                    break;
                case "getscannetworkresults":
                    {
                        resp = "{\"finished\":" + (_scanner == null).ToString().ToLower();
                        resp += ",\"results\":[";
                        if (_scanResults != null)
                        {
                            template = "{{\"deviceName\":\"{0}\",\"IPAddress\":\"{1}\",\"MAC\":\"{2}\",\"port\":{3},\"webServer\":\"{4}\"}},";
                            resp = _scanResults.Aggregate(resp, (current, dev) => current + String.Format(template, dev.DeviceName.JsonSafe(), dev.IPAddress, dev.MAC, dev.Port, dev.WebServer.JsonSafe()));
                            resp = resp.Trim(',');
                        }
                        resp += "]}";

                    }
                    break;
                case "scandevice":
                    {
                        if (_deviceScanner != null)
                        {
                            _deviceScanner.QuitScanner();
                            break;
                        }
                        Uri uri;
                        if (!Uri.TryCreate(GetVar(sPhysicalFilePath, "url"), UriKind.Absolute, out uri))
                        {
                            resp = "{\"error\":\"Invalid camera URL. Please check and try again.\"}";
                            break;
                        }
                        var make = GetVar(sPhysicalFilePath, "make");
                        var m = MainForm.Sources.FirstOrDefault(p => string.Equals(p.name, make, StringComparison.InvariantCultureIgnoreCase));
                        if (m == null)
                        {
                            resp = "{\"error\":\"Select a valid manufacturer (make) in Step 1\"}";
                            break;
                        }
                        make = m.name;
                        _devicescanResults = new List<ConnectionOption>();
                        _deviceScanner = new CameraScanner();
                        _deviceScanner.URLFound += DeviceScannerURLFound;
                        _deviceScanner.ScanComplete += DeviceScannerScanComplete;
                        _deviceScanner.Channel = Convert.ToInt32(GetVar(sPhysicalFilePath, "channel"));
                        _deviceScanner.Make = make;
                        _deviceScanner.Model = GetVar(sPhysicalFilePath, "model");
                        _deviceScanner.Username = GetVar(sPhysicalFilePath, "username");
                        _deviceScanner.Password = GetVar(sPhysicalFilePath, "password");
                        _deviceScanner.Uri = uri;
                        _deviceScanner.ScanCamera(m);

                        resp = "{\"running\":true}";

                    }
                    break;
                case "getscandeviceresults":
                    {
                        resp = "{\"finished\":" + (_deviceScanner == null).ToString().ToLower();
                        resp += ",\"results\":[";
                        if (_devicescanResults != null)
                        {
                            template = "{{\"type\":\"{0}\",\"URL\":\"{1}\",\"mmid\":{2}}},";
                            resp = _devicescanResults.Aggregate(resp, (current, dev) => current + String.Format(template, dev.Source, dev.URL.JsonSafe(), dev.MmUrl.id));

                            resp = resp.Trim(',');
                        }
                        resp += "]}";

                    }
                    break;
                case "loadmakes":
                    {
                        string s = GetVar(sPhysicalFilePath, "search");
                        string makes = "{\"makes\": [";

                        var ml = MainForm.Sources.Where(p => p.name.IndexOf(s, StringComparison.OrdinalIgnoreCase) != -1).OrderBy(p => p.name).Take(20).ToList();
                        var sb = new StringBuilder();
                        foreach (var m in ml)
                        {
                            sb.Append("\"" + m.name.JsonSafe() + "\",");
                        }
                        makes += sb.ToString().Trim(',');

                        resp = makes + "]}";
                    }
                    break;
                case "loadmodels":
                    {
                        string s = GetVar(sPhysicalFilePath, "search");
                        string m = GetVar(sPhysicalFilePath, "make");
                        var make = MainForm.Sources.FirstOrDefault(p => p.name.ToLowerInvariant() == m.ToLowerInvariant());

                        string models = "{\"models\": [\"Other\",";

                        if (make != null)
                        {
                            var lmake = make.url.Where(p => p.version.IndexOf(s, StringComparison.OrdinalIgnoreCase) != -1).OrderBy(p => p.version).ToList();
                            int i = 0;
                            foreach (var u in lmake)
                            {
                                if (!string.IsNullOrEmpty(u.version))
                                {
                                    if (models.IndexOf("\"" + u.version + "\"", StringComparison.OrdinalIgnoreCase) ==
                                        -1)
                                    {
                                        models += "\"" + u.version.JsonSafe() + "\",";
                                        i++;
                                        if (i == 20)
                                            break;
                                    }
                                }
                            }
                        }

                        resp = models.Trim(',') + "]}";
                    }
                    break;
                case "loadapi":
                {
                    resp = BuildApijson(r);
                }
                    break;
                case "authorise":
                    {
                        string provider = GetVar(sPhysicalFilePath, "provider");
                        t = "{{\"provider\":\"{0}\",\"url\":\"{1}\",\"message\":\"{2}\",\"error\":\"{3}\"}}";
                        string url = "", message = "", error = "";
                        if (!MainForm.Conf.Subscribed)
                        {
                            error = LocRm.GetString("NotSubscribed");
                        }
                        else
                        { 
                            switch (provider)
                            {
                                case "dropbox":
                                    url = Dropbox.GetAuthoriseURL(out error);
                                    break;
                                case "drive":
                                    if (Drive.Authorise())
                                    {
                                        message = "Authorised";
                                    }
                                    else
                                        error = "Failed";
                                    break;
                                case "youtube":
                                    if (YouTubeUploader.Authorise())
                                    {
                                        message = "Authorised";
                                    }
                                    else
                                        error = "Failed";
                                    break;

                            }
                        }

                        resp = string.Format(t, provider, url, message, error);
                    }
                    break;
                case "onvifdiscover":
                    {
                        string un = GetVar(sPhysicalFilePath, "un");
                        string pwd = GetVar(sPhysicalFilePath, "pwd");
                        string url = GetVar(sPhysicalFilePath, "surl");

                        Uri u;
                        if (!Uri.TryCreate(url, UriKind.Absolute, out u))
                        {
                            resp = "{\"error\":\"Service URL is invalid\"}";
                            break;
                        }
                        var devHolder = new DeviceDescriptionHolder
                        {
                            Uris = new[] { u },
                            Address = u.DnsSafeHost,
                            Name = u.AbsoluteUri,
                            DeviceIconUri = null
                        };

                        try
                        {
                            var dev = MainForm.ONVIFDevices.FirstOrDefault(p => p.Address == devHolder.Address);
                            if (dev == null)
                            {
                                MainForm.ONVIFDevices.Add(devHolder);
                            }
                            else
                                devHolder = dev;

                            devHolder.Account = new NetworkCredential { UserName = un, Password = pwd };
                            var sessionFactory = new NvtSessionFactory(devHolder.Account);

                            template = "{{\"text\":\"{0}\",\"value\":\"{1}\"}},";
                            foreach (var uri in devHolder.Uris)
                            {
                                var f = sessionFactory.CreateSession(uri);
                                devHolder.URL = uri.ToString();
                                Profile[] profiles;
                                try
                                {
                                    profiles = f.GetProfiles().RunSynchronously();
                                }
                                catch (Exception ex)
                                {
                                    Logger.LogExceptionToFile(ex, "ONVIF");
                                    throw;
                                }

                                devHolder.Profiles = profiles;
                                foreach (var p in profiles)
                                {
                                    try
                                    {
                                        string streamSize = p.videoEncoderConfiguration.resolution.width + "x" +
                                                            p.videoEncoderConfiguration.resolution.height;
                                        resp += String.Format(template, streamSize.JsonSafe(), p.token);
                                    }
                                    catch (Exception ex)
                                    {
                                        Logger.LogExceptionToFile(ex, "ONVIF");
                                    }

                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            resp = "{\"error\":\"" + ex.Message.JsonSafe() + "\"}";
                            break;
                        }
                        resp = "{\"list\":[" + resp.Trim(',') + "]}";
                    }
                    break;
                case "editsource":
                    {
                        switch (ot)
                        {
                            case 1:
                                {
                                    objectsMicrophone om = MainForm.Microphones.FirstOrDefault(p => p.id == oid);
                                    if (om == null)
                                        throw new Exception("Microphone not found");
                                    resp = File.ReadAllText(r + @"api\editaudiosource.json");

                                    var st = om.settings.typeindex.ToString(CultureInfo.InvariantCulture);

                                    var se = File.ReadAllText(r + @"api\sources\audio\" + st + ".json");
                                    string task = "";

                                    string m = GetVar(sPhysicalFilePath, "id");
                                    if (!string.IsNullOrEmpty(m))
                                    {
                                        om.settings.sourcename = m;
                                        task = "rendersourceeditor";
                                    }
                                    template = "{{\"text\":\"{0}\",\"value\":\"{1}\"}},";
                                    switch (st)
                                    {
                                        case "0":
                                            //localdevice

                                            string sr = Conf.SampleRates.Aggregate("", (current, s) => current + String.Format(template, s, s));

                                            if (!Conf.SampleRates.Contains(om.settings.samples))
                                                om.settings.samples = 8000;

                                            se = se.Replace("SAMPLERATES", sr.Trim(','));
                                            try
                                            {
                                                string devs = "";
                                                for (int n = 0; n < WaveIn.DeviceCount; n++)
                                                {
                                                    string name = WaveIn.GetCapabilities(n).ProductName.JsonSafe();
                                                    devs += String.Format(template, name, name);

                                                }
                                                se = se.Replace("DEVICELIST", devs.Trim(','));
                                            }
                                            catch (ApplicationException ex)
                                            {
                                                Logger.LogExceptionToFile(ex, "LocalDevice");
                                            }
                                            break;
                                        case "5":
                                            string miclist = MainForm.Microphones.Where(mic => mic.id != om.id && mic.settings.typeindex != 5).Aggregate("", (current, mic) => current + String.Format(template, mic.name.JsonSafe(), mic.id));
                                            se = se.Replace("MICROPHONES", miclist.Trim(','));
                                            break;
                                    }
                                    resp = resp.Replace("SOURCEEDITOR", se);

                                    dynamic d = PopulateResponse(resp, om);
                                    d.task = task;
                                    resp = JsonConvert.SerializeObject(d);
                                }
                                break;
                            case 2:
                                {
                                    objectsCamera oc = MainForm.Cameras.FirstOrDefault(p => p.id == oid);
                                    if (oc == null)
                                        throw new Exception("Camera not found");
                                    resp = File.ReadAllText(r + @"api\editvideosource.json");

                                    var st = oc.settings.sourceindex.ToString(CultureInfo.InvariantCulture);

                                    var se = File.ReadAllText(r + @"api\sources\video\" + st + ".json");
                                    string task = "";

                                    string m = GetVar(sPhysicalFilePath, "id");
                                    if (!string.IsNullOrEmpty(m))
                                    {
                                        oc.settings.videosourcestring = m;
                                        task = "rendersourceeditor";
                                    }

                                    template = "{{\"text\":\"{0}\",\"value\":\"{1}\"}},";

                                    switch (st)
                                    {
                                        case "3":
                                            //localdevice
                                            string devicelist = "",
                                                videoresolutions = "",
                                                inputlist = "",
                                                snapshotresolutions = "",
                                                capturemodes = "";

                                            var disc = new Sources.Video.discovery.LocalDevice();
                                            string moniker = "";
                                            var ldev = disc.Devices;
                                            foreach (var dev in ldev)
                                            {
                                                devicelist += String.Format(template, dev.Name.JsonSafe(), dev.Value.JsonSafe());
                                                if (String.Equals(oc.settings.videosourcestring, dev.Value,
                                                    StringComparison.InvariantCultureIgnoreCase))
                                                {
                                                    moniker = dev.Value;
                                                    oc.settings.videosourcestring = dev.Value;
                                                }

                                            }
                                            if (moniker == "")
                                            {
                                                if (ldev.Count > 0)
                                                    moniker = ldev.First().Value;
                                            }
                                            if (moniker != "")
                                            {
                                                disc.Inspect(moniker);
                                                inputlist = disc.Inputs.Aggregate(inputlist, (current, input) => current + String.Format(template, input.Name.JsonSafe(), input.Value.JsonSafe()));
                                                videoresolutions = disc.VideoResolutions.Aggregate(videoresolutions, (current, vres) => current + String.Format(template, vres.Name.JsonSafe(), vres.Value.JsonSafe()));
                                                snapshotresolutions = disc.SnapshotResolutions.Aggregate(snapshotresolutions, (current, sres) => current + String.Format(template, sres.Name.JsonSafe(), sres.Value.JsonSafe()));

                                                if (disc.SupportsSnapshots)
                                                {
                                                    capturemodes += String.Format(template, "Snapshots", "snapshots");
                                                }
                                                if (disc.SupportsVideo)
                                                {
                                                    capturemodes += String.Format(template, "Video", "video");
                                                }
                                            }

                                            se = se.Replace("DEVICELIST", devicelist.Trim(','));
                                            se = se.Replace("VIDEORESOLUTIONS", videoresolutions.Trim(','));
                                            se = se.Replace("SNAPSHOTRESOLUTIONS", snapshotresolutions.Trim(','));
                                            se = se.Replace("INPUTLIST", inputlist.Trim(','));
                                            se = se.Replace("CAPTUREMODES", capturemodes.Trim(','));
                                            break;
                                        case "4":
                                            string screens = "";
                                            int i = 0,j=0;
                                            foreach (Screen s in Screen.AllScreens)
                                            {
                                                screens += String.Format(template, s.DeviceName.JsonSafe(),
                                                    i.ToString(CultureInfo.InvariantCulture));
                                                i++;
                                                if (oc.settings.videosourcestring == i.ToString(CultureInfo.InvariantCulture))
                                                    j = i;
                                            }
                                            se = se.Replace("SCREENS", screens.Trim(','));
                                            if (oc.settings.videosourcestring == null)
                                                oc.settings.videosourcestring = j.ToString(CultureInfo.InvariantCulture);
                                            var area = "[]";
                                            if (oc.settings.desktoparea != null) { 
                                                int[] arr = System.Array.ConvertAll(oc.settings.desktoparea.Split(','), int.Parse);
                                                if (arr.Length == 4)
                                                {
                                                    var sc = Screen.AllScreens[j];
                                                    arr[0] = Math.Min(100, Convert.ToInt32((Convert.ToDecimal(arr[0])/sc.WorkingArea.Width)*100));
                                                    arr[1] = Math.Min(100, Convert.ToInt32((Convert.ToDecimal(arr[1])/sc.WorkingArea.Height)*100));
                                                    arr[2] = Math.Min(100, Convert.ToInt32((Convert.ToDecimal(arr[2])/sc.WorkingArea.Width)*100));
                                                    arr[3] = Math.Min(100, Convert.ToInt32((Convert.ToDecimal(arr[3])/sc.WorkingArea.Height)*100));
                                                    area = "[{\"x\":" + arr[0] + ",\"y\":" + arr[1] + ",\"w\":" + arr[2] +
                                                           ",\"h\":" + arr[3] + "}]";
                                                }
                                            }
                                            se = se.Replace("SCREENAREA", area);
                                            break;
                                        case "9":
                                            if (oc.settings.namevaluesettings.IndexOf("use=", StringComparison.Ordinal) == -1)
                                                oc.settings.namevaluesettings = "use=ffmpeg,transport=RTSP";

                                            string[] cfg = oc.settings.onvifident.Split('|');
                                            if (cfg.Length == 2)
                                            {
                                                oc.settings.namevaluesettings += ",profileid=" + cfg[1];
                                                oc.settings.onvifident = cfg[0];
                                            }

                                            string svlc = "";
                                            if (VlcHelper.VlcInstalled)
                                            {
                                                svlc = ",{\"text\": \"VLC\", \"value\": \"vlc\"}";
                                            }
                                            se = se.Replace("VLCOPT", svlc);

                                            var ourl = "";
                                            var ss = NV(oc.settings.namevaluesettings, "streamsize");
                                            var pn = NV(oc.settings.namevaluesettings, "profilename");
                                            if (ss != "" && pn != "")
                                            {
                                                ourl = "{\"text\":\"" + ss + "\",\"value\":\"" + pn.JsonSafe() + "\"}";
                                            }
                                            se = se.Replace("ONVIFURL", ourl);
                                            break;
                                        case "10":
                                            string camlist = MainForm.Cameras.Where(cam => cam.id != oc.id && cam.settings.sourceindex != 10).Aggregate("", (current, cam) => current + String.Format(template, cam.name.JsonSafe(), cam.id));
                                            se = se.Replace("CAMERAS", camlist.Trim(','));
                                            break;
                                    }

                                    resp = resp.Replace("SOURCEEDITOR", se);

                                    dynamic d = PopulateResponse(resp, oc);
                                    d.task = task;
                                    resp = JsonConvert.SerializeObject(d);
                                }
                                break;
                        }

                    }
                    break;
                case "editpelco":
                    {
                        switch (ot)
                        {
                            case 2:
                                objectsCamera oc = MainForm.Cameras.FirstOrDefault(p => p.id == oid);
                                if (oc == null)
                                    throw new Exception("Camera not found");
                                resp = File.ReadAllText(r + @"api\editpelco.json");



                                string[] ports = System.IO.Ports.SerialPort.GetPortNames();
                                string comports = ports.Aggregate("", (current, p) => current + String.Format(template, p, p));

                                resp = resp.Replace("COMPORTS", comports.Trim(','));
                                dynamic d = PopulateResponse(resp, oc);
                                resp = JsonConvert.SerializeObject(d);
                                break;
                        }

                    }
                    break;
                case "editftp":
                    {
                        string ident = GetVar(sPhysicalFilePath, "ident");
                        resp = File.ReadAllText(r + @"api\editftp.json");
                        if (ident != "new")
                        {
                            var ftp = MainForm.Conf.FTPServers.First(p => p.ident == ident);
                            dynamic d = PopulateResponse(resp, ftp);
                            d.ident = ftp.ident;
                            resp = JsonConvert.SerializeObject(d);
                        }
                        else
                        {
                            dynamic d = JsonConvert.DeserializeObject(resp);
                            resp = JsonConvert.SerializeObject(d);
                        }

                    }
                    break;
                case "editstorage":
                {
                        var ident = GetVar(sPhysicalFilePath, "ident");
                        resp = File.ReadAllText(r + @"api\editstorage.json");
                        if (ident != "new")
                        {
                            var dir = MainForm.Conf.MediaDirectories.First(p => p.ID == Convert.ToInt32(ident));
                            dynamic d = PopulateResponse(resp, dir);
                            d.ident = dir.ID;
                            resp = JsonConvert.SerializeObject(d);
                        }
                        else
                        {
                            dynamic d = JsonConvert.DeserializeObject(resp);
                            resp = JsonConvert.SerializeObject(d);
                        }

                    }
                    break;
                case "editschedule":
                    {
                        string ident = GetVar(sPhysicalFilePath, "ident");
                        resp = File.ReadAllText(r + @"api\editschedule.json");

                        var actions = Helper.Actions.ToList();
                        switch (ot)
                        {
                            case 1:
                                actions =
                                    actions.Where(p => p.TypeID != Helper.ScheduleAction.ActionTypeID.CameraOnly).ToList();
                                break;
                        }
                        t = actions.Aggregate(t, (current, a) => current + string.Format(template, Helper.ScheduleDescription(a.ID).JsonSafe(), a.ID));
                        resp = resp.Replace("SCHEDULEACTIONS", t.Trim(','));

                        t = "";
                        foreach (var aa in MainForm.Actions.Where(p => p.objectid == oid && p.objecttypeid == ot))
                        {
                            var ae = new ActionEditor.ActionEntry(aa);
                            t += string.Format(template, (aa.mode + ": " + ae.Summary).JsonSafe(), aa.ident);
                        }
                        resp = resp.Replace("ALERTLIST", t.Trim(','));
                        resp = resp.Replace("TIME", DateTime.Now.ToString("HH:mm:ss"));

                        if (ident != "new")
                        {
                            int id = Convert.ToInt32(ident);
                            var scheds = MainForm.Schedule.Where(p => p.objectid == oid && p.objecttypeid == ot).ToList();
                            if (scheds.Count > id)
                            {
                                dynamic d = PopulateResponse(resp, scheds[id]);
                                d.ident = id;
                                resp = JsonConvert.SerializeObject(d);
                            }
                        }
                        else
                        {
                            dynamic d = JsonConvert.DeserializeObject(resp);
                            resp = JsonConvert.SerializeObject(d);
                        }

                    }
                    break;
                case "editptzschedule":
                    {
                        string ident = GetVar(sPhysicalFilePath, "ident");
                        resp = File.ReadAllText(r + @"api\editptzschedule.json");
                        var oc = MainForm.Cameras.FirstOrDefault(p => p.id == oid);
                        if (oc != null)
                        {
                            string ptzcommands = "";
                            var lcoms = MainForm.PTZs.FirstOrDefault(p => p.id == oc.ptz);
                            if (lcoms != null)
                            {
                                var coms = lcoms.ExtendedCommands.Command.ToList();
                                ptzcommands = coms.Aggregate(ptzcommands, (current, com) => current + String.Format(template, com.Name.JsonSafe(), com.Name.JsonSafe()));
                                resp = resp.Replace("PTZCOMMANDS", ptzcommands.Trim(','));
                            }
                            else
                                resp = resp.Replace("PTZCOMMANDS", "");

                            resp = resp.Replace("TIME", DateTime.Now.ToString("HH:mm:ss"));

                            if (ident != "new")
                            {
                                int id = Convert.ToInt32(ident);
                                var ptzsched = oc.ptzschedule.entries.ToList();
                                if (ptzsched.Count > id)
                                {
                                    dynamic d = PopulateResponse(resp, ptzsched[id]);
                                    d.ident = id;
                                    resp = JsonConvert.SerializeObject(d);
                                }

                            }
                            else
                            {
                                dynamic d = JsonConvert.DeserializeObject(resp);
                                resp = JsonConvert.SerializeObject(d);
                            }
                        }
                    }
                    break;
                case "editaction":
                    {
                        string ident = GetVar(sPhysicalFilePath, "ident");
                        resp = File.ReadAllText(r + @"api\editaction.json");
                        resp = resp.Replace("ACTIONS", Helper.AvailableActionsJson);
                            template = "{{\"text\":\"{0}\",\"value\":{1},\"type\":\"{2}\",\"bindto\":\"{3}\"{4}}},";

                        var par = "";
                        bool bGrab;
                        var action = MainForm.Actions.FirstOrDefault(p => p.ident == ident) ?? new objectsActionsEntry
                                                                                           {
                                                                                               mode = "alert",
                                                                                               active = true,
                                                                                               objectid = oid,
                                                                                               objecttypeid = ot,
                                                                                               type = "S"
                                                                                           };

                        string id = GetVar(sPhysicalFilePath, "id").ToUpper();
                        if (id != "")
                            action.type = id;

                        string mode = GetVar(sPhysicalFilePath, "mode");

                        if (mode != "") action.mode = mode;
                        bool active;

                        if (Boolean.TryParse(GetVar(sPhysicalFilePath, "active"), out active))
                            action.active = active;

                        switch (action.type.ToUpper())
                        {
                            case "S":
                            case "ATC":
                                par = String.Format(template, "File", "\"" + action.param1.JsonSafe() + "\"", "Select",
                                    "param1",
                                    ",\"options\":[" + GetFileOptionsList("Sounds", "*.wav") +
                                    "],\"help\":\"Add more sounds (.wav) into " + (Program.AppPath + "sounds").JsonSafe() + "\"");
                                break;
                            case "EXE":
                                par = String.Format(template, "File", "\"" + action.param1.JsonSafe() + "\"", "Select",
                                    "param1", ",\"options\":[" + GetFileOptionsList("Commands", "*.*") +
                                    "],\"help\":\"Add batch files or executables into " + (Program.AppPath + "commands").JsonSafe() + "\"");
                                break;
                            case "URL":
                                par = String.Format(template, "URL", "\"" + action.param1.JsonSafe() + "\"", "String",
                                    "param1", "");

                                Boolean.TryParse(action.param2, out bGrab);
                                par += String.Format(template, "POST Grab", bGrab.ToString().ToLower(), "Boolean", "param2",
                                    "");
                                break;
                            case "NM":
                                if (action.param1 == "")
                                    action.param1 = "TCP";
                                if (action.param3 == "")
                                    action.param3 = "1010";
                                par += String.Format(template, "Type", "\"" + action.param1.JsonSafe() + "\"", "Select",
                                    "param1",
                                    ", \"options\":[{\"text\":\"TCP\",\"value\":\"TCP\"},{\"text\":\"UDP\",\"value\":\"UDP\"}]");
                                par += String.Format(template, "IP Address", "\"" + action.param2.JsonSafe() + "\"",
                                    "String", "param2", "");

                                par += String.Format(template, "Port", "\"" + action.param3.JsonSafe() + "\"", "String", "param3",
                                    ",\"min\":0,\"max\":65535");

                                par += String.Format(template, "Message", "\"" + action.param4 + "\"", "String", "param4",
                                    "");
                                break;
                            case "SW":
                            case "B":
                            case "M":
                            case "TM":
                                par = "";
                                break;
                            case "TA":
                            case "SOF":
                            case "SOO":
                                var optlist = MainForm.Cameras.Aggregate("", (current, c) => current + ("{\"text\":\"" + c.name.JsonSafe() + "\",\"value\":\"2," + c.id + "\"},"));
                                optlist = MainForm.Microphones.Aggregate(optlist, (current, c) => current + ("{\"text\":\"" + c.name.JsonSafe() + "\",\"value\":\"1," + c.id + "\"},"));
                                par += string.Format(template, "Object", "\"" + action.param1.JsonSafe() + "\"",
                                    "Select", "param1", ", \"options\":[" + optlist.Trim(',') + "]");
                                break;
                            case "E":
                                par = string.Format(template, "Email Address", "\"" + action.param1.JsonSafe() + "\"",
                                    "String", "param1", "");
                                bool.TryParse(action.param2, out bGrab);
                                par += string.Format(template, "Include Grab", bGrab.ToString().ToLower(), "Boolean",
                                    "param2", "");
                                break;
                            case "SMS":
                                par = string.Format(template, "SMS Number", "\"" + action.param1.JsonSafe() + "\"", "String",
                                    "param1", "");
                                break;
                        }
                        resp = par != "" ? resp.Replace("PARAMS", "," + par.Trim(',')) : resp.Replace("PARAMS", "");

                        dynamic d = PopulateResponse(resp, action);
                        d.ident = ident;
                        if (id != "")
                            d.task = "bindActionView";
                        resp = JsonConvert.SerializeObject(d);

                    }
                    break;
                case "deleteschedule":
                    {
                        int id = Convert.ToInt32(GetVar(sPhysicalFilePath, "ident"));
                        var scheds = MainForm.Schedule.Where(p => p.objectid == oid && p.objecttypeid == ot).ToList();
                        if (scheds.Count > id)
                        {
                            scheds.RemoveAt(id);
                            MainForm.Schedule.RemoveAll(p => p.objectid == oid && p.objecttypeid == ot);
                            MainForm.Schedule.AddRange(scheds);
                        }
                        resp = "{\"actionResult\":\"reloadSchedule\"}";
                    }
                    break;
                case "deleteptzschedule":
                    {
                        int id = Convert.ToInt32(GetVar(sPhysicalFilePath, "ident"));
                        var oc = MainForm.Cameras.First(p => p.id == oid);
                        var scheds = oc?.ptzschedule.entries.ToList();
                        if (scheds?.Count > id)
                        {
                            scheds.RemoveAt(id);
                            oc.ptzschedule.entries = scheds.ToArray();
                        }
                        resp = "{\"actionResult\":\"reloadPTZSchedule\"}";
                    }
                    break;
                case "showschedule":
                    {
                        var sched = MainForm.Schedule.Where(p => p.objectid == oid && p.objecttypeid == ot).ToList();
                        int i = 0;
                        foreach (var se in sched)
                        {
                            string text = FormatTime(se.time) + " " + FormatDays(se.daysofweek.Split(',')) + " " +
                                         Helper.ScheduleDescription(se.typeid);
                            t += String.Format(template, text.JsonSafe(), i);
                            i++;

                        }
                        resp = File.ReadAllText(r + @"api\showschedule.json");
                        resp = resp.Replace("SCHEDULE", t.Trim(','));

                    }
                    break;
                case "showptzschedule":
                    {
                        int i = 0;
                        var oc = MainForm.Cameras.FirstOrDefault(p => p.id == oid);
                        if (oc != null)
                        {
                            foreach (var pts in oc.ptzschedule.entries)
                            {
                                string text = pts.time.ToString("HH:mm") + " " + pts.command;
                                t += String.Format(template, text.JsonSafe(), i);
                                i++;
                            }
                        }
                        resp = File.ReadAllText(r + @"api\showptzschedule.json");
                        resp = resp.Replace("SCHEDULE", t.Trim(','));

                    }
                    break;
                case "showactions":
                    {
                        var actions = MainForm.Actions.Where(p => p.objectid == oid && p.objecttypeid == ot).OrderBy(p => p.mode).ToList();
                        foreach (var se in actions)
                        {
                            string m = se.mode;
                            switch (se.mode)
                            {
                                case "alert":
                                    m = "Alert";
                                    break;
                                case "reconnect":
                                    m = "Source Reconnected";
                                    break;
                                case "reconnectfailed":
                                    m = "Reconnect Failed";
                                    break;
                                case "disconnect":
                                    m = "Source Disconnected";
                                    break;
                                case "alertstopped":
                                    m = "Alert Stopped";
                                    break;
                                case "recordingstarted":
                                    m = "Recording Started";
                                    break;
                                case "recordingstopped":
                                    m = "Recording Stopped";
                                    break;
                            }
                            t += String.Format(template, (se.active ? "Active" : "Disabled") + ": " + m + " " + Helper.AlertSummary(se).JsonSafe(), se.ident);
                        }
                        resp = File.ReadAllText(r + @"api\showactions.json");
                        resp = resp.Replace("ACTIONS", t.Trim(','));

                    }
                    break;
                case "deleteaction":
                    {
                        MainForm.Actions.RemoveAll(p => p.ident == GetVar(sPhysicalFilePath, "ident"));
                        MainForm.SaveConfig();
                        resp = "{\"actionResult\":\"reloadActions\"}";
                    }
                    break;
                case "deleteftp":
                    {
                        var lTemp = MainForm.Conf.FTPServers.ToList();
                        lTemp.RemoveAll(p => p.ident == GetVar(sPhysicalFilePath, "ident"));
                        MainForm.Conf.FTPServers = lTemp.ToArray();
                        MainForm.SaveConfig();

                        resp = "{\"actionResult\":\"reloadFTPServers\"}";
                    }
                    break;
                case "deletestorage":
                    {
                        string ident = GetVar(sPhysicalFilePath, "ident");
                        var id = Convert.ToInt32(ident);
                        var lname = new List<string>();
                        lname.AddRange(MainForm.Cameras.Where(p => p.settings.directoryIndex == id).Select(p => p.name));
                        lname.AddRange(MainForm.Microphones.Where(p => p.settings.directoryIndex == id).Select(p => p.name));
                        if (lname.Count > 0)
                        {
                            resp = "{\"error\":\"There are "+lname.Count+" control(s) using this storage location\"}";
                            break;
                        }
                        var lTemp = MainForm.Conf.MediaDirectories.ToList();
                        lTemp.RemoveAll(p => p.ID == Convert.ToInt32(ident));
                        MainForm.Conf.MediaDirectories = lTemp.ToArray();
                        MainForm.SaveConfig();
                        resp = "{\"actionResult\":\"reloadStorage\"}";
                    }
                    break;

                case "loadobjects":
                    {
                        template =
                            "{{\"name\":\"{0}\",\"groups\":\"{1}\",\"typeID\":{2},\"id\":{3},\"active\":{4},\"ptzID\":{5},\"talk\":{6},\"micID\":{7},\"camID\":{8}}},\n";


                        string objectList = "";
                        if (MainForm.Cameras != null)
                        {
                            objectList = MainForm.Cameras.Where(p => !p.deleted)
                                .Aggregate(objectList,
                                    (current, obj) =>
                                        current +
                                        string.Format(template, obj.name.JsonSafe(), obj.settings.accessgroups.JsonSafe(), 2, obj.id,
                                            obj.settings.active.ToString().ToLowerInvariant(), obj.ptz,
                                            (obj.settings.audiomodel != "None").ToString().ToLowerInvariant(),
                                            obj.settings.micpair, -1));
                        }
                        if (MainForm.Microphones != null)
                        {
                            foreach (var obj in MainForm.Microphones.Where(p => !p.deleted))
                            {
                                int camID = -1;
                                var oc = MainForm.Cameras.FirstOrDefault(p => p.settings.micpair == obj.id);
                                if (oc != null)
                                {
                                    camID = oc.id;
                                    if (oc.deleted)
                                        continue;
                                }

                                objectList += string.Format(template, obj.name.JsonSafe(), obj.settings.accessgroups.JsonSafe(), 1, obj.id,
                                                obj.settings.active.ToString().ToLowerInvariant(), -1, "false", -1, camID);
                            }

                        }
                        objectList = objectList.Trim().Trim(',');
                        resp = "{\"objectList\": [" + objectList + "]}";
                    }
                    break;
                case "getlist":
                    {
                        template =
                            "{{\"text\":\"{0}\",\"value\":\"{1}\"}},";

                        string source = GetVar(sPhysicalFilePath, "source");
                        string[] id = GetVar(sPhysicalFilePath, "id").Split(',');
                        string special = "";
                        var lcomms = new List<Helper.ListItem>();
                        switch (source)
                        {
                            case "ptzcommands":
                                special = "\"url\":\"{0}\",";
                                string url = "";
                                switch (id[0])
                                {
                                    case "-6":
                                    case "-1":
                                    case "-2":
                                        break;
                                    case "-3":
                                    case "-4":
                                        {
                                            lcomms.AddRange(PTZController.PelcoCommands.Select(c => new Helper.ListItem(c, c)));
                                        }
                                        break;

                                    case "-5":
                                    {
                                        var cc = MainForm.InstanceReference.GetCameraWindow(oid);
                                        lcomms.AddRange(cc.PTZ.ONVIFPresets.Select(c => new Helper.ListItem(c, c)));
                                    }
                                        break;

                                    default:
                                        var ptz = MainForm.PTZs.Single(p => p.id == Convert.ToInt32(id[0]));
                                        if (ptz != null)
                                        {
                                            url = ptz.CommandURL;
                                            if (ptz.ExtendedCommands?.Command != null)
                                            {
                                                lcomms.AddRange(ptz.ExtendedCommands.Command.Select(extcmd => new Helper.ListItem(extcmd.Name, extcmd.Value)));
                                            }
                                        }
                                        break;
                                }
                                special = string.Format(special, url);
                                break;
                        }
                        resp = lcomms.Aggregate("", (current, li) => current + string.Format(template, li.Name, li.Value.JsonSafe()));
                        resp = "{\"task\":\"" + GetVar(sPhysicalFilePath, "task") + "\",\"target\":\"" + GetVar(sPhysicalFilePath, "target") + "\"," + special + "\"list\": [" + resp.Trim(',') + "]}";
                    }
                    break;
                case "deleteobject":
                    {
                        if (io != null)
                        {
                            MainForm.InstanceReference.RemoveObject(io);
                        }

                        resp = "{\"actionResult\":\"ok\"}";
                    }
                    break;
                case "getsettings":
                    {
                        template = "{{\"text\":\"{0}\",\"value\":\"{1}\"}},";

                        resp = File.ReadAllText(r + @"api\settings.json");
                        string ftp = MainForm.Conf.FTPServers.Aggregate("", (current, srv) => current + String.Format(template, srv.name, srv.ident));
                        resp = resp.Replace("FTPSERVERS", ftp.Trim(','));

                        template = "{{\"text\":\"{0}\",\"value\":{1}}},";

                        string ds = MainForm.Conf.MediaDirectories.Aggregate("", (current, cfg) => current + String.Format(template, cfg.Entry.JsonSafe(), cfg.ID));
                        resp = resp.Replace("DIRECTORIES", ds.Trim(','));

                        dynamic d = PopulateResponse(resp, MainForm.Conf);
                        resp = JsonConvert.SerializeObject(d);
                    }
                    break;
                case "editobject":
                    {
                        object o = null;
                        switch (ot)
                        {
                            case 1:
                                {
                                    objectsMicrophone om = MainForm.Microphones.FirstOrDefault(p => p.id == oid);
                                    if (om == null)
                                        throw new Exception("Microphone not found");
                                    resp = File.ReadAllText(r + @"api\editmicrophone.json");

                                    t = "{{ \"text\": \"{0}\", \"value\": {1}}},";
                                    var ldev =
                                        Conf.DeviceList.Where(p => p.ObjectTypeID == 1 && !p.ExcludeFromOnline)
                                            .OrderBy(p => p.Name);
                                    string s = ldev.Aggregate("",
                                        (current, source) => current + String.Format(t, source.Name.JsonSafe(), source.SourceTypeID));

                                    resp = resp.Replace("SOURCETYPES", s.Trim(','));

                                    o = om;
                                }
                                break;
                            case 2:
                                {
                                    objectsCamera oc = MainForm.Cameras.FirstOrDefault(p => p.id == oid);
                                    if (oc == null)
                                        throw new Exception("Camera not found");

                                    resp = File.ReadAllText(r + @"api\editcamera.json");
                                    var feats = Enum.GetNames(typeof(RotateFlipType));

                                    t = "{{ \"text\": \"{0}\", \"value\": \"{1}\"}},";
                                    string rm = feats.Aggregate("",
                                        (current, f) =>
                                            current + String.Format(t, Regex.Replace(f, "([a-z,0-9])([A-Z])", "$1 $2"), f));
                                    resp = resp.Replace("ROTATEMODES", rm.Trim(','));

                                    string ftps = MainForm.Conf.FTPServers.Aggregate("",
                                        (current, ftp) => current + String.Format(t, ftp.name.JsonSafe(), ftp.ident));
                                    resp = resp.Replace("FTPSERVERS", ftps.Trim(','));


                                    resp = resp.Replace("MASKFOLDER", Program.AppPath.JsonSafe() + "Masks");
                                    resp = resp.Replace("MASKS", GetFileOptionsList("Masks", "*.png"));


                                    t = "{{ \"text\": \"{0}\", \"value\": {1}}},";

                                    var audio = "";
                                    audio += string.Format(template, "None", -1);
                                    audio = (from om in MainForm.Microphones.Where(p => !p.deleted) let om1 = om where MainForm.Cameras.Count(p => p.settings.micpair == om1.id && p.id != oc.id) == 0 select om).Aggregate(audio, (current, om) => current + string.Format(template, om.name.JsonSafe(), om.id));
                                    resp = resp.Replace("AUDIOSOURCES", audio.Trim(','));


                                    var ldev =
                                        Conf.DeviceList.Where(p => p.ObjectTypeID == 2 && !p.ExcludeFromOnline)
                                            .OrderBy(p => p.Name);
                                    string s = ldev.Aggregate("",
                                        (current, source) => current + String.Format(t, source.Name.JsonSafe(), source.SourceTypeID));

                                    resp = resp.Replace("SOURCETYPES", s.Trim(','));





                                    t = "{{ \"text\": \"{0}\", \"value\": \"{1}\"}},";
                                    var ptzEntry = MainForm.PTZs.SingleOrDefault(p => p.id == oc.ptz);
                                    var commands = "";
                                    if (ptzEntry?.ExtendedCommands?.Command != null)
                                    {
                                        commands = ptzEntry.ExtendedCommands.Command.Aggregate(commands,
                                            (current, extcmd) => current + string.Format(t, extcmd.Name.JsonSafe(), extcmd.Value));
                                    }
                                    if (commands == "")
                                    {
                                        commands = string.Format(t, "None", "");
                                    }
                                    resp = resp.Replace("PTZCOMMANDS", commands.Trim(','));

                                    t = "{{ 'x': {0}, 'y': {1} , 'w': {2} , 'h': {3} }},";
                                    string zl = oc.detector.motionzones.Aggregate("", (current, z) => current + String.Format(t, z.left, z.top, z.width, z.height));

                                    resp = resp.Replace("ZONES", zl.Trim(','));

                                    t = "{{ 'id': {0}, 'x': {1}, 'y': {2} , 'w': {3} , 'h': {4} }},";

                                    var l = oc.settings.pip.config.Split('|');
                                    string pip = (from cfg in l where !string.IsNullOrEmpty(cfg) select cfg.Split(',') into p where p.Length == 5 select p).Aggregate("", (current, p) => current + String.Format(t, p[0], p[1], p[2], p[3], p[4]));

                                    resp = resp.Replace("PiPs", pip.Trim(','));

                                    o = oc;
                                }
                                break;
                        }

                        if (o != null)
                        {
                            template = "{{\"text\":\"{0}\",\"value\":{1}}},";
                            var ds = MainForm.Conf.MediaDirectories.Aggregate("", (current, cfg) => current + string.Format(template, cfg.Entry.JsonSafe(), cfg.ID));
                            resp = resp.Replace("DIRECTORIES", ds.Trim(','));

                            resp = resp.Replace("OBJECTID", oid.ToString(CultureInfo.InvariantCulture));
                            dynamic d = PopulateResponse(resp, o);
                            resp = JsonConvert.SerializeObject(d);
                        }
                    }
                    break;
                case "record":
                    io?.RecordSwitch(true);
                    resp = commandExecuted;
                    break;
                case "recordstop":
                    io?.RecordSwitch(false);
                    resp = commandExecuted;
                    break;
                case "snapshot":
                    cw = io as CameraWindow;
                    cw?.SaveFrame();
                    resp = commandExecuted;
                    break;
                case "getptzcommands":
                    ptzid = Convert.ToInt32(GetVar(sPhysicalFilePath, "ptzid"));
                    string cmdlist = "";
                    t = "{{\"name\":\"{0}\",\"value\":\"{1}\"}},";
                    switch (ptzid)
                    {
                        default:
                            PTZSettings2Camera ptz = MainForm.PTZs.SingleOrDefault(p => p.id == ptzid);
                            if (ptz?.ExtendedCommands?.Command != null)
                            {
                                cmdlist = ptz.ExtendedCommands.Command.Aggregate("",
                                    (current, extcmd) =>
                                        current +
                                        (string.Format(t, extcmd.Name.JsonSafe(), extcmd.Value.JsonSafe())));
                            }
                            break;
                        case -2:
                        case -1: //digital (none)
                        case -6: //(none)
                            break;
                        case -3:
                        case -4:
                            cmdlist = PTZController.PelcoCommands.Aggregate(cmdlist,
                                                                            (current, c) =>
                                                                            current +
                                                                            (string.Format(t, c.JsonSafe(), c.JsonSafe())));
                            break;
                        case -5:
                            cw = io as CameraWindow;
                            if (cw?.PTZ?.ONVIFPresets.Length > 0)
                            {
                                cmdlist = cw.PTZ.ONVIFPresets.Aggregate(cmdlist,
                                    (current, c) =>
                                        current +
                                        (string.Format(t, c.JsonSafe(), c.JsonSafe())));
                            }
                            break;
                    }
                    resp = "{\"elements\":[" + cmdlist.Trim(',') + "]}";
                    break;
                case "switchoff":
                    io?.Disable();

                    resp = commandExecuted;
                    break;
                case "switchon":
                    io?.Enable();

                    resp = commandExecuted;
                    break;
                case "getobjectstatus":
                    {
                        t =
                            "{{\"online\":{0},\"recording\":{1},\"width\":{2},\"height\":{3},\"micpairid\":{4},\"talk\":{5}}}";

                        vl = io as VolumeLevel;
                        if (vl != null)
                        {
                            resp = String.Format(t, vl.IsEnabled.ToString().ToLower(),
                                vl.ForcedRecording.ToString().ToLower(), 320, 40, -1, "false");
                        }
                        cw = io as CameraWindow;
                        if (cw != null)
                        {

                            string[] res = cw.Camobject.resolution.Split('x');
                            string micpairid = "-1";
                            if (cw.VolumeControl != null)
                                micpairid = cw.VolumeControl.Micobject.id.ToString(CultureInfo.InvariantCulture);

                            resp = String.Format(t, cw.IsEnabled.ToString().ToLower(),
                                cw.ForcedRecording.ToString().ToLower(), res[0], res[1], micpairid, (cw.Camobject.settings.audiomodel != "None").ToString().ToLower());
                        }
                    }
                    break;
                case "synthtocam":
                    {
                        var txt = GetVar(sPhysicalFilePath, "text");
                        cw = io as CameraWindow;
                        if (cw != null)
                        {
                            Sources.Audio.SpeechSynth.Say(txt, cw);
                        }
                        resp = commandExecuted;
                    }
                    break;
                case "getcameragrabs":
                    {
                        sd = GetVar(sPhysicalFilePath, "startdate");
                        ed = GetVar(sPhysicalFilePath, "enddate");
                        int pagesize = Convert.ToInt32(GetVar(sPhysicalFilePath, "pagesize"));
                        var page = Convert.ToInt32(GetVar(sPhysicalFilePath, "page"));
                        if (sd != "")
                            sdl = Convert.ToInt64(sd);
                        if (ed != "")
                            edl = Convert.ToInt64(ed);

                        var grablist = new StringBuilder("");
                        var ocgrab = MainForm.Cameras.FirstOrDefault(p => p.id == oid);
                        if (ocgrab != null)
                        {
                            var dirinfo = new DirectoryInfo(Helper.GetMediaDirectory(2, oid) + "video\\" +
                                                            ocgrab.directory + "\\grabs\\");

                            var lFi = new List<FileInfo>();
                            lFi.AddRange(dirinfo.GetFiles());
                            lFi =
                                lFi.FindAll(
                                    f =>
                                    f.Extension.ToLower() == ".jpg" && (sdl == 0 || f.CreationTime.Ticks > sdl) &&
                                    (edl == 0 || f.CreationTime.Ticks < edl));
                            lFi = lFi.OrderByDescending(f => f.CreationTime).ToList();



                            total = lFi.Count;
                            lFi = lFi.Skip(page * pagesize).Take(pagesize).ToList();

                            int max = 10000;
                            if (lFi.Count > 0)
                            {
                                foreach (var f in lFi)
                                {
                                    grablist.Append("{\"name\":\"" + f.Name + "\",\"time\":\"" + f.CreationTime.UnixTicks() + "\"},");
                                    max--;
                                    if (max == 0)
                                        break;
                                }
                            }
                        }
                        resp = "{\"total\":" + total + ",\"page\":" + page + ",\"pagesize\":" + pagesize + ",\"results\":[" +
                               grablist.ToString().Trim(',') + "]}";
                        break;
                    }
                case "getlogfilelist":
                    {
                        var dirinfo = new DirectoryInfo(Program.AppDataPath);
                        var lFi = new List<FileInfo>();
                        lFi.AddRange(dirinfo.GetFiles());
                        lFi = lFi.FindAll(f => f.Extension.ToLower() == ".htm" && f.Name.StartsWith("log_"));
                        lFi = lFi.OrderByDescending(f => f.CreationTime).ToList();
                        string logs = lFi.Aggregate("", (current, f) => current + ("{\"name\":\"" + f.Name + "\"},"));
                        resp = "{\"logs\":[" + logs.Trim(',') + "]}";
                    }
                    break;
                case "getcmdlist":
                {
                    var l = "";
                    t = "{{\"id\":{0},\"name\":\"{1}\"}},";
                    foreach (objectsCommand ocmd in MainForm.RemoteCommands)
                    {
                        string n = ocmd.name;
                        if (n.StartsWith("cmd_"))
                        {
                            n = LocRm.GetString(ocmd.name);
                        }

                        l += String.Format(t, ocmd.id, n.JsonSafe());
                    }
                    resp = "{\"commands\":[" + l.Trim(',') + "]}";
                }
                    break;
                case "executecmd":
                    {
                        objectsCommand oc = MainForm.RemoteCommands.SingleOrDefault(p => p.id == Convert.ToInt32(GetVar(sPhysicalFilePath, "id")));
                        resp = commandExecuted;
                        if (oc != null)
                        {
                            try
                            {
                                if (oc.command.StartsWith("ispy ") || oc.command.StartsWith("ispypro.exe "))
                                {
                                    string cmd2 =
                                        oc.command.Substring(oc.command.IndexOf(" ", StringComparison.Ordinal) + 1).Trim();

                                    int k = cmd2.ToLower().IndexOf("commands ", StringComparison.Ordinal);
                                    if (k != -1)
                                    {
                                        cmd2 = cmd2.Substring(k + 9);
                                    }
                                    cmd2 = cmd2.Trim('"');
                                    string[] commands = cmd2.Split('|');
                                    foreach (string command2 in commands)
                                    {
                                        if (!string.IsNullOrEmpty(command2))
                                        {
                                            MainForm.ProcessCommandInternal(command2.Trim('"'));
                                        }
                                    }
                                }
                                else
                                {
                                    Process.Start(oc.command);
                                }
                            }
                            catch (Exception ex)
                            {
                                Logger.LogExceptionToFile(ex, "Server");
                                resp = string.Format(commandFailed, ex.Message);
                            }
                        }
                    }
                    break;
                case "getgraph":
                {
                    FilesFile ff = null;
                    t = "{{\"duration\":{0},\"threshold\":{1},\"raw\":[{2}]}}";

                    vl = io as VolumeLevel;
                    string fn = GetVar(sPhysicalFilePath, "fn");
                    if (vl != null)
                    {
                        ff = vl.FileList.FirstOrDefault(p => p.Filename == fn);
                    }
                    cw = io as CameraWindow;
                    if (cw != null)
                    {
                        ff = cw.FileList.FirstOrDefault(p => p.Filename == fn);
                    }


                    if (ff != null)
                    {
                        resp = string.Format(t, ff.DurationSeconds,
                            string.Format(CultureInfo.InvariantCulture, "{0:0.000}", ff.TriggerLevel), ff.AlertData);
                    }
                    else
                    {
                        resp = string.Format(t, 0, 0, "");
                    }
                }
                    break;
                case "ptzcommand":
                    cw = io as CameraWindow;
                    if (cw != null)
                    {
                        var value = GetVar(sPhysicalFilePath, "value");
                        if (value != "")
                        {
                            try
                            {
                                if (value.StartsWith("ispydir_"))
                                {
                                    cw.PTZ.SendPTZCommand(
                                        (Enums.PtzCommand)Convert.ToInt32(value.Replace("ispydir_", "")));
                                }
                                else
                                    cw.PTZ.SendPTZCommand(value);
                            }
                            catch (Exception ex)
                            {
                                Logger.LogErrorToFile(LocRm.GetString("Validate_Camera_PTZIPOnly") + ": " +
                                                      ex.Message, "Server");
                            }
                        }
                        resp = commandExecuted;
                    }
                    break;
                case "getevents":
                {
                        string num = GetVar(sPhysicalFilePath, "num");
                        if (num == "")
                            num = "500";
                        int n = Convert.ToInt32(num);

                        DateTime timestamp = Helper.Now;
                        
                        sd = GetVar(sPhysicalFilePath, "startdate");
                        ed = GetVar(sPhysicalFilePath, "enddate");

                        sdl = sd != "" ? Convert.ToInt64(sd) : 0;
                        edl = ed != "" ? Convert.ToInt64(ed) : long.MaxValue;


                        List<FilePreview> ffs = MainForm.MasterFileList.OrderByDescending(p => p.CreatedDateTicksUTC).ToList();

                        if (sdl > 0)
                            ffs = ffs.FindAll(f => f.CreatedDateTicksUTC > sdl);

                        if (edl < long.MaxValue)
                            ffs = ffs.FindAll(f => f.CreatedDateTicksUTC < edl);
                            
                        ffs = ffs.Take(n).ToList();
                        var sb = new StringBuilder();
                        sb.Append("[");
                        foreach (var f in ffs)
                        {
                            sb.Append("{\"ot\":");
                            sb.Append(f.ObjectTypeId);
                            sb.Append(",\"oid\":");
                            sb.Append(f.ObjectId);
                            sb.Append(",\"created\":");
                            sb.Append(String.Format(CultureInfo.InvariantCulture, "{0:0.00}", f.CreatedDateTicksUTC));
                            sb.Append(",\"maxalarm\":");
                            sb.Append(String.Format(CultureInfo.InvariantCulture, "{0:0.0}",f.MaxAlarm));
                            sb.Append(",\"duration\": ");
                            sb.Append(f.Duration);
                            sb.Append(",\"filename\":\"");
                            sb.Append(f.Filename);
                            sb.Append("\"},");
                        }
                        resp = sb.ToString().Trim(',') + "]";

                        var tzo = Convert.ToInt32(System.TimeZone.CurrentTimeZone.GetUtcOffset(new DateTime()).TotalMinutes);
                        resp = "{\"timeStamp\":" + timestamp.Ticks + ",\"timezoneOffset\":"+tzo+",\"events\": " + resp + "}";
                    }
                    break;
                //post commands
                case "uploadyoutube":
                    {
                        var d = getJSONObject(sBuffer);
                        t = YouTubeUploader.Upload(oid, Helper.GetFullPath(ot, oid) + d.files[0].name, out success);
                        resp = "{\"action\":\"" + cmd + "\",\"status\":\"" + (success ? "ok" : "Upload Failed ("+t.JsonSafe()+")") + "\"}";
                    }
                    break;
                case "uploadcloud":
                    {
                        var d = getJSONObject(sBuffer);
                        t = CloudGateway.Upload(ot, oid, Helper.GetFullPath(ot, oid) + d.files[0].name, out success);
                        resp = "{\"action\":\"" + cmd + "\",\"status\":\"" + (success ? "ok" : "Upload Failed (" + t.JsonSafe() + ")") + "\"}";
                    }
                    break;
                case "massdelete":
                    {
                        var d = getJSONObject(sBuffer);
                        var files = new List<string>();
                        foreach (var file in d.files)
                        {
                            files.Add(file.name.ToString());
                        }

                        DeleteFiles(oid,ot, files);

                        resp = "{\"action\":\"" + cmd + "\",\"status\":\"ok\"}";
                    }
                    break;
                case "massdeletegrabs":
                    {
                        var d = getJSONObject(sBuffer);
                        var files = new List<string>();
                        foreach (var file in d.files)
                        {
                            files.Add(file.name.ToString());
                        }
                        var folderpath = Helper.GetMediaDirectory(ot, oid) + "video\\" + Helper.GetDirectory(ot, oid) + "\\grabs\\";

                        foreach (string file in files)
                        {
                            FileOperations.Delete(folderpath + file);
                        }

                        resp = "{\"action\":\"" + cmd + "\",\"status\":\"ok\"}";
                    }

                    break;

                case "archive":
                    {
                        success = false;
                        if (io == null)
                        {
                            t = "Object not found";
                        }
                        else
                        {
                            if (Helper.CanArchive)
                            {
                                var d = getJSONObject(sBuffer);
                                string dir = "audio";
                                if (ot == 2)
                                    dir = "video";

                                var folderpath = Helper.GetMediaDirectory(ot, oid) + dir + "\\" +
                                                 Helper.GetDirectory(ot, oid) + "\\";
                                success = true;
                                var files = new List<string>();
                                foreach (var file in d.files)
                                {
                                    success = Helper.ArchiveFile(folderpath + file.name.ToString());
                                    if (!success)
                                    {
                                        t = "Archive Failed";
                                        break;
                                    }
                                    else
                                        files.Add(file.name.ToString());
                                }

                                if (files.Count>0)
                                {
                                    DeleteFiles(oid,ot, files);
                                }

                            }
                            else
                            {
                                
                                t = "Invalid archive directory in settings";
                            }
                        }
                        resp = "{\"action\":\"" + cmd + "\",\"status\":\"" + (success ? "ok" : t) + "\"}";
                    }
                    break;
                default:
                    return;
            }

            SendHeader(sHttpVersion, "application/json", resp.Length, " 200 OK", 0, ref req);

            SendToBrowser(resp, req);
        }
Esempio n. 13
0
 public BatchItem(DeviceDescriptionHolder dev)
 {
     Device = dev;
 }
Esempio n. 14
0
 public static Func <Action <TResult>, Action <Exception>, IBackgroundTask> CreateForAsync <TResult>(FSharpAsync <TResult> async, DeviceDescriptionHolder dev)
 {
     return((onSuccess, onError) => {
         var disp = new MultipleAssignmentDisposable();
         var backgroundTask = new AnonymousBackgroundTask();
         backgroundTask.name = "Restore device " + dev.Name;
         backgroundTask.description = "Address: " + dev.Address;
         backgroundTask.state = BackgroundTaskState.InProgress;
         backgroundTask.disposable = Disposable.Create(() => {
             disp.Dispose();
             backgroundTask.state = BackgroundTaskState.Canceled;
         });
         disp.Disposable = async.Subscribe(
             res => {
             onSuccess(res);
             backgroundTask.state = BackgroundTaskState.Completed;
         },
             err => {
             onError(err);
             backgroundTask.state = BackgroundTaskState.Failed;
         }
             );
         return backgroundTask;
     });
 }
Esempio n. 15
0
        void ManualDelete(DeviceDescriptionHolder dhold)
        {
            Devices.Remove(dhold);

            SaveManualList();
        }