Beispiel #1
0
        public string GetFilePath(string fileExt)
        {
            SMCollection collection = Core.SM.Collection;

            return(GetFilePathForSlotId(
                       collection,
                       SlotIdOrOffset,
                       fileExt
                       ));

            /*
             * switch (LinkType)
             * {
             * case RegistryLinkType.File:
             * case RegistryLinkType.FileAndRtx:
             *  SMCollection collection = SMA.Instance.Collection;
             *
             *  return GetFilePathForSlotId(
             *    collection,
             *    SlotIdOrOffset,
             *    fileExt
             *  );
             *
             * default:
             *  return null;
             * }*/
        }
Beispiel #2
0
        public CollectionConfigurationService(SMCollection collection, ISMAPlugin plugin)
        {
            _collection = collection;
            _subDir     = plugin.AssemblyName;

            EnsureFolderExists();
        }
Beispiel #3
0
        private async Task LoadConfig(SMCollection collection)
        {
            Core.CollectionConfiguration = new CollectionConfigurationService(collection, "Core");

            // CollectionsCfg
            CollectionConfig = await Core.CollectionConfiguration.Load <CollectionCfg>() ?? new CollectionCfg();
        }
Beispiel #4
0
        private async Task LoadConfigAsync(SMCollection collection)
        {
            Core.CollectionConfiguration = new CollectionConfigurationService(collection, "Core");

            // CollectionsCfg
            CollectionConfig = await Core.CollectionConfiguration.LoadAsync <CollectionCfg>().ConfigureAwait(false) ?? new CollectionCfg();
        }
Beispiel #5
0
        public CollectionConfigurationService(SMCollection collection, string subDir)
        {
            _collection = collection;
            _subDir     = subDir;

            EnsureFolderExists();
        }
Beispiel #6
0
        public static string GetFilePathForSlotId(
            SMCollection collection,
            int slotId,
            string slotFileExt)
        {
            if (slotId <= 10)
            {
                return(collection.GetElementFilePath($"{slotId}.{slotFileExt}"));
            }

            List <int> folders = new List <int>();
            int        nBranch = (int)Math.Floor((slotId - 1) / 10.0);

            do
            {
                folders.Add((nBranch - 1) % 30 + 1);

                nBranch = (int)Math.Floor((nBranch - 1) / 30.0);
            } while (nBranch > 0);

            folders.Reverse();
            var folderPath = string.Join("\\", folders);

            return(collection.GetElementFilePath(
                       Path.Combine(
                           folderPath,
                           $"{slotId}.{slotFileExt}"
                           )
                       ));
        }
 public static string GetInfoFilePath(
     this SMCollection collection,
     string fileName)
 {
     return(collection.GetFilePath(SMConst.Paths.InfoFolder,
                                   fileName));
 }
 public static string GetRtfFilePath(
     this SMCollection collection,
     IRegistryFileDescriptor fileDesc)
 {
     return(collection.GetFilePath(SMConst.Paths.RegistryFolder,
                                   fileDesc.RtfFileName));
 }
Beispiel #9
0
        //
        // Core hook methods

        public IProcess CreateAndHook(
            SMCollection collection,
            ISMHookSystem systemCallback,
            IEnumerable <ISMHookIO> ioCallbacks)
        {
            try
            {
                SystemCallback = systemCallback;
                IOCallbacks.AddRange(ioCallbacks);

                IOTargetFilePaths.AddRange(IOCallbacks.SelectMany(c => c.GetTargetFilePaths()));

                // Initialize event to non-Signaled
                HookInitEvent = new AutoResetEvent(false);
                SMAInitEvent  = new AutoResetEvent(false);

                HookSuccess   = false;
                HookException = null;

                // Start a new IPC server
                StartIPCServer();

                // Start SuperMemo application with given collection as parameter,
                // and immediatly install hooks
                RemoteHooking.CreateAndInject(
                    SMConst.BinPath,
                    collection.GetKnoFilePath().Quotify(),
                    0,
                    InjectionOptions.Default,
                    SMAConst.Assembly.GetInjectionLibFilePath(),
                    null,
                    out var pId
                    );

                // Wait for Signal from OnHookInstalled with timeout
                HookInitEvent.WaitOne(WaitTimeout);

                if (HookSuccess == false)
                {
                    StopIPCServer();

                    var ex = new HookException("Hook setup failed: " + HookException?.Message,
                                               HookException);
                    HookException = null;

                    throw ex;
                }

                return(new ProcessSharp <SM17Natives>(
                           pId,
                           Process.NET.Memory.MemoryType.Remote,
                           true,
                           SMA.Instance.Config.PatternsHintAddresses));
            }
            finally
            {
                HookInitEvent = null;
            }
        }
Beispiel #10
0
        //
        // Collection loading management

        public async Task <bool> Start(
            NativeDataCfg nativeDataCfg,
            StartupCfg startupCfg,
            SMCollection collection)
        {
            try
            {
                if (_sm != null)
                {
                    throw new InvalidOperationException("_sm is already instantiated");
                }

                await LoadConfig(collection, startupCfg);

                var nativeData = CheckSuperMemoExecutable(nativeDataCfg);

                _sm = InstantiateSuperMemo(collection, nativeData.SMVersion);

                // TODO: Move somewhere else
                _sm.UI.ElementWdw.OnAvailable += OnSuperMemoWindowsAvailable;

                await _sm.Start(nativeData);

                // TODO: Ensure opened collection (windows title) matches parameter
            }
            catch (Exception ex)
            {
                if (ex is SMAException)
                {
                    LogTo.Warning(ex, "Failed to start SM.");
                }

                else
                {
                    LogTo.Error(ex, "Failed to start SM.");
                }

                _sm?.Dispose();
                _sm = null;

                try
                {
                    if (OnSMStoppedEvent != null)
                    {
                        await OnSMStoppedEvent.InvokeAsync(this, new SMProcessArgs(_sm, null)).ConfigureAwait(true);
                    }
                }
                catch (Exception pluginEx)
                {
                    LogTo.Error(pluginEx, "Exception while notifying plugins OnSMStoppedEvent.");
                }

                // TODO: Handle exception

                return(false);
            }

            return(true);
        }
 private void DeleteCollection(SMCollection collection)
 {
     if (Forge.Forms.Show.Window().For(new Confirmation("Are you sure ?")).Result.Model.Confirmed)
     {
         SavedCollections.Remove(collection);
         SaveConfig();
     }
 }
        //
        // Core hook methods

        public async Task <IProcess> CreateAndHook(
            SMCollection collection,
            string binPath,
            ISMAHookSystem systemCallback,
            IEnumerable <ISMAHookIO> ioCallbacks)
        {
            LogTo.Debug("Starting and injecting SuperMemo");

            SystemCallback = systemCallback;
            IOCallbacks.AddRange(ioCallbacks);

            IOTargetFilePaths.AddRange(IOCallbacks.SelectMany(c => c.GetTargetFilePaths()));

            HookSuccess   = false;
            HookException = null;

            // Start a new IPC server
            var channelName = StartIPCServer();

            // Start SuperMemo application with given collection as parameter,
            // and immediatly install hooks
            RemoteHooking.CreateAndInject(
                binPath,
                collection.GetKnoFilePath().Quotify(),
                0,
                InjectionOptions.Default,
                SMAFileSystem.InjectionLibFile.FullPath,
                null,
                out var pId,
                channelName
                );

            LogTo.Debug("Waiting for signal from Injected library");

            // Wait for Signal from OnHookInstalled with timeout
            await HookInitEvent.WaitAsync(WaitTimeout);

            if (HookSuccess == false)
            {
                LogTo.Debug("Hook failed, aborting");

                StopIPCServer();

                var ex = new HookException("Hook setup failed: " + HookException?.Message,
                                           HookException);
                HookException = null;

                throw ex;
            }

            LogTo.Debug($"SuperMemo started and injected, pId: {pId}");

            return(new ProcessSharp <SM17Natives>(
                       pId,
                       Process.NET.Memory.MemoryType.Remote,
                       true,
                       SMA.SMA.Instance.StartupConfig.PatternsHintAddresses));
        }
Beispiel #13
0
        private static SuperMemoCore GetSuperMemoFactory(SMCollection collection, Version smVersion)
        {
            if (SM17.Versions.Contains(smVersion))
            {
                return(new SM17(collection, CoreConfig.SuperMemo.SMBinPath));
            }

            throw new SMAException($"Unsupported SM version {smVersion}");
        }
Beispiel #14
0
        /// <inheritdoc />
        protected SuperMemoCore(SMCollection collection, string binPath)
            : base(collection, binPath)
        {
            Core.SM = this;

            _registry = new SuperMemoRegistryCore();
            _ui       = new SuperMemoUICore();
            Hook      = new SMHookEngine();
        }
Beispiel #15
0
        private SuperMemoCore InstantiateSuperMemo(SMCollection collection,
                                                   Version smVersion)
        {
            if (SM17.Versions.Contains(smVersion))
            {
                return(new SM17(collection, StartupConfig.SMBinPath));
            }

            throw new SMAException($"Unsupported SM version {smVersion}");
        }
Beispiel #16
0
        /// <inheritdoc />
        protected override void OnCollectionSelected(SMCollection col)
        {
            base.OnCollectionSelected(col);

            ImportConfig = Svc.CollectionConfiguration.Load <ImportCollectionCfg>() ?? new ImportCollectionCfg();

            _importService = new ImportPluginService();

            CreateBrowserRegistryKeys();

            PublishService <IImportPluginService, ImportPluginService>(_importService, ImportConst.ChannelName);
        }
Beispiel #17
0
        //
        // Collection loading management

        public async Task <Exception> StartAsync(
            NativeDataCfg nativeDataCfg,
            SMCollection collection)
        {
            try
            {
                if (_sm != null)
                {
                    throw new InvalidOperationException("_sm is already instantiated");
                }

                // Load collection config
                await LoadConfigAsync(collection).ConfigureAwait(false);

                // Make sure the SuperMemo version is compatible and instantiate it
                var nativeData = CheckSuperMemoExecutable(nativeDataCfg);

                _sm = GetSuperMemoFactory(collection, nativeData.SMVersion);

                // Notify Plugins of selected collection
                await OnCollectionSelectedAsync(collection).ConfigureAwait(false);

                await _sm.StartAsync(nativeData).ConfigureAwait(false);

                // TODO: Ensure opened collection (windows title) matches parameter
            }
            catch (Exception ex)
            {
                if (ex is SMAException)
                {
                    LogTo.Warning(ex, "Failed to start SM.");
                }

                else
                {
                    LogTo.Error(ex, "Failed to start SM.");
                }

                _sm?.Dispose();
                _sm = null;

                // TODO: Handle exception

                return(ex);
            }

            return(null);
        }
Beispiel #18
0
        private async Task DeleteCollectionAsync(SMCollection collection)
        {
            var res = await Forge.Forms.Show.Window().For(new Confirmation("Are you sure ?")).ConfigureAwait(true);

            if (res.Model.Confirmed)
            {
                // ObservableHashSet does not have index, which results in an exception when notifying for removal
                var tmpCollections = SavedCollections;
                SavedCollections = null;

                tmpCollections.Remove(collection);
                SaveConfig();

                SavedCollections = tmpCollections;
            }
        }
Beispiel #19
0
        //
        // Collection loading management

        public async Task <Exception> Start(
            NativeDataCfg nativeDataCfg,
            SMCollection collection)
        {
            try
            {
                if (_sm != null)
                {
                    throw new InvalidOperationException("_sm is already instantiated");
                }

                await LoadConfig(collection);

                var nativeData = CheckSuperMemoExecutable(nativeDataCfg);

                _sm = InstantiateSuperMemo(collection, nativeData.SMVersion);

                // TODO: Move somewhere else
                _sm.UI.ElementWdw.OnAvailable += OnSuperMemoWindowsAvailable;

                await _sm.Start(nativeData);

                // TODO: Ensure opened collection (windows title) matches parameter
            }
            catch (Exception ex)
            {
                if (ex is SMAException)
                {
                    LogTo.Warning(ex, "Failed to start SM.");
                }

                else
                {
                    LogTo.Error(ex, "Failed to start SM.");
                }

                _sm?.Dispose();
                _sm = null;

                // TODO: Handle exception

                return(ex);
            }

            return(null);
        }
        protected SuperMemoBase(SMCollection collection)
        {
            Collection = collection;

            OnPreInit();

            SMProcess = SMHookEngine.Instance.CreateAndHook(
                collection,
                this,
                GetIOCallbacks()
                );

            SMProcess.Native.Exited += OnSMExited;

            OnPostInit();

            SMHookEngine.Instance.SignalWakeUp();
        }
Beispiel #21
0
        private void LoadConfig(SMCollection collection)
        {
            var knoPath = collection.GetKnoFilePath();

            // StartupCfg

            StartupConfig = Core.Configuration.Load <StartupCfg>().Result ?? new StartupCfg();

            // CollectionsCfg

            _collectionsCfg  = Core.Configuration.Load <CollectionsCfg>().Result ?? new CollectionsCfg();
            CollectionConfig = _collectionsCfg.CollectionsConfig.SafeGet(knoPath);

            if (CollectionConfig == null)
            {
                CollectionConfig = new CollectionCfg();
                _collectionsCfg.CollectionsConfig[knoPath] = CollectionConfig;
            }
        }
Beispiel #22
0
        public bool ValidateCollection(SMCollection collection)
        {
            if (collection.Exists() == false)
            {
                Forge.Forms.Show.Window().For(new Alert("Collection doesn't exist anymore.", "Error"));

                return(false);
            }

            // Check whether collection is locked
            if (collection.IsLocked())
            {
                Forge.Forms.Show.Window().For(new Alert("Collection is locked. Is SuperMemo already running ?", "Error"));

                return(false);
            }

            return(true);
        }
        public void CommitFromFiles(SMCollection collection,
                                    IRegistryFileDescriptor registryFileDesc)
        {
            var memFilePath = collection.GetMemFilePath(registryFileDesc);
            var rtxFilePath = collection.GetRtxFilePath(registryFileDesc);

            var memExists = File.Exists(memFilePath);
            var rtxExists = File.Exists(rtxFilePath);

            switch (registryFileDesc.IsOptional)
            {
            case true when rtxExists == false || memExists == false:
                return;

            case false when memExists == false:
                throw new InvalidOperationException($"({GetType().Name}) Failed to load registry file: no such file {memFilePath}");

            case false when rtxExists == false:
                throw new InvalidOperationException($"({GetType().Name}) Failed to load registry file: no such file {rtxFilePath}");
            }

            using (Stream memStream = File.OpenRead(memFilePath))
                using (Stream rtxStream = File.OpenRead(rtxFilePath))
                //using (Stream rtfStream = File.OpenRead(rtfFilePath))
                {
                    Dictionary <int, RegMemElem17> memElems = memStream.StreamToStruct <RegMemElem17, RegMemElem17>(
                        RegMemElem17.SizeOfMemElem,
                        e => e
                        );

                    foreach (var id in memElems.Keys.OrderBy(id => id))
                    {
                        var memElem = memElems[id];
                        var rtxElem = ParseRtStream(rtxStream, memElem);

                        Commit(id, memElem, rtxElem);
                    }
                }
        }
        public bool ValidateCollection(SMCollection collection)
        {
            var knoFilePath = new FilePath(collection.GetKnoFilePath());

            if (knoFilePath.Exists() == false ||
                Directory.Exists(collection.GetRootDirPath()) == false)
            {
                Forge.Forms.Show.Window().For(new Alert("Collection doesn't exist anymore.", "Error"));

                return(false);
            }

            // Check whether collection is locked
            if (knoFilePath.IsLocked())
            {
                Forge.Forms.Show.Window().For(new Alert("Collection is locked. Is SuperMemo already running ?", "Error"));

                return(false);
            }

            return(true);
        }
Beispiel #25
0
        public static (AppDomain domain, PluginHost runner) Create(SMCollection collection)
        {
            DirectoryEx.EnsureExists(SMAConst.Paths.AppDomainCachePath);
            DirectoryEx.EnsureExists(SMAConst.Paths.PluginPath);
            DirectoryEx.EnsureExists(collection.GetSMAFolder());
            DirectoryEx.EnsureExists(collection.GetSMAElementsFolder());
            DirectoryEx.EnsureExists(collection.GetSMAPluginsFolder());
            DirectoryEx.EnsureExists(collection.GetSMASystemFolder());

            var assemblyPaths = String.Join(";",
                                            GetAssemblyPaths());

            var setup = new AppDomainSetup()
            {
                ApplicationBase       = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                CachePath             = SMAConst.Paths.AppDomainCachePath,
                PrivateBinPath        = assemblyPaths,
                ShadowCopyFiles       = "true",
                ShadowCopyDirectories = assemblyPaths
            };

            var permissions = GetPermissions(collection);

            var domain = AppDomain.CreateDomain(
                AppDomainName,
                AppDomain.CurrentDomain.Evidence,
                setup,
                permissions
                );

            var runner = (PluginHost)domain.CreateInstanceAndUnwrap(
                typeof(PluginHost).Assembly.FullName,
                // ReSharper disable once AssignNullToNotNullAttribute
                typeof(PluginHost).FullName
                );

            return(domain, runner);
        }
Beispiel #26
0
        public async Task OnCollectionSelectedAsync(SMCollection collection)
        {
            try
            {
                _sm.UI.ElementWdw.OnAvailableInternal += OnSuperMemoWindowsAvailable;

                if (OnCollectionSelectedInternalEvent != null)
                {
                    await OnCollectionSelectedInternalEvent.InvokeAsync(this, new SMEventArgs(_sm)).ConfigureAwait(false);
                }

                OnCollectionSelectedEvent?.InvokeRemote(
                    nameof(OnCollectionSelectedAsync),
                    collection,
                    h => OnCollectionSelectedEvent -= h
                    );
            }
            catch (Exception ex)
            {
                LogTo.Error(ex, "Exception while notifying subscribers of OnCollectionSelected");
                throw;
            }
        }
Beispiel #27
0
        /// <inheritdoc />
        public void CommitFromFiles(SMCollection collection)
        {
            using (Stream cttStream = File.OpenRead(collection.GetInfoFilePath(SMConst.Files.ContentsFileName)))
                using (Stream elStream = File.OpenRead(collection.GetInfoFilePath(SMConst.Files.ElementsInfoFileName)))
                {
                    var cttElems = cttStream.StreamToStruct <InfContentsElem17, InfContentsElem17>(
                        InfContentsElem17.SizeOfContentsElem,
                        s => s
                        );

                    var elElems = elStream.StreamToStruct <InfElementsElemContainer17, InfElementsElem17>(
                        InfElementsElem17.SizeOfElementsElem,
                        e => new InfElementsElemContainer17(e)
                        );

                    foreach (int id in cttElems.Keys.Union(elElems.Keys))
                    {
                        Commit(id,
                               cttElems.SafeGet(id),
                               elElems.SafeGet(id));
                    }
                }
        }
Beispiel #28
0
        private static PermissionSet GetPermissions(SMCollection collection)
        {
            // TODO: Switch back to restricted
            var permissions = new PermissionSet(PermissionState.Unrestricted);

            //permissions.SetPermission(new EnvironmentPermission(PermissionState.Unrestricted));
            //permissions.SetPermission(new UIPermission(PermissionState.Unrestricted));
            //permissions.SetPermission(new FileDialogPermission(PermissionState.Unrestricted));
            //permissions.SetPermission(new MediaPermission(PermissionState.Unrestricted));
            //permissions.SetPermission(new ReflectionPermission(PermissionState.Unrestricted));

            /*permissions.SetPermission(
             * new SecurityPermission(SecurityPermissionFlag.AllFlags));
             *  SecurityPermissionFlag.Execution | SecurityPermissionFlag.UnmanagedCode | SecurityPermissionFlag.BindingRedirects
             | SecurityPermissionFlag.Assertion | SecurityPermissionFlag.RemotingConfiguration | SecurityPermissionFlag.ControlThread));*/

            permissions.RemovePermission(typeof(FileIOPermission));
            permissions.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess,
                                                           Path.GetTempPath()));
            permissions.AddPermission(new FileIOPermission(
                                          FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read,
                                          Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles))
                                      );
            permissions.AddPermission(new FileIOPermission(
                                          FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read,
                                          Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFilesX86))
                                      );
            permissions.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess,
                                                           collection.GetSMAFolder()));
            permissions.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess,
                                                           SMAConst.Paths.AppDataPath));
            permissions.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess,
                                                           AppDomain.CurrentDomain.BaseDirectory));

            return(permissions);
        }
Beispiel #29
0
        private async Task LoadApp(SMAParameters args)
        {
            //
            // Installer events
            if (SMAInstaller.HandleEvent(args, out var firstRun))
            {
                if (firstRun)
                {
                    await "SuperMemo Assistant has been successfully installed.".MsgBox("Installation");
                }

                Shutdown();
                return;
            }

            //
            // Make sure assemblies are available, and SMA is installed in "%LocalAppData%\SuperMemoAssistant"
            if (AssemblyCheck.CheckRequired(out var errMsg) == false || CheckSMALocation(out errMsg) == false)
            {
                LogTo.Warning(errMsg);
                await errMsg.ErrorMsgBox();

                Shutdown(SMAExitCodes.ExitCodeDependencyError);
                return;
            }

            //
            // Load system configs
            if (await LoadConfigs(out var nativeDataCfg, out var startupCfg) == false)
            {
                errMsg =
                    $"At least one essential config file could not be loaded: nativeDataCfg ? {nativeDataCfg == null} ; startupCfg ? {startupCfg == null}";
                LogTo.Warning(errMsg);
                await errMsg.ErrorMsgBox();

                Shutdown(SMAExitCodes.ExitCodeConfigError);
                return;
            }

            //
            // Make sure SuperMemo exe path is correct. Prompt user to input the path otherwise.
            if (SMASetup.ShouldFindSuperMemo(startupCfg, nativeDataCfg))
            {
                var smFinder = new Setup.SuperMemoFinder(nativeDataCfg, startupCfg);
                smFinder.ShowDialog();

                if (smFinder.DialogResult == null || smFinder.DialogResult == false)
                {
                    LogTo.Warning(errMsg);

                    Shutdown(SMAExitCodes.ExitCodeSMExeError);
                    return;
                }
            }

            //
            // (Optional) Start the debug Key logger (logs key strokes with modifiers, e.g. ctrl, alt, ..)
            if (args.KeyLogger)
            {
                SMA.Core.KeyboardHotKey.MainCallback = hk => LogTo.Debug($"Key pressed: {hk}");
            }

            //
            // Determine which collection to open
            SMCollection smCollection = null;
            var          selectionWdw = new CollectionSelectionWindow(startupCfg);

            // Try to open command line collection, if one was passed
            if (args.CollectionKnoPath != null && selectionWdw.ValidateSuperMemoPath())
            {
                smCollection = new SMCollection(args.CollectionKnoPath, DateTime.Now);

                if (selectionWdw.ValidateCollection(smCollection) == false)
                {
                    smCollection = null;
                }
            }

            // No valid collection passed, show selection window
            if (smCollection == null)
            {
                selectionWdw.ShowDialog();

                smCollection = selectionWdw.Collection;
            }

            //
            // If a collection was defined, start SMA
            if (smCollection != null)
            {
                SMA.Core.SMA.OnSMStoppedEvent += OnSMStoppedEvent;

                if (await SMA.Core.SMA.Start(nativeDataCfg, startupCfg, smCollection).ConfigureAwait(true) == false)
                {
                    await $"SMA failed to start. Please check the logs in '{SMAFileSystem.LogDir.FullPath}' for details.".ErrorMsgBox();
                    Shutdown(SMAExitCodes.ExitCodeSMAStartupError);

                    return;
                }

                if (SMAExecutableInfo.Instance.IsDev == false)
                {
                    await SMAInstaller.Instance.Update();
                }
            }
            else
            {
                Shutdown();
            }
        }
Beispiel #30
0
 protected SuperMemoBase(SMCollection collection,
                         string binPath)
 {
     Collection = collection;
     _binPath   = binPath;
 }