///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ОписаниеПеременных

&НаКлиенте
Перем ВходящиеКонтексты;

#КонецОбласти

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ТолькоУстановкаТокенов = Параметры.ТолькоУстановкаТокенов;
	Если ТолькоУстановкаТокенов Тогда
		Элементы.Приложения.Видимость = Ложь;
		ТекстПояснения = Элементы.ДекорацияЗаголовок.Заголовок;
		Элементы.ДекорацияЗаголовок.Заголовок = СтрЗаменить(ТекстПояснения, НСтр("ru = 'или одно из приложений для установки '"), "");
	КонецЕсли;
	Разрядность = "x86-64";
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	ПодключитьОбработчикОжидания("ЗапуститьДиагностикуТокенов", 0.1, Истина);
	Если Не ТолькоУстановкаТокенов Тогда
		ПроверитьВозможностьУстановкиПрограммКриптографии();
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийЭлементовШапкиФормы

&НаКлиенте
Процедура ТокеныВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
	ОписаниеТокена = Элементы.Токены.ТекущиеДанные.Токен;
	ЭлектроннаяПодписьСлужебныйКлиент.ОткрытьТокен(ОписаниеТокена, ЭтотОбъект);
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура УстановитьVipNet(Команда)
	
	ОповещениеОЗавершении = Новый ОписаниеОповещения("ПовторнаяПроверкаПрограммКриптографии", ЭтотОбъект);
	
	ВходящийКонтекст = Неопределено;
	Если ТипЗнч(ВходящиеКонтексты) = Тип("Соответствие") Тогда
		ВходящийКонтекст = ВходящиеКонтексты.Получить(ЭлектроннаяПодписьКлиентСерверЛокализация.ИмяПрограммыVipNet());
	КонецЕсли;
	
	ЭлектроннаяПодписьКлиентЛокализация.УстановитьVipNet(ЭтотОбъект, ОповещениеОЗавершении, ВходящийКонтекст);
	
КонецПроцедуры

&НаКлиенте
Процедура УстановитьКриптоПро(Команда)
	
	ВходящийКонтекст = Неопределено;
	Если ТипЗнч(ВходящиеКонтексты) = Тип("Соответствие") Тогда
		ВходящийКонтекст = ВходящиеКонтексты.Получить(ЭлектроннаяПодписьКлиентСерверЛокализация.ИмяПрограммыКриптоПро());
	КонецЕсли;
	
	ОповещениеОЗавершении = Новый ОписаниеОповещения("ПовторнаяПроверкаПрограммКриптографии", ЭтотОбъект);
	ЭлектроннаяПодписьКлиентЛокализация.УстановитьКриптоПро(ЭтотОбъект, ОповещениеОЗавершении, ВходящийКонтекст);
	
КонецПроцедуры

&НаКлиенте
Процедура УстановитьSignalCOM(Команда)
	
	ЭлектроннаяПодписьКлиентЛокализация.УстановитьSignalCOM();
	
КонецПроцедуры

&НаКлиенте
Процедура УстановитьДругоеПриложение(Команда)
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку("https://v8.1c.ru/platforma/kriptografiya/");
КонецПроцедуры

&НаКлиенте
Процедура УстановитьДляРутокена(Команда)
	
	УстановитьБиблиотеку(Истина);
	
КонецПроцедуры

&НаКлиенте
Процедура УстановитьДляДжакарта(Команда)
	
	УстановитьБиблиотеку(Ложь);
	
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьИнформациюОТокенах(Команда)
	ЗапуститьДиагностикуТокенов()
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

&НаКлиенте
Процедура ПроверитьВозможностьУстановкиПрограммКриптографии()
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	
	Если ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
		
		ДоступенVipNet = ДоступенВОСWindowsДляУстановкиVipNet(СистемнаяИнформация.ВерсияОС);
		Если Не ДоступенVipNet Тогда
			Элементы.УстановитьVipNet.Доступность = Ложь;
			Элементы.ДекорацияНедоступноДляУстановкиVipNet.Видимость = Истина;
			Элементы.ДекорацияНедоступноДляУстановкиVipNet.Подсказка = 
				НСтр("ru = 'Версия вашей операционной системы Microsoft Windows ниже минимально рекомендуемой для работы с данным приложением.'");
		КонецЕсли;
		
		ДоступенSignalCOM = ДоступенВОСWindowsДляУстановкиSignalCOM(СистемнаяИнформация.ВерсияОС);
		Если Не ДоступенSignalCOM Тогда
			Элементы.УстановитьSignalCOM.Доступность = Ложь;
			Элементы.ДекорацияНедоступноДляУстановкиSignalCOM.Видимость = Истина;
			Элементы.ДекорацияНедоступноДляУстановкиSignalCOM.Подсказка = 
				НСтр("ru = 'Версия вашей операционной системы Microsoft Windows ниже минимально рекомендуемой для работы с данным приложением.'");
		КонецЕсли;
		
	ИначеЕсли ОбщегоНазначенияКлиент.ЭтоLinuxКлиент()
		Или ОбщегоНазначенияКлиент.ЭтоMacOSКлиент() Тогда
		
		Элементы.ГруппаУстановитьVipNet.Видимость = Ложь;
		Элементы.УстановитьSignalCOM.Видимость = Ложь;
		Элементы.УстановитьДругое.Видимость = Ложь;
		
	Иначе
		Элементы.Приложения.Доступность = Ложь;
		ПоказатьПредупреждение(, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Работа с программами криптографии в ОС %1 недоступна.'"), СистемнаяИнформация.ВерсияОС));
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Функция ДоступенВОСWindowsДляУстановкиVipNet(ВерсияОС)
	
	Возврат Не (СтрНайти(ВерсияОС, "Windows 7") <> 0
		Или СтрНайти(ВерсияОС, "Windows Vista") <> 0
		Или СтрНайти(ВерсияОС, "Windows XP") <> 0
		Или СтрНайти(ВерсияОС, "Windows 2000") <> 0);
	
КонецФункции

&НаКлиенте
Функция ДоступенВОСWindowsДляУстановкиSignalCOM(ВерсияОС)
	
	Возврат Не СтрНайти(ВерсияОС, "Windows 2000") <> 0;
	
КонецФункции

&НаКлиенте
Асинх Процедура ПовторнаяПроверкаПрограммКриптографии(Результат, ДополнительныеПараметры) Экспорт
	
	Если Не ТипЗнч(Результат) = Тип("Структура") Тогда
		Возврат;
	КонецЕсли;
	
	Если Результат.Выполнено = Истина Тогда
		
		ОбновитьПовторноИспользуемыеЗначения();
		
		Ответ = Ждать ВопросАсинх(
			НСтр("ru = 'Для работы с только что установленным криптопровайдером перезапустите сеанс. Перезапустить сейчас?'"),
			РежимДиалогаВопрос.ДаНет,, КодВозвратаДиалога.Нет, НСтр("ru = 'После установки криптопровайдера'"));
		
		Если Ответ = КодВозвратаДиалога.Да Тогда
			ПараметрыПриложения.Вставить("СтандартныеПодсистемы.ПропуститьПредупреждениеПередЗавершениемРаботыСистемы", Истина);
			ЗавершитьРаботуСистемы(Истина, Истина);
			Возврат;
		Иначе
			Оповестить("Установка_ПриложениеКриптографии", Истина);
		КонецЕсли;
		
		Закрыть();
		Возврат;
		
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Результат, "ВходящийКонтекст", Неопределено) <> Неопределено Тогда
		Если ВходящиеКонтексты = Неопределено Тогда
			ВходящиеКонтексты = Новый Соответствие;
		КонецЕсли;
		ВходящиеКонтексты.Вставить(Результат.ВходящийКонтекст.ИмяПрограммы, Результат.ВходящийКонтекст);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда
		ПоказатьПредупреждение(, УстановитьГиперссылку(Результат.ОписаниеОшибки));
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Функция УстановитьГиперссылку(Строка)
	
	МассивСсылок = Новый Массив;
	МассивСсылок.Добавить(Новый Структура("Текст, Гиперссылка", "www.infotecs.ru", "https://infotecs.ru/"));
	МассивСсылок.Добавить(Новый Структура("Текст, Гиперссылка", "www.cryptopro.ru", "https://cryptopro.ru/"));
	
	Для Каждого ТекущаяСсылка Из МассивСсылок Цикл
		Позиция = СтрНайти(Строка, ТекущаяСсылка.Текст);
		Если Позиция = 0 Тогда
			Продолжить;
		КонецЕсли;

		СтрокаСоСсылкой = Новый ФорматированнаяСтрока(ТекущаяСсылка.Текст, , , , ТекущаяСсылка.Гиперссылка);

		Возврат Новый ФорматированнаяСтрока(Лев(Строка, Позиция - 1), СтрокаСоСсылкой, Сред(Строка, Позиция + СтрДлина(
			ТекущаяСсылка.Текст)));
	КонецЦикла;
	
	Возврат Новый ФорматированнаяСтрока(Строка);
	
КонецФункции

&НаКлиенте
Процедура УстановитьБиблиотеку(ДляРутокена)
	
	Элементы.УстановитьДляРутокена.Доступность = Ложь;
	Элементы.УстановитьДляДжакарта.Доступность = Ложь;
	Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Ложь;
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	
	ПараметрыУстановкиБиблиотек = Новый Структура;
	
	Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86 
		Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64 Тогда
			
		Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 И Разрядность = "x86-64" Тогда
			ПараметрыУстановкиБиблиотек.Вставить("ТипПлатформы", "Windows_x86_64");
		Иначе
			ПараметрыУстановкиБиблиотек.Вставить("ТипПлатформы", ОбщегоНазначенияКлиентСервер.ИмяТипаПлатформы());
		КонецЕсли;
		
	Иначе
		ПоказатьПредупреждение(, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для работы с токенами в ОС %1 установите библиотеки самостоятельно.'"), СистемнаяИнформация.ТипПлатформы));
		Возврат;
	КонецЕсли;
	
	ПараметрыУстановкиБиблиотек.Вставить("Система", СокрЛП(СистемнаяИнформация.ВерсияОС));
	ПараметрыУстановкиБиблиотек.Вставить("ТребуетсяУстановкаДрайверовРутокен", Ложь);
	ПараметрыУстановкиБиблиотек.Вставить("ТребуетсяУстановкаДрайверовДжакарта", Ложь);
	ПараметрыУстановкиБиблиотек.Вставить("ТребуетсяУстановкаOpenSSL", Ложь);
	ПараметрыУстановкиБиблиотек.Вставить("ТребуетсяУстановкаБиблиотекиИнтеграции", Ложь);
	ПараметрыУстановкиБиблиотек.Вставить("Ошибки", Новый Массив);
		
	Если ДляРутокена Тогда
		ПараметрыУстановкиБиблиотек.ТребуетсяУстановкаДрайверовРутокен = ТребуетсяУстановкаДрайверовРутокен;
		ПараметрыУстановкиБиблиотек.ТребуетсяУстановкаБиблиотекиИнтеграции = ТребуетсяУстановкаБиблиотекиИнтеграции;
		ПараметрыУстановкиБиблиотек.ТребуетсяУстановкаOpenSSL = ТребуетсяУстановкаOpenSSL;
		
		Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Тогда 
			ПараметрыУстановкиБиблиотек.Вставить("КаталогСистемныхПриложений", "C:\Windows\System32");
#Если Не ВебКлиент И Не МобильныйКлиент Тогда
			ПараметрыУстановкиБиблиотек.КаталогСистемныхПриложений = СтандартныеПодсистемыКлиент.КаталогСистемныхПриложений();
#КонецЕсли
		Иначе
			ПараметрыУстановкиБиблиотек.Вставить("КаталогСистемныхПриложений", "/usr/lib");
		КонецЕсли;
	Иначе
		ПараметрыУстановкиБиблиотек.ТребуетсяУстановкаДрайверовДжакарта = ТребуетсяУстановкаДрайверовДжакарта;
	КонецЕсли;
	
	Оповещение = Новый ОписаниеОповещения(
		"УстановитьБиблиотекиПослеПолученияДистрибутивов", ЭтотОбъект, ПараметрыУстановкиБиблиотек);
	
	ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
	
	ДлительнаяОперация = ПолучитьДистрибутивыБиблиотек(ПараметрыУстановкиБиблиотек);
	ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания);

КонецПроцедуры

&НаКлиенте
Асинх Функция ЗапуститьДиагностикуТокенов()
	
	Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.ВыполняетсяДиагностика;
	Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Ложь;
	Элементы.ДекорацияОшибка.Видимость = Ложь;
	Элементы.Компонента.Видимость = Ложь;
	
	Если ЗначениеЗаполнено(Параметры.ВидТокена) Тогда
		Элементы.Джакарта.Видимость = НРег(Параметры.ВидТокена) = НРег(ЭлектроннаяПодписьКлиентЛокализация.Джакарта());
		Элементы.Рутокен.Видимость = НРег(Параметры.ВидТокена) = НРег(ЭлектроннаяПодписьКлиентЛокализация.Рутокен());
	Иначе
		Элементы.Джакарта.Видимость = Истина;
		Элементы.Рутокен.Видимость = Истина;
	КонецЕсли;
	
	Токены.Очистить();
	
	ОписаниеКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
	ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для работы с токенами требуется установка внешней компоненты %1.'"),
			ОписаниеКомпоненты.ИмяОбъекта);
	ТекстОшибки = "";
	Попытка
		ОбъектКомпоненты = Ждать ЭлектроннаяПодписьСлужебныйКлиент.ОбъектВнешнейКомпонентыExtraCryptoAPI(Истина, ТекстПояснения);
	Исключение
		ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	Если Не ПустаяСтрока(ТекстОшибки) Тогда
		Элементы.ДекорацияКомпонента.Заголовок = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
			НСтр("ru = 'Компонента не установлена: %1.'"), ТекстОшибки);
		Элементы.Компонента.Видимость = Истина;
		Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.РезультатДиагностики;
		Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Истина;
		УстановитьВидимостьПриОшибке();
		Возврат Истина;
	КонецЕсли;
	
	ТребуетсяУстановкаДрайверовРутокен = Ложь;
	ТребуетсяУстановкаДрайверовДжакарта = Ложь;
	ТребуетсяУстановкаOpenSSL = Ложь;
	ТребуетсяУстановкаБиблиотекиИнтеграции = Ложь;
	ЕстьТокеныДжакарта = Ложь;
	ЕстьТокеныРутокен = Ложь;
	
	Результат = Ждать ЭлектроннаяПодписьСлужебныйКлиент.УстановленныеКриптопровайдеры(ОбъектКомпоненты);
	Если Не Результат.ПроверкаВыполнена Тогда
		Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.РезультатДиагностики;
		Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Истина;
		Элементы.ДекорацияОшибка.Видимость = Истина;
		Элементы.ДекорацияОшибка.Заголовок = ТекстОшибки;
		УстановитьВидимостьПриОшибке();
		Возврат Истина;
	КонецЕсли;
	
	Для Каждого Токен Из Результат.Токены Цикл
		
		Если ЗначениеЗаполнено(Токен.Слот) Тогда
			НоваяСтрока = Токены.Добавить();
			НоваяСтрока.Токен = Токен;
			НоваяСтрока.Представление = Токен.Представление;
			Если Токен.Токен = ЭлектроннаяПодписьКлиентЛокализация.Рутокен() Тогда
				ЕстьТокеныРутокен = Истина;
			Иначе
				ЕстьТокеныДжакарта = Истина;
			КонецЕсли;
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(Токен.Библиотеки) Тогда
			Продолжить;
		КонецЕсли;
		
		Для Каждого КлючИЗначение Из Токен.Библиотеки Цикл
			Если ЗначениеЗаполнено(КлючИЗначение.Значение) Тогда
				Продолжить;
			КонецЕсли;
			Если НРег(КлючИЗначение.Ключ) = "openssl_engine_library_path" Тогда
				ТребуетсяУстановкаБиблиотекиИнтеграции = Истина;
			ИначеЕсли НРег(КлючИЗначение.Ключ) = "pkcs11_library_path" Тогда
				Если Токен.Токен = ЭлектроннаяПодписьКлиентЛокализация.Рутокен() Тогда
					ТребуетсяУстановкаДрайверовРутокен = Истина;
				Иначе
					ТребуетсяУстановкаДрайверовДжакарта = Истина;
				КонецЕсли;
			ИначеЕсли НРег(КлючИЗначение.Ключ) = "openssl_path" Тогда
				ТребуетсяУстановкаOpenSSL = Истина;
			КонецЕсли;
		КонецЦикла;
		
	КонецЦикла;
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	Элементы.Токены.Видимость = Токены.Количество() > 0;
	
	РутокенБиблиотекаЗаголовок = "";
	РутокенOpenSSLЗаголовок = "";
	РутокенБиблиотекаИнтеграцииЗаголовок = "";
	ДжакартаБиблиотекаЗаголовок = "";
	
	ЗаголовокГотовКРаботе = НСтр("ru = 'Готов к работе.'");
	ЗаголовокТокеныНеПодключены = НСтр("ru = 'Токены не подключены.'");
	
	Элементы.УстановитьДляДжакартаРасширеннаяПодсказка.Заголовок = "";
	Если Не ТребуетсяУстановкаДрайверовДжакарта Тогда
		Элементы.УстановитьДляДжакартаРасширеннаяПодсказка.Заголовок =
			СтроковыеФункцииКлиент.ФорматированнаяСтрока(ЗаголовокГотовКРаботе + ?(ЕстьТокеныДжакарта, "", Символы.ПС + ЗаголовокТокеныНеПодключены));
			Оповестить("Установка_ПриложениеКриптографии", Истина);
	КонецЕсли;
	
	Элементы.УстановитьДляРутокенаРасширеннаяПодсказка.Заголовок = "";
	Если Не ТребуетсяУстановкаДрайверовРутокен И Не ТребуетсяУстановкаOpenSSL И Не ТребуетсяУстановкаБиблиотекиИнтеграции Тогда
		Элементы.УстановитьДляРутокенаРасширеннаяПодсказка.Заголовок =
			СтроковыеФункцииКлиент.ФорматированнаяСтрока(ЗаголовокГотовКРаботе + ?(ЕстьТокеныРутокен, "", Символы.ПС + ЗаголовокТокеныНеПодключены));
			Оповестить("Установка_ПриложениеКриптографии", Ложь);
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета")
		И (СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
			Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64
			Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86
			Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64) Тогда
			
		Элементы.УстановитьДляРутокена.Доступность = ТребуетсяУстановкаДрайверовРутокен Или ТребуетсяУстановкаOpenSSL Или ТребуетсяУстановкаБиблиотекиИнтеграции;
		Элементы.УстановитьДляДжакарта.Доступность = ТребуетсяУстановкаДрайверовДжакарта;
		
		Если ТребуетсяУстановкаOpenSSL Тогда
			Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
				Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Тогда
				РутокенOpenSSLЗаголовок = НСтр("ru = 'Для создания подписей требуется установка библиотеки <b>OpenSSL</b>. При нажатии на кнопку <b>Рутокен ЭЦП</b>, библиотека будет установлена с сайта <a href = ""https://slproweb.com/products/Win32OpenSSL.html"">slproweb.com</a>.'");
			Иначе
				РутокенOpenSSLЗаголовок = НСтр("ru = 'Для создания подписей требуется установка библиотеки <b>libcrypto</b> из состава <b>OpenSSL</b>.'");
			КонецЕсли;
		КонецЕсли;
		Если ТребуетсяУстановкаБиблиотекиИнтеграции Тогда
			РутокенБиблиотекаИнтеграцииЗаголовок = НСтр("ru = 'Для создания подписей требуется установка библиотеки интеграции с OpenSSL <b>rtengine</b>. При нажатии на кнопку <b>Рутокен ЭЦП</b>, библиотека будет установлена с <a href = ""https://www.rutoken.ru/support/download/openssl/"">сайта производителя</a>.'");
		КонецЕсли;
		Если ТребуетсяУстановкаДрайверовРутокен Тогда
			Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
				Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Тогда
				РутокенБиблиотекаЗаголовок = НСтр("ru = 'Для работы с токеном требуется установка <b>Панели управления Рутокен</b>. При нажатии на кнопку <b>Рутокен ЭЦП</b>, библиотека будет установлена с <a href = ""https://www.rutoken.ru/support/download/windows/"">сайта производителя</a>.'");
			Иначе
				РутокенБиблиотекаЗаголовок = НСтр("ru = 'Для работы с токеном требуются установленные библиотеки <a href = ""https://www.rutoken.ru/support/download/nix/""> <b>libccid</b></a> и <a href = ""https://www.rutoken.ru/support/download/pkcs/""><b>rtPKCS11ECP</b></b></a> .'");
			КонецЕсли;
		КонецЕсли;
		Если ТребуетсяУстановкаДрайверовДжакарта Тогда
			ДжакартаБиблиотекаЗаголовок = НСтр("ru = 'Для работы с токеном требуется установка <b>Единого Клиента JaCarta</b>. При нажатии на кнопку <b>JaCarta</b>, библиотека будет установлена с <a href = ""https://www.aladdin-rd.ru/catalog/jacarta-client/"">сайта производителя</a>.'");
		КонецЕсли;
		
		Элементы.Разрядность.Видимость = СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
			И (Элементы.УстановитьДляРутокена.Доступность Или Элементы.УстановитьДляДжакарта.Доступность);
		
	Иначе
		Элементы.УстановитьДляРутокена.Видимость = Ложь;
		Элементы.УстановитьДляДжакарта.Видимость = Ложь;
		Если ТребуетсяУстановкаOpenSSL Тогда
			РутокенOpenSSLЗаголовок = НСтр("ru = 'Для создания подписей требуется установка библиотеки <b>libcrypto</b> из состава <b>OpenSSL</b>.'");
		КонецЕсли;
		Если ТребуетсяУстановкаБиблиотекиИнтеграции Тогда
			РутокенБиблиотекаИнтеграцииЗаголовок = НСтр("ru = 'Для создания подписей требуется установка библиотеки интеграции с OpenSSL <b>rtengine</b> с <a href = ""https://www.rutoken.ru/support/download/openssl/"">сайта производителя</a>.'");
		КонецЕсли;
		Если ТребуетсяУстановкаДрайверовРутокен Тогда
			РутокенБиблиотекаЗаголовок = НСтр("ru = 'Для работы с токеном требуется установка библиотек для работы с Рутокен с <a href = ""https://www.rutoken.ru/support/download/pkcs/"">сайта производителя</a>.'");
		КонецЕсли;
		Если ТребуетсяУстановкаДрайверовДжакарта Тогда
			ДжакартаБиблиотекаЗаголовок = НСтр("ru = 'Для работы с токеном требуется установка <b>Единого Клиента JaCarta</b> с <a href = ""https://www.aladdin-rd.ru/catalog/jacarta-client/"">сайта производителя</a>.'");
		КонецЕсли;
	КонецЕсли;
	
	Элементы.РутокенРасширеннаяПодсказка.Заголовок = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
		СокрЛП(РутокенБиблиотекаЗаголовок + Символы.ПС + РутокенOpenSSLЗаголовок + Символы.ПС + РутокенБиблиотекаИнтеграцииЗаголовок));
	Элементы.ДжакартаРасширеннаяПодсказка.Заголовок = СтроковыеФункцииКлиент.ФорматированнаяСтрока(ДжакартаБиблиотекаЗаголовок);
	
	Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.РезультатДиагностики;
	Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Истина;
	
	Возврат Истина;
	
КонецФункции

&НаКлиенте
Процедура УстановитьВидимостьПриОшибке()
	
	Элементы.Токены.Видимость = Ложь;
	Элементы.Джакарта.Видимость = Ложь;
	Элементы.Рутокен.Видимость = Ложь;
	
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДистрибутивыБиблиотек(Параметры)
	
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(Новый УникальныйИдентификатор);
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Получение дистрибутивов библиотек для работы с токенами'");
	
	Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, 
		"ЭлектроннаяПодписьСлужебныйРФ.ПолучитьДистрибутивыБиблиотекТокенов", Параметры);
	
КонецФункции

&НаКлиенте
Процедура УстановитьБиблиотекиПослеПолученияДистрибутивов(РезультатВыполнения, Контекст) Экспорт
	
	Если РезультатВыполнения = Неопределено Тогда
		Элементы.УстановитьДляРутокена.Доступность = Истина;
		Элементы.УстановитьДляДжакарта.Доступность = Истина;
		Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Истина;
		Возврат;
	КонецЕсли;
	
	Если РезультатВыполнения.Статус = "Ошибка" Тогда
		ОбработатьОшибкуУстановкиДистрибутивов(РезультатВыполнения.ИнформацияОбОшибке, Контекст);
		Возврат;
	КонецЕсли;
	
	РезультатПолученияДистрибутивов = ПолучитьРезультатДлительнойОперации(РезультатВыполнения, УникальныйИдентификатор);
	Если ТипЗнч(РезультатПолученияДистрибутивов) = Тип("ИнформацияОбОшибке")
		Или ТипЗнч(РезультатПолученияДистрибутивов) = Тип("Строка") Тогда
		ОбработатьОшибкуУстановкиДистрибутивов(РезультатПолученияДистрибутивов, Контекст);
		Возврат;
	КонецЕсли;
	
	Если РезультатПолученияДистрибутивов.Дистрибутивы.Количество() = 0 Тогда
		Массив = СтрРазделить("ТребуетсяУстановкаДрайверовРутокен,ТребуетсяУстановкаOpenSSL,ТребуетсяУстановкаБиблиотекиИнтеграции,ТребуетсяУстановкаДрайверовДжакарта", ",");
		ТекстОшибки = "";
		Для Каждого Свойство Из Массив Цикл
			Если Контекст[Свойство] = Ложь Тогда
				Продолжить;
			КонецЕсли;
			Если Контекст[Свойство] = Ложь Тогда
				Продолжить;
			КонецЕсли;
			Контекст.Ошибки.Добавить(РезультатПолученияДистрибутивов[Свойство]);
		КонецЦикла;
		ЗакончитьУстановкуДистрибутивов(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("РезультатПолученияДистрибутивов", РезультатПолученияДистрибутивов);
	ФайловаяСистемаКлиент.СоздатьВременныйКаталог(Новый ОписаниеОповещения("ПослеСозданияВременногоКаталога", ЭтотОбъект, Контекст));
	
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьРезультатДлительнойОперации(РезультатВыполнения, УникальныйИдентификатор)
	
	// Результат выполнения фонового задания.
	Попытка
		Результат = ПолучитьИзВременногоХранилища(РезультатВыполнения.АдресРезультата);
	Исключение
		Возврат ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	УдалитьИзВременногоХранилища(РезультатВыполнения.АдресРезультата);
	
	Если Результат.Дистрибутивы.Количество() = 0 Тогда
		Возврат Результат;
	КонецЕсли;
	
	ОписаниеФайлов = Новый Массив;
	Для каждого Файл Из Результат.Дистрибутивы Цикл
		ОписаниеФайлов.Добавить(Новый ОписаниеПередаваемогоФайла(Файл.Имя,
			ПоместитьВоВременноеХранилище(Файл.ДвоичныеДанные, УникальныйИдентификатор)));
	КонецЦикла;
		
	Результат.Дистрибутивы = ОписаниеФайлов;
	
	Возврат Результат;
	
КонецФункции

&НаКлиенте
Процедура ПослеСозданияВременногоКаталога(ИмяВременногоКаталога, Контекст) Экспорт
	
	Если Не ЗначениеЗаполнено(ИмяВременногоКаталога) Тогда
		ОбработатьОшибкуУстановкиДистрибутивов(
			НСтр("ru = 'Не удалось создать временный каталог для сохранения дистрибутива'"), Контекст);
		Возврат;
	КонецЕсли;
	
	ИмяКаталогаВременныхФайлов = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ИмяВременногоКаталога);
	Контекст.Вставить("ВременныйКаталог", ИмяКаталогаВременныхФайлов);
	
	Оповещение = Новый ОписаниеОповещения("ПослеСохраненияФайловДистрибутива", ЭтотОбъект, Контекст);
	
	ПараметрыСохранения = ФайловаяСистемаКлиент.ПараметрыСохраненияФайла();
	ПараметрыСохранения.Интерактивно = Ложь;
	ПараметрыСохранения.Диалог.Каталог = ИмяКаталогаВременныхФайлов;
	ФайловаяСистемаКлиент.СохранитьФайлы(Оповещение, Контекст.РезультатПолученияДистрибутивов.Дистрибутивы, ПараметрыСохранения);
	
КонецПроцедуры

&НаКлиенте
Процедура ПослеСохраненияФайловДистрибутива(ПолученныеФайлы, Контекст) Экспорт
	
	Если ПолученныеФайлы = Неопределено Тогда
		ОбработатьОшибкуУстановкиДистрибутивов(НСтр("ru = 'Не удалось сохранить на компьютер файлы дистрибутива'"),
			Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ФайлыДистрибутиваПолучены", Истина);
	НачатьУстановкуДистрибутивов(Контекст);

КонецПроцедуры

&НаКлиенте
Процедура НачатьУстановкуДистрибутивов(Контекст)
	
	Массив = СтрРазделить("ТребуетсяУстановкаДрайверовРутокен,ТребуетсяУстановкаOpenSSL,ТребуетсяУстановкаБиблиотекиИнтеграции,ТребуетсяУстановкаДрайверовДжакарта", ",");
	Контекст.Вставить("Свойства", Массив);
	Контекст.Вставить("Индекс", -1);
	Если Контекст.ТипПлатформы = "Linux_x86_64" Или Контекст.ТипПлатформы = "Linux_x86" Тогда
		Контекст.Свойства.Вставить(0, "ТребуетсяОбновлениеБиблиотек");
	КонецЕсли;	

	НачатьУстановкуДистрибутива(Контекст)

КонецПроцедуры

&НаКлиенте
Процедура НачатьУстановкуДистрибутива(Контекст)
	
	Контекст.Индекс = Контекст.Индекс + 1;
	Если Контекст.Индекс > Контекст.Свойства.ВГраница() Тогда
		ЗакончитьУстановкуДистрибутивов(Контекст);
		Возврат;
	КонецЕсли;
	
	Свойство = Контекст.Свойства[Контекст.Индекс];
	
	Если Свойство = "ТребуетсяОбновлениеБиблиотек" Тогда
		Оповещение = Новый ОписаниеОповещения(
			"ЗапуститьПриложениеНаКлиентеПослеЗапускаПриложения", ЭтотОбъект, Контекст,
			"ЗапуститьПриложениеНаКлиентеПриОшибкеЗапускаПриложения", ЭтотОбъект);
		ИмяПрограммы = Новый Массив;
		ИмяПрограммы.Добавить("apt-get");
		ИмяПрограммы.Добавить("install");
		ИмяПрограммы.Добавить("libccid");
		ИмяПрограммы.Добавить("pcscd");
		ИмяПрограммы.Добавить("libpcsclite1");
		ИмяПрограммы.Добавить("pcsc-tools");
		ИмяПрограммы.Добавить("opensc");
		
		ПараметрыЗапуска = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
		ПараметрыЗапуска.ПолучитьПотокВывода = Истина;
		ПараметрыЗапуска.ПолучитьПотокОшибок = Истина;
		ПараметрыЗапуска.Оповещение = Оповещение;
		ПараметрыЗапуска.ТекущийКаталог = Контекст.ВременныйКаталог;
		ПараметрыЗапуска.ДождатьсяЗавершения = Истина;
		ПараметрыЗапуска.ВыполнитьСНаивысшимиПравами = Истина;
		ФайловаяСистемаКлиент.ЗапуститьПрограмму(ИмяПрограммы, ПараметрыЗапуска);
		Возврат;
	КонецЕсли;	
	
	Если Контекст[Свойство] = Ложь Тогда
		НачатьУстановкуДистрибутива(Контекст);
		Возврат;
	КонецЕсли;
	
	ПараметрыДистрибутива = Контекст.РезультатПолученияДистрибутивов[Свойство];
	
	Если ТипЗнч(ПараметрыДистрибутива) = Тип("Строка") Тогда
		Контекст.Ошибки.Добавить(ПараметрыДистрибутива);
		НачатьУстановкуДистрибутива(Контекст);
		Возврат;
	КонецЕсли;
	
	УстановитьДистрибутив(Контекст);
	
КонецПроцедуры

&НаКлиенте
Процедура УстановитьДистрибутив(Контекст)
	
	Дистрибутив = Контекст.Свойства[Контекст.Индекс];
	ПараметрыДистрибутива = Контекст.РезультатПолученияДистрибутивов[Дистрибутив];
	
	Оповещение = Новый ОписаниеОповещения(
		"ЗапуститьПриложениеНаКлиентеПослеЗапускаПриложения", ЭтотОбъект, Контекст,
		"ЗапуститьПриложениеНаКлиентеПриОшибкеЗапускаПриложения", ЭтотОбъект);
	ПараметрыЗапуска = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
	ПараметрыЗапуска.ВыполнитьСНаивысшимиПравами = Ложь;
	
	Если Дистрибутив = "ТребуетсяУстановкаБиблиотекиИнтеграции" Тогда
		ИмяПрограммы = Новый Массив;
		Если Контекст.ТипПлатформы = "Linux_x86_64" Или Контекст.ТипПлатформы = "Linux_x86" Тогда
			ИмяПрограммы.Добавить("cp");
		Иначе	
			ИмяПрограммы.Добавить("copy");
		КонецЕсли;
		ИмяПрограммы.Добавить(Контекст.ВременныйКаталог + ПараметрыДистрибутива.Имя);
		ИмяПрограммы.Добавить(Контекст.КаталогСистемныхПриложений);
		ПараметрыЗапуска.ВыполнитьСНаивысшимиПравами = Истина;
	ИначеЕсли Дистрибутив = "ТребуетсяУстановкаДрайверовДжакарта" И (Контекст.ТипПлатформы = "Linux_x86_64"
		Или Контекст.ТипПлатформы = "Linux_x86") Тогда

		ИмяПрограммы = Новый Массив;
		ИмяПрограммы.Добавить("bash");
		ИмяПрограммы.Добавить(Контекст.ВременныйКаталог + ПараметрыДистрибутива.Имя);
		ПараметрыЗапуска.ВыполнитьСНаивысшимиПравами = Истина;
	ИначеЕсли Дистрибутив = "ТребуетсяУстановкаДрайверовРутокен" И (Контекст.ТипПлатформы = "Linux_x86_64"
		Или Контекст.ТипПлатформы = "Linux_x86") Тогда
		ИмяПрограммы = Новый Массив;
		ИмяПрограммы.Добавить("dpkg");
		ИмяПрограммы.Добавить("-i");
		ИмяПрограммы.Добавить(Контекст.ВременныйКаталог + ПараметрыДистрибутива.Имя);
		ПараметрыЗапуска.ВыполнитьСНаивысшимиПравами = Истина;
	Иначе
		ИмяПрограммы = Контекст.ВременныйКаталог + ПараметрыДистрибутива.Имя;
	КонецЕсли;
	
	ПараметрыЗапуска.ПолучитьПотокВывода = Истина;
	ПараметрыЗапуска.ПолучитьПотокОшибок = Истина;
	ПараметрыЗапуска.Оповещение = Оповещение;
	ПараметрыЗапуска.ТекущийКаталог = Контекст.ВременныйКаталог;
	ПараметрыЗапуска.ДождатьсяЗавершения = Истина;
	
	ФайловаяСистемаКлиент.ЗапуститьПрограмму(ИмяПрограммы, ПараметрыЗапуска);
	
КонецПроцедуры

&НаКлиенте
Асинх Процедура ЗапуститьПриложениеНаКлиентеПослеЗапускаПриложения(Результат, Контекст) Экспорт
	
	Ждать ЗапуститьДиагностикуТокенов();
	
	Дистрибутив = Контекст.Свойства[Контекст.Индекс];
	Если Дистрибутив <> "ТребуетсяОбновлениеБиблиотек"
		И ЭтотОбъект[Контекст.Свойства[Контекст.Индекс]] = Истина Тогда
		
		Если Дистрибутив = "ТребуетсяУстановкаБиблиотекиИнтеграции" Тогда
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось установить библиотеку интеграции с OpenSSL (rtengine).
			|Загрузите библиотеку с сайта производителя %1 самостоятельно, распакуйте и скопируйте в каталог %2 файл %3.'"),
			"https://www.rutoken.ru/support/download/openssl/",
			Контекст.КаталогСистемныхПриложений,
			Контекст.РезультатПолученияДистрибутивов[Дистрибутив].Имя);
			
		ИначеЕсли Дистрибутив = "ТребуетсяУстановкаДрайверовДжакарта" Тогда
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Установите Единый Клиент JaCarta с сайта производителя %1 самостоятельно.'"),
			"https://www.aladdin-rd.ru/catalog/jacarta-client/");
			
		ИначеЕсли Дистрибутив = "ТребуетсяУстановкаДрайверовРутокен" Тогда	
			
			Если Контекст.ТипПлатформы = "Windows_x86_64" Или Контекст.ТипПлатформы = "Windows_x86" Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось установить драйверы для работы с Рутокеном.
				|Установите драйверы самостоятельно с сайта производителя %2.'"),
				Контекст.Система,
				"https://www.rutoken.ru/support/download/windows/");
			Иначе
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось установить драйверы для работы с Рутокеном в ОС %1.
				|Установите библиотеку %2 самостоятельно с сайта производителя %3.'"),
				Контекст.Система,
				"rtPKCS11ecp",
				"https://www.rutoken.ru/support/download/nix/");
			КонецЕсли;
			
		ИначеЕсли Дистрибутив = "ТребуетсяУстановкаOpenSSL" Тогда
			
			Если Контекст.ТипПлатформы = "Windows_x86_64" Или Контекст.ТипПлатформы = "Windows_x86" Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Для работы с токенами в ОС %1 установите библиотеку %2 самостоятельно, например, с ресурса %3.'"),
					Контекст.ТипПлатформы,
					"OpenSSL",
					"https://slproweb.com");
			Иначе
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для работы с токенами в ОС %1 установите библиотеку %2 из состава OpenSSL 3 в %3 самостоятельно, например, из комплекта разработчика %4.
				|Проверьте зависимости (ldd /usr/lib/libcrypto.so.3) и обновите необходимые библиотеки.'"),
				Контекст.ТипПлатформы,
				"libcrypto.so.3",
				Контекст.КаталогСистемныхПриложений,
				"https://www.rutoken.ru/developers/sdk/");

			КонецЕсли;
			
		КонецЕсли;
		
		Если ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда
			Контекст.Ошибки.Добавить(СтрШаблон("%1%2%3", ТекстОшибки, Символы.ПС, Результат.ОписаниеОшибки));
		ИначеЕсли ЗначениеЗаполнено(Результат.ПотокОшибок) Тогда
			Контекст.Ошибки.Добавить(СтрШаблон("%1%2%3", ТекстОшибки, Символы.ПС, Результат.ПотокОшибок));
		КонецЕсли;
	КонецЕсли;
	
	НачатьУстановкуДистрибутива(Контекст);
	
КонецПроцедуры

&НаКлиенте
Процедура ЗапуститьПриложениеНаКлиентеПриОшибкеЗапускаПриложения(Ошибка, Контекст) Экспорт
	Контекст.Ошибки.Добавить(ОбработкаОшибок.КраткоеПредставлениеОшибки(Ошибка));
	НачатьУстановкуДистрибутива(Контекст);
КонецПроцедуры

&НаКлиенте
Процедура ЗакончитьУстановкуДистрибутивов(Контекст)
	
	Элементы.УстановитьДляРутокена.Доступность = Истина;
	Элементы.УстановитьДляДжакарта.Доступность = Истина;
	Элементы.ФормаОбновитьИнформациюОТокенах.Доступность = Истина;
	ПоказатьОшибкиУстановкиДистрибутивов(Контекст);
	
КонецПроцедуры

&НаКлиенте
Процедура ОбработатьОшибкуУстановкиДистрибутивов(ТекстОшибки, Контекст)

	Если ТипЗнч(ТекстОшибки) = Тип("ИнформацияОбОшибке") Тогда
		ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ТекстОшибки);
	КонецЕсли;
	Контекст.Ошибки.Добавить(ТекстОшибки);
	ЗакончитьУстановкуДистрибутивов(Контекст)

КонецПроцедуры

&НаКлиенте
Процедура ПоказатьОшибкиУстановкиДистрибутивов(Контекст) 
	
	Если Контекст.Ошибки.Количество() > 0 Тогда
		ТекстОшибкиКлиент = "";
		Для Каждого Ошибка Из Контекст.Ошибки Цикл
			ТекстОшибкиКлиент = ТекстОшибкиКлиент + ?(ТекстОшибкиКлиент = "", "", Символы.ПС + Символы.ПС) + "• "+ Ошибка; 
		КонецЦикла;	
		ПараметрыОшибки = ЭлектроннаяПодписьКлиент.ПараметрыФормыРасширенногоПредставленияОшибки();
		ПараметрыОшибки.ЗаголовокПредупреждения = НСтр("ru = 'Не удалось установить библиотеки'");
		ПараметрыОшибки.ТекстОшибкиКлиент = ТекстОшибкиКлиент;
		ПараметрыОшибки.ПоказатьТребуетсяПомощь = Истина;
		Оповещение = Новый ОписаниеОповещения("ЗапуститьДиагностикуТокеновПослеОтображенияОшибок", ЭтотОбъект);
		ЭлектроннаяПодписьКлиент.ОткрытьФормуРасширенногоПредставленияОшибки(ПараметрыОшибки, ЭтотОбъект, Оповещение);
	Иначе
		ЗапуститьДиагностикуТокенов();
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ЗапуститьДиагностикуТокеновПослеОтображенияОшибок(Результат, ДополнительныеПараметры) Экспорт
	ЗапуститьДиагностикуТокенов();
КонецПроцедуры

#КонецОбласти