Меню

Elma агент ошибка 401

Здравствуйте!

Не удаётся подключиться ELMA-Agent’ом (версия 3.8.8.33777) к серверу ELMA 3.8.8.24773 Стандарт.
Сервер установлен на Windows Server 2012R2 Std в режиме работы с собственным веб-сервером (Cassini), база данных SQL Server Express. Свободных лицензий больше 5 штук.
«Клиентский компьютер»: Windows 10 Pro (со всем и обновлениями, включая Creators Update). Находятся в разных сетях («клиентский» компьютер за NAT’ом).

После нажатия кнопки «Войти в систему» практически сразу же выдаёт: «Ошибка соединения». Если развернуть описание ошибки: «Код ошибки — 401; Описание — Ошибка авторизации«.

С теми же реквизитами регистрация через веб-браузер (и дальнейшая работа на портале) проходит успешно.

В это же время в журнале работы ELMА-Agent (который в файле %USERPROFILE%AppDataRoamingELMA Agent MonoElmaAgent.log):
—————————
2017-26-06 10:06:32 [7] ERROR Errors — Ошибка авторизации
EleWise.ELMA.Agent.Core.Managers.ExceptionManager.LogSystem.Exception: Сетевая ошибка

—————————

В это же время (с поправкой на небольшую разницу по секундам между «клиентским» компьютером и сервером) в журнале ошибок сервера ELMA (файл Каталог_установки_ELMAWeblogserrorerror-log-20170626
—————————
ERROR 2017-06-26 10:06:34,793 [30] EleWise.ELMA.Logging.Logger — В сервисе «EleWise.ELMA.Web.Service.v1.AuthorizationService» в методе «s => s.LoginWithUserName(value(EleWise.ELMA.Web.Service.v1.AuthorizationService+<>c__DisplayClass5).username, value(EleWise.ELMA.Web.Service.v1.AuthorizationService+<>c__DisplayClass5).password)» произошла ошибка: Сессия клиента не установлена
—————————

В это же время в журнале диагностики сервера ELMA (кратковременно включён на полный сбор информации, файл Каталог_установки_ELMAWeblogsDiagnosticsdiagnostics-20170626):
—————————
2017-06-26 10:06:34,776 [1526055] Web request start. POST: /API/REST/Authorization/LoginWith?username=user77. User host address: 92.241.17.16.
2017-06-26 10:06:34,776 [1526055] [CALL#4364] Start UserManager.Load(Int64).
2017-06-26 10:06:34,776 [1526055] [CALL#4365] Start UserManager.LoadOrNull(Int64).
2017-06-26 10:06:34,776 [1526055] [CALL#4367] Start PermissionManagmentService.GetPermissions().
2017-06-26 10:06:34,776 [1526055] [CALL#4367] End.
2017-06-26 10:06:34,776 [1526055] [CALL#4365] End.
2017-06-26 10:06:34,776 [1526055] [CALL#4364] End.
2017-06-26 10:06:34,776 [1526055] [CALL#4368] Start UserManager.CreateCriteria(FetchOptions, Type, String, IEntityFilter).
2017-06-26 10:06:34,776 [1526055] [CALL#4369] Start UserManager.get_DefaultCriteriaAlias().
2017-06-26 10:06:34,776 [1526055] [CALL#4369] End.
2017-06-26 10:06:34,776 [1526055] [CALL#4368] End.
2017-06-26 10:06:34,776 [1526055] [CALL#4376] Start UserManager.LoadOrNull(Int64).
2017-06-26 10:06:34,776 [1526055] [CALL#4376] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4380] Start PublicApplicationTokenManager.CreateCriteria(FetchOptions, Type, String, IEntityFilter).
2017-06-26 10:06:34,793 [1526055] [CALL#4381] Start PublicApplicationTokenManager.get_DefaultCriteriaAlias().
2017-06-26 10:06:34,793 [1526055] [CALL#4381] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4382] Start PublicApplicationTokenManager.SetupFetchOptions(ICriteria, FetchOptions, Type).
2017-06-26 10:06:34,793 [1526055] [CALL#4383] Start PublicApplicationTokenManager.SetupSortOptions(ICriteria, FetchOptions, Type).
2017-06-26 10:06:34,793 [1526055] [CALL#4383] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4382] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4380] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4386] Start PublicApplicationTokenManager.CreateCriteria(FetchOptions, Type, String, IEntityFilter).
2017-06-26 10:06:34,793 [1526055] [CALL#4387] Start PublicApplicationTokenManager.get_DefaultCriteriaAlias().
2017-06-26 10:06:34,793 [1526055] [CALL#4387] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4388] Start PublicApplicationTokenManager.SetupFetchOptions(ICriteria, FetchOptions, Type).
2017-06-26 10:06:34,793 [1526055] [CALL#4389] Start PublicApplicationTokenManager.SetupSortOptions(ICriteria, FetchOptions, Type).
2017-06-26 10:06:34,793 [1526055] [CALL#4389] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4388] End.
2017-06-26 10:06:34,793 [1526055] [CALL#4386] End.
2017-06-26 10:06:34,793 [1526055] Web request end.

—————————

Elma-Agent, будучи установлен на сам сервер (с целью проверить как авторизация работает в таком случае), просто не запускается. Сразу выдает окно с ошибкой:
—————————
Ссылка на объект не указывает на экземпляр объекта.; в EleWise.ELMA.Agent.Core.UI.ElmaAppImpl.Run(String[] args, Type mainClass) в c:BuildAgentworkf7c9271625244ecaEleWise.ELMA.Agent.MonoEleWise.ELMA.Agent.CoreUIAppImpl.cs:строка 84
в EleWise.ELMA.Agent.MainClassElmaAgent.Main(String[] args)

—————————

Может кто знает что нужно «подкрутить» в настройках сервера, чтобы Агент мог к нему успешно подключиться (авторизоваться)?

Появление сообщения об ошибке 401 Unauthorized Error («отказ в доступе») при открытии страницы сайта означает неверную авторизацию или аутентификацию пользователя на стороне сервера при обращении к определенному url-адресу. Чаще всего она возникает при ошибочном вводе имени и/или пароля посетителем ресурса при входе в свой аккаунт. Другой причиной являются неправильные настройки, допущенные при администрировании web-ресурса. Данная ошибка отображается в браузере в виде отдельной страницы с соответствующим описанием. Некоторые разработчики интернет-ресурсов, в особенности крупных порталов, вводят собственную дополнительную кодировку данного сбоя:

  • 401 Unauthorized;
  • Authorization Required;
  • HTTP Error 401 – Ошибка авторизации.

Попробуем разобраться с наиболее распространенными причинами возникновения данной ошибки кода HTTP-соединения и обсудим способы их решения.

Причины появления ошибки сервера 401 и способы ее устранения на стороне пользователя

При доступе к некоторым сайтам (или отдельным страницам этих сайтов), посетитель должен пройти определенные этапы получения прав:

  1. Идентификация – получение вашей учетной записи («identity») по username/login или email.
  2. Аутентификация («authentic») – проверка того, что вы знаете пароль от этой учетной записи.
  3. Авторизация – проверка вашей роли (статуса) в системе и решение о предоставлении доступа к запрошенной странице или ресурсу на определенных условиях.

Большинство пользователей сохраняют свои данные по умолчанию в истории браузеров, что позволяет быстро идентифицироваться на наиболее часто посещаемых страницах и синхронизировать настройки между устройствами. Данный способ удобен для серфинга в интернете, но может привести к проблемам с безопасностью доступа к конфиденциальной информации. При наличии большого количества авторизованных регистрационных данных к различным сайтам используйте надежный мастер-пароль, который закрывает доступ к сохраненной в браузере информации.

Наиболее распространенной причиной появления ошибки с кодом 401 для рядового пользователя является ввод неверных данных при посещении определенного ресурса. В этом и других случаях нужно попробовать сделать следующее:

  1. Проверьте в адресной строке правильность написания URL. Особенно это касается перехода на подстраницы сайта, требующие авторизации. Введите правильный адрес. Если переход на страницу осуществлялся после входа в аккаунт, разлогинитесь, вернитесь на главную страницу и произведите повторный вход с правильными учетными данными.
  2. При осуществлении входа с сохраненными данными пользователя и появлении ошибки сервера 401 проверьте их корректность в соответствующих настройках данного браузера. Возможно, авторизационные данные были вами изменены в другом браузере. Также можно очистить кэш, удалить cookies и повторить попытку входа. При удалении истории браузера или очистке кэша потребуется ручное введение логина и пароля для получения доступа. Если вы не помните пароль, пройдите процедуру восстановления, следуя инструкциям.
  3. Если вы считаете, что вводите правильные регистрационные данные, но не можете получить доступ к сайту, обратитесь к администратору ресурса. В этом случае лучше всего сделать скриншот проблемной страницы.
  4. Иногда блокировка происходит на стороне провайдера, что тоже приводит к отказу в доступе и появлению сообщения с кодировкой 401. Для проверки можно попробовать авторизоваться на том же ресурсе с альтернативного ip-адреса (например, используя VPN). При подтверждении блокировки трафика свяжитесь с провайдером и следуйте его инструкциям.

Некоторые крупные интернет-ресурсы с большим количеством подписчиков используют дополнительные настройки для обеспечения безопасности доступа. К примеру, ваш аккаунт может быть заблокирован при многократных попытках неудачной авторизации. Слишком частые попытки законнектиться могут быть восприняты как действия бота. В этом случае вы увидите соответствующее сообщение, но можете быть просто переадресованы на страницу с кодом 401. Свяжитесь с администратором сайта и решите проблему.

Иногда простая перезагрузка проблемной страницы, выход из текущей сессии или использование другого веб-браузера полностью решают проблему с 401 ошибкой авторизации.

Ошибка 401 - отказ в доступе

Устранение ошибки 401 администратором веб-ресурса 

Для владельцев сайтов, столкнувшихся с появлением ошибки отказа доступа 401, решить ее порою намного сложнее, чем обычному посетителю ресурса. Есть несколько рекомендаций, которые помогут в этом:

  • Обращение в службу поддержки хостинга сайта. Как и в случае возникновения проблем с провайдером, лучше всего подробно описать последовательность действий, приведших к появлению ошибки 401, приложить скриншот.
  • При отсутствии проблем на стороне хостинг-провайдера можно внести следующие изменения в настройки сайта с помощью строки Disallow:/адрес проблемной страницы. Запретить индексацию страницам с ошибкой в «rоbоts.txt», после чего добавить в файл «.htассеss» строку такого типа:
Redirect 301 /oldpage.html http://site.com/newpage.html.

Где в поле /oldpage.html прописывается адрес проблемной страницы, а в http://site.com/newpage.html адрес страницы авторизации.

Таким образом вы перенаправите пользователей со всех страниц, которые выдают ошибку 401, на страницу начальной авторизации.

  • Если после выполнения предыдущих рекомендаций пользователи при попытках авторизации все равно видят ошибку 401, то найдите на сервере файл «php.ini» и увеличьте время жизни сессии, изменив значения следующих параметров: «session.gc_maxlifetime» и «session.cookie_lifetime» на 1440 и 0 соответственно.
  • Разработчики веб-ресурсов могут использовать более сложные методы авторизации и аутентификации доступа для создания дополнительной защиты по протоколу HTTP. Если устранить сбой простыми методами администрирования не удается, следует обратиться к специалистам, создававшим сайт, для внесения соответствующих изменений в код.

Хотя ошибка 401 и является проблемой на стороне клиента, ошибка пользователя на стороне сервера может привести к ложному требованию входа в систему. К примеру, сетевой администратор разрешит аутентификацию входа в систему всем пользователям, даже если это не требуется. В таком случае сообщение о несанкционированном доступе будет отображаться для всех, кто посещает сайт. Баг устраняется внесением соответствующих изменений в настройки.

Дополнительная информация об ошибке с кодом 401

Веб-серверы под управлением Microsoft IIS могут предоставить дополнительные данные об ошибке 401 Unauthorized в виде второго ряда цифр:

  • 401, 1 – войти не удалось;
  • 401, 2 – ошибка входа в систему из-за конфигурации сервера;
  • 401, 3 – несанкционированный доступ из-за ACL на ресурс;
  • 401, 501 – доступ запрещен: слишком много запросов с одного и того же клиентского IP; ограничение динамического IP-адреса – достигнут предел одновременных запросов и т.д.

Более подробную информацию об ошибке сервера 401 при использовании обычной проверки подлинности для подключения к веб-узлу, который размещен в службе MS IIS, смотрите здесь. 

Следующие сообщения также являются ошибками на стороне клиента и относятся к 401 ошибке:

  • 400 Bad Request; 
  • 403 Forbidden; 
  • 404 Not Found;
  • 408 Request Timeout.

Как видим, появление ошибки авторизации 401 Unauthorized не является критичным для рядового посетителя сайта и чаще всего устраняется самыми простыми способами. В более сложной ситуации оказываются администраторы и владельцы интернет-ресурсов, но и они в 100% случаев разберутся с данным багом путем изменения настроек или корректировки html-кода с привлечением разработчика сайта. 

Ошибка 401 Unauthorized Error – это код состояния HTTP, который означает, что страница, к которой вы пытались получить доступ, не может быть загружена, пока вы не войдете в систему с действительным идентификатором пользователя и паролем.

Если вы только что вошли в систему и получили 401 ошибку авторизации, это означает, что введенные вами учетные данные по какой-то причине недействительны.

Сообщения об ошибках 401 часто настраиваются на каждом веб-сайте индивидуально, особенно если это крупный портал, поэтому имейте в виду, что эта ошибка может проявляться многими способами, из которых самые распространенные:

  • 401 Unauthorized
  • Authorization Required
  • HTTP Error 401 – Ошибка авторизации

401 ошибка авторизации отображается внутри окна веб-браузера, как обычная веб-страница. Как и большинство подобных ошибок, вы можете найти их во всех браузерах, работающих в любой операционной системе.

Иллюстрация на тему появления ошибки 401

  1. Проверьте на наличие ошибок в URL. Возможно, ошибка 401 Unauthorized возникла, потому что URL-адрес был введен неправильно, или выбранная ссылка указывает на неправильный URL-адрес, предназначенный только для авторизованных пользователей.

  2. Если вы уверены, что URL-адрес действителен, посетите главную страницу веб-сайта и найдите ссылку с надписью «Логин» или «Безопасный доступ». Введите здесь свои учетные данные, а затем повторите попытку.

    Если у вас нет учетных данных или вы забыли свои, следуйте инструкциям на веб-сайте для настройки учетной записи или изменения пароля.

    Если вам трудно вспоминать свои, храните их в диспетчере паролей, чтобы приходилось помнить только один пароль.

  3. Перезагрузите страницу. Как бы просто это не показалось, закрытия страницы и её повторное открытие может помочь исправить ошибку 401, но только если она вызвана ошибочно загруженной страницей.

  4. Удалите кеш вашего браузера. Возможно, в вашем браузере хранится неверная информация для входа в систему, что нарушает процесс входа и выдает ошибку 401. Очистка кеша устранит все проблемы в этих файлах и даст странице возможность загружать свежие файлы прямо с сервера.

  5. Если вы уверены, что страница, которую вы пытаетесь открыть, не нуждается в авторизации, сообщение об ошибке 401 Unauthorized может быть общей ошибкой. В этом случае лучше всего связаться с веб-мастером или другим контактом веб-сайта и сообщить им о проблеме.

Другие варианты ошибки 401

Веб-серверы под управлением Microsoft IIS могут предоставить дополнительную информацию об ошибке 401 Unauthorized, например:

Коды ошибок Microsoft IIS 401
Ошибка Объяснение
401,1 Войти не удалось.
401,2 Ошибка входа в систему из-за конфигурации сервера.
401,3 Несанкционированный доступ из-за ACL на ресурс.
401,4 Авторизация не пройдена фильтром.
401,5 Авторизация блокирована приложением ISAPI/CGI.
401,501 Доступ запрещен: слишком много запросов с одного и того же клиентского IP; Ограничение динамического IP-адреса – достигнут предел одновременных запросов.
401,502 Запрещено: слишком много запросов с одного IP-адреса клиента; Ограничение динамического IP-адреса – достигнут максимальный предел скорости запросов.
401,503 Отказ в доступе: IP-адрес включен в список запрещенных IP
401,504 Отказ в доступе: имя хоста включено в список запрещенных

Ошибки подобные 401

Следующие сообщения также являются ошибками на стороне клиента и относятся к 401 ошибке: 400 Bad Request, 403 Forbidden, 404 Not Found и 408 Request Timeout.

Также существует ряд кодов состояния HTTP на стороне сервера, например, часто встречающийся 500 Internal Server Error.

RomanNF

0 / 0 / 0

Регистрация: 05.02.2018

Сообщений: 16

1

03.06.2022, 15:04. Показов 525. Ответов 4

Метки нет (Все метки)


Добрый день! Пытаюсь на Python реализовать взаимодействие с web-сервисом BPMS ELMA. Не получается авторизоваться в системе и получить токены для дальнейшей работы с сервисом. Что я упускаю? Спасибо!

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import datetime as dt
import requests as r
 
elma_host = ' http://bpm-demo.elma-bpm.ru'
elma_user = 'robot'
elma_password = 'QazWsxEdc#123'
 
elma_app_token = 'A3BEDD75C3BC5BD402703F0327F9CA5B5D95AC456F4AC9952563508882B62F8A566E859BF8BDB0A9A1CBD9857296C3DE0CD93FBD1A60DF62CB757DB2B6DD6123'
 
elma_url = f'''{elma_host}/API/REST/Authorization/LoginWith?username={elma_user}'''
 
elma_request_headers = {'ApplicationToken':elma_app_token,
                                       'Content-Type':'application/json; charset=utf-8',
                                       'webdata-version':'2.0'}
 
elma_request_params = {'password':elma_password}
response = r.post(url=elma_url, params=elma_request_params, headers=elma_request_headers)

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

03.06.2022, 15:04

4

Эксперт по компьютерным сетям

5868 / 3331 / 1028

Регистрация: 03.11.2009

Сообщений: 9,950

03.06.2022, 16:25

2

«Не получается» — это не техническое описание проблемы. Что именно не получается? Ошибка (если да, то какая), нет ошибки, и просто не приходит токен, не знаете как код написать (если да, то что именно не понимаете)

Добавлено через 1 минуту
с кодом выше я вижу, что проблема в авторизации

Код

{'InnerException': None, 'Message': 'Ошибка авторизации', 'StatusCode': 401}



0



0 / 0 / 0

Регистрация: 05.02.2018

Сообщений: 16

03.06.2022, 17:07

 [ТС]

3

Да, не получается авторизоваться — выдается сообщение об ошибке как на вашем скриншоте.



0



0 / 0 / 0

Регистрация: 05.02.2018

Сообщений: 16

03.06.2022, 18:39

 [ТС]

5

На счет этого как раз не уверен… Не понимаю как корректно передать пароль. Сами запросы обрабатываются сервером — данный пользователь блокировался в системе после превышения кол-ва некорректных вводов учетных данных.



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

03.06.2022, 18:39

Помогаю со студенческими работами здесь

Авторизация по API
Всем привет.

Встала задача авторизоваться по API на одном сайте, вот ссылка на их API:…

Авторизация VK API
Для авторизации необходимо ввести логин/пароль с помощью QWebView

Но при нажатии на кнопку…

Авторизация vk.com API
Здравствуйте, возникла проблема с авторизацией в vk. В самой VS проект отлично запускается и…

Авторизация в vk api
Здравствуйте, есть небольшой вопросик:
Как сделать проверку на вход вк?

vk_session =…

авторизация в vk api
пожалуйста опишите, как можно подробнее процесс авторизации пользователя когда тот добавляет…

Авторизация API
Добрый день!

Задался вопросом и не могу нагуглить:

Есть простейшее API на PHP (REST вроде…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

5

I am extracting gmail contacts using opencontactsnet. I get The remote server returned an error: (401) Unauthorized. when executing this line

HttpWebResponse exportResponse = ( HttpWebResponse ) contactsRequest.GetResponse();

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Net;
using System.Web.UI;
using System.Web.UI.WebControls;
using OpenContactsNet;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        GmailExtract gm = new GmailExtract();
        NetworkCredential nw = new NetworkCredential("chendur.pandiya","**");
        MailContactList mc;
        if (gm.Extract(nw, out mc))
        {

        }
        else
        {

        }
     }
}

Here is the complete GmailExtract class,

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Utilities.Web;

namespace OpenContactsNet
{
    public class GmailExtract : IMailContactExtract
    {
        private const string ContinueUrl = "http://mail.google.com/mail?ui=html&amp;zy=l";
        private const string ExportUrl = "https://mail.google.com/mail/contacts/data/export?exportType=ALL&groupToExport=&out=GMAIL_CSV";
        private const string LoginRefererUrl = "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&ltmpl=default&ltmplcache=2";
        private const string LoginUrl = "https://www.google.com/accounts/ServiceLoginAuth?service=mail";
        private const string UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 1.0.3705; .NET CLR 3.0.04506.30)";

        #region IMailContactExtract Members

        public bool Extract( NetworkCredential credential, out MailContactList list )
        {
            bool result = false;
            list = new MailContactList();

            try
            {
                CookieCollection cookies = new CookieCollection();

                // Prepare login form data
                HttpValueCollection loginFormValues = new HttpValueCollection();
                loginFormValues[ "ltmpl" ] = "default";
                loginFormValues[ "ltmplcache" ] = "2";
                loginFormValues[ "continue" ] = ContinueUrl;
                loginFormValues[ "service" ] = "mail";
                loginFormValues[ "rm" ] = "false";
                loginFormValues[ "hl" ] = "en";
                loginFormValues[ "Email" ] = credential.UserName;
                loginFormValues[ "Passwd" ] = credential.Password;
                loginFormValues[ "PersistentCookie" ] = "true";
                loginFormValues[ "rmShown" ] = "1";
                loginFormValues[ "null" ] = "Sign In";

                // Convert to bytes
                byte[] loginPostData = Encoding.UTF8.GetBytes( loginFormValues.ToString( true ) );

                HttpWebRequest loginRequest = ( HttpWebRequest ) WebRequest.Create( LoginUrl );
                loginRequest.Method = "POST";
                loginRequest.UserAgent = UserAgent;
                loginRequest.Referer = LoginRefererUrl;
                loginRequest.ContentType = "application/x-www-form-urlencoded";
                loginRequest.ContentLength = loginPostData.Length;
                loginRequest.AllowAutoRedirect = false;

                // Create cookie container
                loginRequest.CookieContainer = new CookieContainer();

                // Add post data to request
                Stream stream;
                using ( stream = loginRequest.GetRequestStream() )
                {
                    stream.Write( loginPostData, 0, loginPostData.Length );
                }

                HttpWebResponse loginResponse = ( HttpWebResponse ) loginRequest.GetResponse();

                cookies.Add( loginResponse.Cookies );

                // Create request to export Google CSV page
                HttpWebRequest contactsRequest = ( HttpWebRequest ) WebRequest.Create( ExportUrl );
                contactsRequest.Method = "GET";
                contactsRequest.UserAgent = UserAgent;
                contactsRequest.Referer = loginResponse.ResponseUri.ToString();

                // use cookie gotten from login page
                contactsRequest.CookieContainer = new CookieContainer();
                foreach ( Cookie cookie in cookies )
                {
                    contactsRequest.CookieContainer.Add( cookie );
                }

                HttpWebResponse exportResponse = ( HttpWebResponse ) contactsRequest.GetResponse();

                // Read data from response stream
                string csvData;
                using ( Stream responseStream = exportResponse.GetResponseStream() )
                {
                    using ( StreamReader streamRead = new StreamReader( responseStream ) )
                    {
                        csvData = streamRead.ReadToEnd();
                    }
                }

                // parse google csv
                string[] lines = csvData.Split( 'n' );
                foreach ( string line in lines )
                {
                    string[] values = line.Split( ',' );
                    if ( values.Length < 2 )
                    {
                        continue;
                    }

                    MailContact mailContact = new MailContact();
                    mailContact.Email = values[ 1 ];
                    mailContact.Name = values[ 0 ];
                    list.Add( mailContact );
                }

                result = true;
            }
            catch (Exception e)
            {
                throw e;
            }

            return result;
        }

        #endregion
    }
}

asked Aug 2, 2010 at 6:43

ACP's user avatar

I ran into the same problem. I had to change the GmailExtract class in opencontactsnet. Below is the new code which works for me.

public class GmailExtract : IMailContactExtract
    {
        private const string ContinueUrl = "https://mail.google.com/mail/?"; 
        private const string ExportUrl = "https://mail.google.com/mail/contacts/data/export?exportType=ALL&groupToExport=&out=GMAIL_CSV";
        private const string LoginRefererUrl = "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&ltmpl=default&ltmplcache=2";
        private const string LoginUrl = "https://www.google.com/accounts/ServiceLoginAuth?service=mail";
        private const string UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)";

        #region IMailContactExtract Members

        public bool Extract( NetworkCredential credential, out MailContactList list)
        {
            bool result = false;
            list = new MailContactList();

            DateTime jsStartDate = new DateTime(1970, 1, 1);
            TimeSpan endTs = DateTime.Now.Subtract(jsStartDate);
            TimeSpan startTs = DateTime.Now.AddMinutes(-2).Subtract(jsStartDate);

            try
            {
                CookieCollection cookies = new CookieCollection();

                // Prepare login form data
                HttpValueCollection loginFormValues = new HttpValueCollection();
                loginFormValues["Email"] = credential.UserName;
                loginFormValues["Passwd"] = credential.Password;
                loginFormValues["asts"] = "";
                loginFormValues["continue"] = ContinueUrl;
                loginFormValues["dsh"] = "1461574034599761425";
                loginFormValues["hl"] = "en";
                loginFormValues["ltmpl"] = "default";
                loginFormValues["ltmplcache"] = "2";
                loginFormValues["rm"] = "false";
                loginFormValues["rmShown"] = "1";
                loginFormValues["service"] = "mail";
                loginFormValues["signIn"] = "Sign In";
                loginFormValues["scc"] = "1";
                loginFormValues["ss"] = "1";
                loginFormValues["GALX"] = "rBTUs4OAJBI";
                loginFormValues["ltmpl"] = "default";
                loginFormValues["ltmpl"] = "default";

                // Convert to bytes
                byte[] loginPostData = Encoding.UTF8.GetBytes( loginFormValues.ToString( true ) );

                HttpWebRequest loginRequest = ( HttpWebRequest ) WebRequest.Create( LoginUrl );
                loginRequest.Method = "POST";
                loginRequest.UserAgent = UserAgent;
                loginRequest.Referer = LoginRefererUrl;
                loginRequest.ContentType = "application/x-www-form-urlencoded";
                loginRequest.ContentLength = loginPostData.Length;
                loginRequest.AllowAutoRedirect = false;

                // Create cookie container
                loginRequest.CookieContainer = new CookieContainer();
                loginRequest.CookieContainer.Add(new Cookie("GMAIL_LOGIN", "T" + startTs.Milliseconds.ToString() + "/" + startTs.Milliseconds.ToString() + "/" + endTs.Milliseconds.ToString(), "/", ".google.com"));
                loginRequest.CookieContainer.Add(new Cookie("GALX", "rBTUs4OAJBI", "/accounts", ".google.com"));

                // Add post data to request
                Stream stream;
                using ( stream = loginRequest.GetRequestStream())
                {
                    stream.Write( loginPostData, 0, loginPostData.Length);
                }

                HttpWebResponse loginResponse = ( HttpWebResponse ) loginRequest.GetResponse();

                cookies.Add( loginResponse.Cookies );

                // Create request to export Google CSV page
                HttpWebRequest contactsRequest = ( HttpWebRequest ) WebRequest.Create( ExportUrl );
                contactsRequest.Method = "GET";
                contactsRequest.UserAgent = UserAgent;
                contactsRequest.Referer = loginResponse.ResponseUri.ToString();

                // use cookie gotten from login page
                contactsRequest.CookieContainer = new CookieContainer();
                foreach ( Cookie cookie in cookies )
                {
                    contactsRequest.CookieContainer.Add( cookie );
                }

                HttpWebResponse exportResponse = ( HttpWebResponse ) contactsRequest.GetResponse();

                // Read data from response stream
                string csvData;
                using ( Stream responseStream = exportResponse.GetResponseStream())
                {
                    using ( StreamReader streamRead = new StreamReader( responseStream ) )
                    {
                        csvData = streamRead.ReadToEnd();
                    }
                }

                // parse google csv
                string[] lines = csvData.Split( 'n' );
                foreach ( string line in lines )
                {
                    string[] values = line.Split( ',' );
                    if ( values.Length < 2 )
                    {
                        continue;
                    }

                    MailContact mailContact = new MailContact();
                    mailContact.Email = values[ 28 ];
                    mailContact.Name = values[ 0 ];
                    if (mailContact.Email.Trim().Length > 0)
                    {

                         list.Add(mailContact);

                    }
                }

                result = true;
            }
            catch
            {
            }

            return result;
        }

        #endregion
    }

answered Aug 2, 2010 at 7:31

ajay_whiz's user avatar

ajay_whizajay_whiz

17.3k3 gold badges36 silver badges44 bronze badges

5

I am not familiar with google’s api nor do I know C#.
However check the URL you are sending your form to.
Looks like your authentication works. Otherwise you would have recieved a 403.
401 means that you (as an authenticated user) are not allowed to access the requested resource.

answered Aug 2, 2010 at 7:03

sprehn's user avatar

1

10.4.2 401 Unauthorized

The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information.

Is the LoginRefererUrl correctly formed? As that address isn’t found on google servers however the correctly formed version signs me straight into my mail box.

answered Aug 2, 2010 at 7:11

Confussedinwales's user avatar

I am extracting gmail contacts using opencontactsnet. I get The remote server returned an error: (401) Unauthorized. when executing this line

HttpWebResponse exportResponse = ( HttpWebResponse ) contactsRequest.GetResponse();

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Net;
using System.Web.UI;
using System.Web.UI.WebControls;
using OpenContactsNet;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        GmailExtract gm = new GmailExtract();
        NetworkCredential nw = new NetworkCredential("chendur.pandiya","**");
        MailContactList mc;
        if (gm.Extract(nw, out mc))
        {

        }
        else
        {

        }
     }
}

Here is the complete GmailExtract class,

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Utilities.Web;

namespace OpenContactsNet
{
    public class GmailExtract : IMailContactExtract
    {
        private const string ContinueUrl = "http://mail.google.com/mail?ui=html&amp;zy=l";
        private const string ExportUrl = "https://mail.google.com/mail/contacts/data/export?exportType=ALL&groupToExport=&out=GMAIL_CSV";
        private const string LoginRefererUrl = "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&ltmpl=default&ltmplcache=2";
        private const string LoginUrl = "https://www.google.com/accounts/ServiceLoginAuth?service=mail";
        private const string UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 1.0.3705; .NET CLR 3.0.04506.30)";

        #region IMailContactExtract Members

        public bool Extract( NetworkCredential credential, out MailContactList list )
        {
            bool result = false;
            list = new MailContactList();

            try
            {
                CookieCollection cookies = new CookieCollection();

                // Prepare login form data
                HttpValueCollection loginFormValues = new HttpValueCollection();
                loginFormValues[ "ltmpl" ] = "default";
                loginFormValues[ "ltmplcache" ] = "2";
                loginFormValues[ "continue" ] = ContinueUrl;
                loginFormValues[ "service" ] = "mail";
                loginFormValues[ "rm" ] = "false";
                loginFormValues[ "hl" ] = "en";
                loginFormValues[ "Email" ] = credential.UserName;
                loginFormValues[ "Passwd" ] = credential.Password;
                loginFormValues[ "PersistentCookie" ] = "true";
                loginFormValues[ "rmShown" ] = "1";
                loginFormValues[ "null" ] = "Sign In";

                // Convert to bytes
                byte[] loginPostData = Encoding.UTF8.GetBytes( loginFormValues.ToString( true ) );

                HttpWebRequest loginRequest = ( HttpWebRequest ) WebRequest.Create( LoginUrl );
                loginRequest.Method = "POST";
                loginRequest.UserAgent = UserAgent;
                loginRequest.Referer = LoginRefererUrl;
                loginRequest.ContentType = "application/x-www-form-urlencoded";
                loginRequest.ContentLength = loginPostData.Length;
                loginRequest.AllowAutoRedirect = false;

                // Create cookie container
                loginRequest.CookieContainer = new CookieContainer();

                // Add post data to request
                Stream stream;
                using ( stream = loginRequest.GetRequestStream() )
                {
                    stream.Write( loginPostData, 0, loginPostData.Length );
                }

                HttpWebResponse loginResponse = ( HttpWebResponse ) loginRequest.GetResponse();

                cookies.Add( loginResponse.Cookies );

                // Create request to export Google CSV page
                HttpWebRequest contactsRequest = ( HttpWebRequest ) WebRequest.Create( ExportUrl );
                contactsRequest.Method = "GET";
                contactsRequest.UserAgent = UserAgent;
                contactsRequest.Referer = loginResponse.ResponseUri.ToString();

                // use cookie gotten from login page
                contactsRequest.CookieContainer = new CookieContainer();
                foreach ( Cookie cookie in cookies )
                {
                    contactsRequest.CookieContainer.Add( cookie );
                }

                HttpWebResponse exportResponse = ( HttpWebResponse ) contactsRequest.GetResponse();

                // Read data from response stream
                string csvData;
                using ( Stream responseStream = exportResponse.GetResponseStream() )
                {
                    using ( StreamReader streamRead = new StreamReader( responseStream ) )
                    {
                        csvData = streamRead.ReadToEnd();
                    }
                }

                // parse google csv
                string[] lines = csvData.Split( 'n' );
                foreach ( string line in lines )
                {
                    string[] values = line.Split( ',' );
                    if ( values.Length < 2 )
                    {
                        continue;
                    }

                    MailContact mailContact = new MailContact();
                    mailContact.Email = values[ 1 ];
                    mailContact.Name = values[ 0 ];
                    list.Add( mailContact );
                }

                result = true;
            }
            catch (Exception e)
            {
                throw e;
            }

            return result;
        }

        #endregion
    }
}

asked Aug 2, 2010 at 6:43

ACP's user avatar

I ran into the same problem. I had to change the GmailExtract class in opencontactsnet. Below is the new code which works for me.

public class GmailExtract : IMailContactExtract
    {
        private const string ContinueUrl = "https://mail.google.com/mail/?"; 
        private const string ExportUrl = "https://mail.google.com/mail/contacts/data/export?exportType=ALL&groupToExport=&out=GMAIL_CSV";
        private const string LoginRefererUrl = "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&ltmpl=default&ltmplcache=2";
        private const string LoginUrl = "https://www.google.com/accounts/ServiceLoginAuth?service=mail";
        private const string UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)";

        #region IMailContactExtract Members

        public bool Extract( NetworkCredential credential, out MailContactList list)
        {
            bool result = false;
            list = new MailContactList();

            DateTime jsStartDate = new DateTime(1970, 1, 1);
            TimeSpan endTs = DateTime.Now.Subtract(jsStartDate);
            TimeSpan startTs = DateTime.Now.AddMinutes(-2).Subtract(jsStartDate);

            try
            {
                CookieCollection cookies = new CookieCollection();

                // Prepare login form data
                HttpValueCollection loginFormValues = new HttpValueCollection();
                loginFormValues["Email"] = credential.UserName;
                loginFormValues["Passwd"] = credential.Password;
                loginFormValues["asts"] = "";
                loginFormValues["continue"] = ContinueUrl;
                loginFormValues["dsh"] = "1461574034599761425";
                loginFormValues["hl"] = "en";
                loginFormValues["ltmpl"] = "default";
                loginFormValues["ltmplcache"] = "2";
                loginFormValues["rm"] = "false";
                loginFormValues["rmShown"] = "1";
                loginFormValues["service"] = "mail";
                loginFormValues["signIn"] = "Sign In";
                loginFormValues["scc"] = "1";
                loginFormValues["ss"] = "1";
                loginFormValues["GALX"] = "rBTUs4OAJBI";
                loginFormValues["ltmpl"] = "default";
                loginFormValues["ltmpl"] = "default";

                // Convert to bytes
                byte[] loginPostData = Encoding.UTF8.GetBytes( loginFormValues.ToString( true ) );

                HttpWebRequest loginRequest = ( HttpWebRequest ) WebRequest.Create( LoginUrl );
                loginRequest.Method = "POST";
                loginRequest.UserAgent = UserAgent;
                loginRequest.Referer = LoginRefererUrl;
                loginRequest.ContentType = "application/x-www-form-urlencoded";
                loginRequest.ContentLength = loginPostData.Length;
                loginRequest.AllowAutoRedirect = false;

                // Create cookie container
                loginRequest.CookieContainer = new CookieContainer();
                loginRequest.CookieContainer.Add(new Cookie("GMAIL_LOGIN", "T" + startTs.Milliseconds.ToString() + "/" + startTs.Milliseconds.ToString() + "/" + endTs.Milliseconds.ToString(), "/", ".google.com"));
                loginRequest.CookieContainer.Add(new Cookie("GALX", "rBTUs4OAJBI", "/accounts", ".google.com"));

                // Add post data to request
                Stream stream;
                using ( stream = loginRequest.GetRequestStream())
                {
                    stream.Write( loginPostData, 0, loginPostData.Length);
                }

                HttpWebResponse loginResponse = ( HttpWebResponse ) loginRequest.GetResponse();

                cookies.Add( loginResponse.Cookies );

                // Create request to export Google CSV page
                HttpWebRequest contactsRequest = ( HttpWebRequest ) WebRequest.Create( ExportUrl );
                contactsRequest.Method = "GET";
                contactsRequest.UserAgent = UserAgent;
                contactsRequest.Referer = loginResponse.ResponseUri.ToString();

                // use cookie gotten from login page
                contactsRequest.CookieContainer = new CookieContainer();
                foreach ( Cookie cookie in cookies )
                {
                    contactsRequest.CookieContainer.Add( cookie );
                }

                HttpWebResponse exportResponse = ( HttpWebResponse ) contactsRequest.GetResponse();

                // Read data from response stream
                string csvData;
                using ( Stream responseStream = exportResponse.GetResponseStream())
                {
                    using ( StreamReader streamRead = new StreamReader( responseStream ) )
                    {
                        csvData = streamRead.ReadToEnd();
                    }
                }

                // parse google csv
                string[] lines = csvData.Split( 'n' );
                foreach ( string line in lines )
                {
                    string[] values = line.Split( ',' );
                    if ( values.Length < 2 )
                    {
                        continue;
                    }

                    MailContact mailContact = new MailContact();
                    mailContact.Email = values[ 28 ];
                    mailContact.Name = values[ 0 ];
                    if (mailContact.Email.Trim().Length > 0)
                    {

                         list.Add(mailContact);

                    }
                }

                result = true;
            }
            catch
            {
            }

            return result;
        }

        #endregion
    }

answered Aug 2, 2010 at 7:31

ajay_whiz's user avatar

ajay_whizajay_whiz

17.3k3 gold badges36 silver badges44 bronze badges

5

I am not familiar with google’s api nor do I know C#.
However check the URL you are sending your form to.
Looks like your authentication works. Otherwise you would have recieved a 403.
401 means that you (as an authenticated user) are not allowed to access the requested resource.

answered Aug 2, 2010 at 7:03

sprehn's user avatar

1

10.4.2 401 Unauthorized

The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information.

Is the LoginRefererUrl correctly formed? As that address isn’t found on google servers however the correctly formed version signs me straight into my mail box.

answered Aug 2, 2010 at 7:11

Confussedinwales's user avatar

Три года назад с целью автоматизации управления организационно-распорядительной документацией была приобретена система elma. Но после года эксплуатации стало понятно, что от нее придется отказаться.

Рассказ о том, как я ушел от elma к easla.com.

Прежде, чем приобрести elma был проведен тщательный анализ системы на адекватность поставленным задачам. Понравилось в системе следующее:

  • Современный веб-интерфейс
  • Возможность настройки бизнес-процессов с помощью блок-схем
  • Возможность написания кода на C#.

Жаль, что не смог увидеть подводных камней сразу. Не буду сильно вдаваться в подробности, но месяца через три после начала эксплуатации появились проблемы разного плана. Прежде всего, меня конечно беспокоили технические проблемы, например:

  • Крайне сложно именовать файлы объекта программно (помнится, техподдержка предложила для этого написать больше сотни строк кода в разных событиях), правда месяца через два разработчики исправили эту проблему.
  • Проблемы при создании процессов с ветвлениями. Был создан процесс рассмотрения входящего письма, который ветвился в соответствии с количеством ответственных исполнителей. Кода в процессе практически не было. Однако регулярно появлялись задачи-фантомы — я их так назвал. Назначено 5 задач, а получается 10. Решить проблему с помощью техподдержки не удалось и мне пришлось писать «костыли», которые уничтожали фантомов программно. Но все равно в непредсказуемых ситуациях они проявлялись.
  • Разработка новых процессов была возможна только на отдельном, тестовом сервере, для которого регулярно приходилось выпрашивать лицензию, т.к. она не включена в поставку. Готовый процесс приходилось вручную переносить с тестового сервера на боевой. При этом боевой сервер приходилось перезапускать. В рабочее время такое невозможно, что приводило к регулярному переносу рабочего времени на ночь.
  • Каждое обновление приносило свои исправления и свои баги. Однажды, обновление принесло баг, который был исправлен 2-3 обновления назад. Причем порой ошибки были смешные — детские. Например, два обновления подряд не могли главное меню развернуть на всю высоту браузера.

Были и другие проблемы. Но то, технические проблемы, которые конечных пользователей не касаются.
Однако и пользователи тоже регулярно жаловались на неудобства, например:

  • Поиск объектов осуществляется только на отдельной странице, что вроде бы логично, и даже критерии поиска можно вводить весьма сложные, но для конечного пользователя этот функционал оказался неудобным. Все давно привыкли, что искать удобно указывая критерии в шапке таблицы, а переход на отдельную страницу и многоходовой ввод критериев вызывал недовольство и отторжение.
  • Elma, работая в локальной сети, начала удивлять своей задумчивостью. Мы изучили систему изнутри. Оказалось, что для каждого объекта система создает отдельную таблицу и еще кучку смежных таблиц для хранения данных, т.е. торможения быть не должно. Однако, когда количество записей каждого объекта превысило тысяч пять, тормоза стали заметны на интуитивном уровне. Странички со списком открывались несколько секунд.

После года эксплуатации elma стало понятно, что система приведет организацию в тупик. Мы не сможем реализовать на ней другие процессы без деградации производительности. И нет гарантии, что реализовав процессы, они будут работать стабильно, учитывая постоянно «вылезающие баги». Все преимущества системы сошли на нет.

Поиск

Был осуществлен поиск системы взамен elma. Одним из критериев поиска была ее бесплатность или дешевизна, т.к. руководство организации не хотело тратиться на покупку новой системы, а мне, как руководителю отдела ИТ принявшему в свое время решение о приобретении elma и обосновав ее приобретение было стыдно в очередной раз просить деньги на тоже самое. Также, в списке критериев были:

  • Привычный пользователю веб-интерфейс
  • Разработка и изменение процессов в реальном времени
  • Гибкость хранения файлов
  • Возможность импорт данных из elma в новую систему.

Как раз easla.com подошла по всем пунктам.

Разработка

После регистрации в системе начал разработку соответствующих бизнес-процессов. Причем атрибуты объектов пришлось реализовывать так, чтобы они могли принимать импортируемые данные из elma.
Потребовалось реализовать четыре процесса:

  • Заказчики
  • Договоры
  • Переписка
  • Задачи.

Процесс «Заказчики» сложно назвать процессом. У объектов нет даже статусов. Фактически – это каталог контрагентов и контактов связанных между собой. Но контрагент отличается от всех других объектов числом атрибутов. Он позволяет хранить не только наименование, но и юридический, и почтовый адреса, а также банковские реквизиты. Всего 40 атрибутов! Контакт – это физическое лицо являющееся сотрудником контрагента.
Процесс «Договоры» в тот момент тоже представлял собой простой каталог договоров. Он был нужен исключительно для классификации писем.
Процесс «Переписка» – очень важный для организации процесс. Он управляет официальной входящей и исходящей корреспонденцией, которая влияет на принятие технических решений и участвует в разрешении конфликтных ситуации в суде. Входящие письма могут принести убытки из-за несвоевременного рассмотрения или ответа. Исходящие письма могут приносить

шести-, а иногда и семизначную прибыль

при их своевременной отправке. Важными отличиями объекта «Исходящий документ» являются:

  • Способ хранения файла письма
  • Способ хранения прилагаемых документов
  • Возможность разработки письма онлайн
  • Возможность отправки письма одним из десятка способов.

Процесс «Задачи» важен точно также, как «Переписка», т.к. является его логическим продолжением. С помощью задач осуществляется контроль исполнения поручений по каждому входящему или исходящему документу. Кроме этого, в каждой задаче осуществляется регистрация трудозатрат в минутах и связка с входящим и исходящим письмом.
Разработку процессов закончил за месяц и встал вопрос собственно импорта данных. Но прежде – экспорта из elma.

Экспорт-импорт

Импорт в easla.com обладает некоторыми особенностями, которые надо учитывать:

  • Первая строка файла с данными может содержать обозначения атрибутов
  • Можно импортировать только 1000 записей за один раз
  • Нескольких значений для одного атрибута надо разделить символом «|»
  • Импортируемые файлы должны иметь разные имена.

Штатных средств выгрузки данных из elma не нашел, поэтому пришлось лезть в базу данных. В базе elma море разных таблиц, необходимые таблицы были найдены интуитивно. Все-таки программисты мыслят одинаково.
Начал экспорт с простых объектов. Сперва контрагенты. Написал вот такой SQL запрос:

ELMA_export_contragents.sql

SELECT DISTINCT 
	   [ELMA].[dbo].[Contractor].[Name] AS [crm_management_contragent_name]
	  ,[LF].[LongName] AS [crm_management_contragent_opf]	  
      ,[ELMA].[dbo].[ContractorType].[Name] AS [crm_management_contragent_type]
      ,[Site] AS [crm_management_contragent_url]
      ,[crm_management_contragent_email] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Email].[EmailString]
		FROM [ELMA].[dbo].[Contractor_Email]
		LEFT OUTER JOIN [ELMA].[dbo].[Email] ON [ELMA].[dbo].[Email].[Id] = [ELMA].[dbo].[Contractor_Email].[Email]
		WHERE [ELMA].[dbo].[Contractor_Email].[Contractor] = [ELMA].[dbo].[Contractor].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
	  ,[Fax] AS [crm_management_contragent_fax]	
      ,[crm_management_contragent_phone] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Phone].[PhoneString]
		FROM [ELMA].[dbo].[Contractor_Phone]
		LEFT OUTER JOIN [ELMA].[dbo].[Phone] ON [ELMA].[dbo].[Phone].[Id] = [ELMA].[dbo].[Contractor_Phone].[Phone]
		WHERE [ELMA].[dbo].[Contractor_Phone].[Contractor] = [ELMA].[dbo].[Contractor].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
      ,[LAC].[Name] AS [crm_management_contragent_legal_country]
      ,[LA].[Region] AS [crm_management_contragent_legal_region]
      ,[LA].[District] AS [crm_management_contragent_legal_district]
      ,[LA].[City] AS [crm_management_contragent_legal_city]
      ,[LA].[Locality] AS [crm_management_contragent_legal_locality]
      ,[LA].[Street] AS [crm_management_contragent_legal_street]
      ,[LA].[Building] AS [crm_management_contragent_legal_house]
      ,[LA].[Stroenie] AS [crm_management_contragent_legal_building]
      ,[LA].[Korpus] AS [crm_management_contragent_legal_corp]
      ,[LA].[Appartment] AS [crm_management_contragent_legal_apartment]
      ,[LA].[Zip] AS [crm_management_contragent_legal_postcode]     
      ,[PAC].[Name] AS [crm_management_contragent_post_country]
      ,[PA].[Region] AS [crm_management_contragent_post_region]
      ,[PA].[District] AS [crm_management_contragent_post_district]
      ,[PA].[City] AS [crm_management_contragent_post_city]
      ,[PA].[Locality] AS [crm_management_contragent_post_locality]
      ,[PA].[Street] AS [crm_management_contragent_post_street]
      ,[PA].[Building] AS [crm_management_contragent_post_house]
      ,[PA].[Stroenie] AS [crm_management_contragent_post_building]
      ,[PA].[Korpus] AS [crm_management_contragent_post_corp]
      ,[PA].[Appartment] AS [crm_management_contragent_post_apartment]
      ,[PA].[Zip] AS [crm_management_contragent_post_postcode]
      ,[INN] AS [crm_management_contragent_inn]
      ,[ELMA].[dbo].[ContractorLegal].[KPP] AS [crm_management_contragent_kpp]
      ,[ELMA].[dbo].[ContractorLegal].[OGRN] AS [crm_management_contragent_ogrn]
      ,[ELMA].[dbo].[ContractorLegal].[BIK] AS [crm_management_contragent_bik]
      ,[ELMA].[dbo].[ContractorLegal].[BANK] AS [crm_management_contragent_bank]
      ,[ELMA].[dbo].[ContractorLegal].[KS] AS [crm_management_contragent_ks]
      ,[ELMA].[dbo].[ContractorLegal].[RS] AS [crm_management_contragent_rs]         
  FROM [ELMA].[dbo].[Contractor]
  LEFT OUTER JOIN [ELMA].[dbo].[ContractorType] ON [ELMA].[dbo].[ContractorType].[Id] = [ELMA].[dbo].[Contractor].[Type]
  LEFT OUTER JOIN [ELMA].[dbo].[ContractorLegal] ON [ELMA].[dbo].[ContractorLegal].[Id] = [ELMA].[dbo].[Contractor].[Id]
  LEFT OUTER JOIN [ELMA].[dbo].[Address] AS [LA] ON [LA].[Id] = [ELMA].[dbo].[Contractor].[LegalAddress]
  LEFT OUTER JOIN [ELMA].[dbo].[Country] AS [LAC] ON [LAC].[Id] = [LA].[Country]
  LEFT OUTER JOIN [ELMA].[dbo].[Address] AS [PA] ON [PA].[Id] = [ELMA].[dbo].[Contractor].[PostalAddress]
  LEFT OUTER JOIN [ELMA].[dbo].[Country] AS [PAC] ON [PAC].[Id] = [PA].[Country]
  LEFT OUTER JOIN [ELMA].[dbo].[LegalForm] AS [LF] ON [LF].[Id] = [ELMA].[dbo].[ContractorLegal].[LegalForm]
  
  WHERE [ELMA].[dbo].[Contractor].[IsDeleted] = 0 AND [ELMA].[dbo].[Contractor].[Name] IS NOT NULL AND [ELMA].[dbo].[Contractor].[id] > 500

Несколько значений для одного атрибута объединил в одно с помощью STUFF(…). Результат запроса сохранил в формате csv с разделителем «;». Первой строкой в файле добавил обозначения атрибутов в easla.com. Загрузил файл в разделе «Импорт объектов». Потом указал кодировку файла и пользователя, от имени которого выполнить импорт. Запустил импорт. Процедура импорта не очень быстрая, на создание каждого объекта может уходить порядка одной секунды. Количество импортированных записей было примерно 500. Выглядело это примерно так:

Теперь контакты. Написал вот такой SQL запрос:

ELMA_export_contacts.sql

SELECT 
	   [Surname] AS [crm_management_contact_lastname]
      ,[Firstname] AS [crm_management_contact_firstname]
      ,[Middlename] AS [crm_management_contact_middlename]
      ,[ELMA].[dbo].[Contractor].[Name] AS [crm_management_contact_contragent]
      ,[Department] AS [cnt_management_contact_department]
      ,[Position] AS [cnt_management_contact_position]
      ,[crm_management_contact_email] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Email].[EmailString]
		FROM [ELMA].[dbo].[Contact_Email]
		LEFT OUTER JOIN [ELMA].[dbo].[Email] ON [ELMA].[dbo].[Email].[Id] = [ELMA].[dbo].[Contact_Email].[Email]
		WHERE [ELMA].[dbo].[Contact_Email].[Contact] = [ELMA].[dbo].[Contact].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
      ,[crm_management_contact_phone] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Phone].[PhoneString]
		FROM [ELMA].[dbo].[Contact_Phone]
		LEFT OUTER JOIN [ELMA].[dbo].[Phone] ON [ELMA].[dbo].[Phone].[Id] = [ELMA].[dbo].[Contact_Phone].[Phone]
		WHERE [ELMA].[dbo].[Contact_Phone].[Contact] = [ELMA].[dbo].[Contact].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
	  ,CASE WHEN [Year] IS NULL THEN NULL ELSE CONVERT(varchar, [Birthday],104) END AS [crm_management_contact_birthday]
	  ,[RAC].[Name] AS [crm_management_contact_country]
      ,[RA].[Region] AS [crm_management_contact_region]
      ,[RA].[District] AS [crm_management_contact_district]
      ,[RA].[City] AS [crm_management_contact_city]
      ,[RA].[Locality] AS [crm_management_contact_locality]
      ,[RA].[Street] AS [crm_management_contact_street]
      ,[RA].[Building] AS [crm_management_contact_house]
      ,[RA].[Stroenie] AS [crm_management_contact_building]
      ,[RA].[Korpus] AS [crm_management_contact_corp]
      ,[RA].[Appartment] AS [crm_management_contact_apartment]
      ,[RA].[Zip] AS [crm_management_contact_postcode]	         
  FROM [ELMA].[dbo].[Contact]
  LEFT OUTER JOIN [ELMA].[dbo].[Contractor] ON [ELMA].[dbo].[Contractor].[Id] = [ELMA].[dbo].[Contact].[Contractor]
  LEFT OUTER JOIN [ELMA].[dbo].[Address] AS [RA] ON [RA].[Id] = [ELMA].[dbo].[Contact].[RegistrationAddress]
  LEFT OUTER JOIN [ELMA].[dbo].[Country] AS [RAC] ON [RAC].[Id] = [RA].[Country]
  WHERE [ELMA].[dbo].[Contact].[Id] > 1919

Все действия аналогичны предыдущему импорту. Особенность импорта контактов после контрагентов заключалась в том, что контакт обладает атрибутом «Контрагент», который ссылается на контрагента. Поэтому, в первую очередь были импортированы контрагенты, а за ними контакты. При импорте контактов в поле «Контрагент» easla.com

находила и подставляла ссылки на контрагентов

! Количество импортированных записей было примерно 1800.
После импорта контрагентов и контактов получилась структурированная база данных, в которой все контакты принадлежат определенным контрагентам. На импорт данных ушло примерно 2 часа. Причем половину времени потратил на разработку SQL запросов. В результате получил две готовые и взаимосвязанные таблицы.
Реестр контрагентов:

Реестр контактов:

На очереди стоял импорт договоров. Выгрузил их с помощью вот такого SQL запроса:

ELMA_export_contracts.sql

SELECT 
      [RegYear] AS [agr_management_contract_year]
      ,[RegNum] AS [agr_management_contract_num]
      ,[RegAppendixFront] AS [agr_management_contract_appendix_front]
      ,[RegAppendixBack] AS [agr_management_contract_appendix_back]
      ,[RegCode]
      ,[ELMA].[dbo].[Contractor].[Name] AS [agr_management_contract_contragent]
      ,'"'+REPLACE(REPLACE(REPLACE([Title],CHAR(10),''),CHAR(13),''),';',',')+'"' AS [agr_management_contract_title]
      ,CONVERT(varchar, [RegDate],104) AS [agr_management_contract_reg_date]
      ,CONVERT(varchar, [SignDate],104) AS [agr_management_contract_sign_date]
      ,[PM1].[EMail] AS [agr_management_contract_project_manager]
      ,[PM2].[EMail] AS [agr_management_contract_project_manager_helper]
      ,agr_management_contract_fields = STUFF((
		SELECT '|' + [F1].[Title]
		FROM [ELMA].[dbo].[Project_Fields]
		LEFT OUTER JOIN [ELMA].[dbo].[Field] AS [F1] ON [F1].[Id] = [ELMA].[dbo].[Project_Fields].[Field]
		WHERE [ELMA].[dbo].[Project_Fields].[Parent] = [ELMA].[dbo].[Project].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
  FROM [ELMA].[dbo].[Project]
  LEFT JOIN [ELMA].[dbo].[Contractor] ON [ELMA].[dbo].[Contractor].[Id] = [ELMA].[dbo].[Project].[Contragent]
  LEFT JOIN [ELMA].[dbo].[User] AS [PM1] ON [PM1].[Id] = [ELMA].[dbo].[Project].[ProjectManager]
  LEFT JOIN [ELMA].[dbo].[User] AS [PM2] ON [PM2].[Id] = [ELMA].[dbo].[Project].[ProjectManagerHelper]

Все действия также аналогичны предыдущему импорту. И точно также, как с контактами, все договоры обладая атрибутом «Контрагент» при импорте связались с соответствующими контрагентами. Количество импортированных записей было немногим больше 200.

Вот теперь, когда все контрагенты, контакты и договоры, на которые ссылаются входящие и исходящие документы находились в easla.com, можно было приступить к импорту переписки.
Количество входящих и исходящих писем было большим — примерно 5400 и 5300 соответственно.
Интересно то, что входящие и исходящие письма ссылаются друг на друга, т.е. исходящее может быть отправлено в ответ на входящее и информации об этом сохраняется в соответствующем атрибуте исходящего документа. Входящий документ может быть получен в ответ на исходящий и информация об этом хранится в соответствующем атрибуте входящего документа. Таким образом, при импорте одного из типов объектов обеспечить формирование всех связей

невозможно

. Первыми были импортированы входящие документы, но перед этим, тип атрибута хранящего ссылку на исходящий документ был изменен с «Объект» на «Строка». Это позволило сохранить в атрибуте описание исходящего документа, которого пока нет в базе данных и использовать его позже, после импорта исходящих документов. В конечном счете, для выгрузки входящих документов получился вот такой SQL запрос:

ELMA_export_incomings.sql

SELECT 
       CASE [DocMethod] WHEN 1 THEN 'Эл. письмо' WHEN 2 THEN 'Бумажное письмо' WHEN 3 THEN 'Факсимиле' WHEN 4 THEN 'Передан лично' END AS [crs_management_incoming_method]
      ,[ELMA].[dbo].[Contractor].[Name] AS [crs_management_incoming_contragent]
      ,[ELMA].[dbo].[Contact].[Surname] + ' ' + SUBSTRING([ELMA].[dbo].[Contact].[Firstname],1,1) + '.' + SUBSTRING([ELMA].[dbo].[Contact].[Middlename],1,1) + '.' AS [crs_management_incoming_contact]
      ,[crs_management_incoming_performers] = STUFF((
		SELECT '|' + [C1].[Surname] + ' ' + SUBSTRING([C1].[Firstname],1,1) + '.' + SUBSTRING([C1].[Middlename],1,1) + '.'
		FROM [ELMA].[dbo].[IncomingDoc_Performers]
		LEFT OUTER JOIN [ELMA].[dbo].[Contact] AS [C1] ON [C1].[Id] = [ELMA].[dbo].[IncomingDoc_Performers].[Performer]
		WHERE [ELMA].[dbo].[IncomingDoc_Performers].[Parent] = [ELMA].[dbo].[IncomingDoc].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
      ,CONVERT(varchar, [ELMA].[dbo].[IncomingDoc].[ContragentDate], 104) AS [crs_management_incoming_contragent_date]
      ,[ELMA].[dbo].[IncomingDoc].[ContragentRegNum] AS [crs_management_incoming_contragent_regnum]
      ,CONVERT(VARCHAR,[ELMA].[dbo].[IncomingDoc].[ReceiveDate],20) AS [crs_management_incoming_receive_date]
      ,[ELMA].[dbo].[IncomingDoc].[ReceiveOriginalDate] AS [crs_management_incoming_receive_original_date]
      ,[ReceiveOriginalDateFlag] AS [crs_management_incoming_receive_original_flag]
      ,[ELMA].[dbo].[IncomingDoc].[ReceiveRegNum] AS [crs_management_incoming_receive_regnum]
      ,REPLACE(REPLACE([ELMA].[dbo].[IncomingDoc].[Subj],CHAR(13),''),CHAR(10),'') AS [crs_management_incoming_subj]
      ,CASE [ELMA].[dbo].[IncomingDoc].[DocType] 
		WHEN 0 THEN 'Задания'
		WHEN 1 THEN 'Замечания'
		WHEN 2 THEN 'Ответы на замечания'
		WHEN 3 THEN 'Запрос исходных данных'
		WHEN 4 THEN 'Выдача исходных данных'
		WHEN 5 THEN 'Запрос согласования'
		WHEN 6 THEN 'Согласование ранее направленных материалов'
		WHEN 7 THEN 'Запрос информации'
		WHEN 8 THEN 'Пожелания контрагента'		
		WHEN 9 THEN 'Претензия'
		WHEN 13 THEN 'Постановление'
		WHEN 14 THEN 'Отзыв'
		WHEN 17 THEN 'Ходатайство'
		WHEN 15 THEN 'Определение'
		WHEN 10 THEN 'Приглашение'
		WHEN 18 THEN 'О подтверждении технической возможности'
		WHEN 11 THEN 'Запрос коммерческого предложения'
		WHEN 12 THEN 'Договорная документация'
		WHEN 16 THEN 'Коммерческое предложение'
		WHEN 99 THEN 'Прочее'
		END AS [crs_management_incoming_content]
      ,[U1].[UserName]+'@sngp.ru' AS [crs_management_incoming_to]
      ,[U2].[UserName]+'@sngp.ru' AS [crs_management_incoming_forwardto]
      ,[ELMA].[dbo].[OutgoingDoc].[RegNum] AS [crs_management_incoming_outgoing]
      ,[ELMA].[dbo].[Project].[RegCode] AS [crs_management_incoming_contract]
	  ,[crs_management_incoming_attachments] = STUFF((
		SELECT '|' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(LTRIM(STR([F0].[Id]) + ' ' + [F0].[Name]),'«',''),'»',''),'–','-'),'.zip.zip','.zip'),'.docx','.docx'),'  ',' ') 
		FROM [ELMA].[dbo].[IncomingDoc_DocAttachments]
		LEFT OUTER JOIN [ELMA].[dbo].[FS_FILES] AS [F0] ON [F0].[Uid] = [ELMA].[dbo].[IncomingDoc_DocAttachments].[DocAttachment]		
		WHERE [ELMA].[dbo].[IncomingDoc_DocAttachments].[Parent] = [ELMA].[dbo].[IncomingDoc].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
	  ,LTRIM(STR(ISNULL([F1].[Id],[F2].[Id]))) + REVERSE(SUBSTRING(REVERSE(ISNULL([F1].[Name],[F2].[Name])), 0, CHARINDEX('.',REVERSE(ISNULL([F1].[Name],[F2].[Name]))) + 1)) AS [crs_management_incoming_document]
	  ,[S].[Name] AS [status]
  FROM [ELMA].[dbo].[IncomingDoc]
  LEFT OUTER JOIN [ELMA].[dbo].[Contractor] ON [ELMA].[dbo].[Contractor].[Id] = [ELMA].[dbo].[IncomingDoc].[Contragent]
  LEFT OUTER JOIN [ELMA].[dbo].[Contact] ON [ELMA].[dbo].[Contact].[Id] = [ELMA].[dbo].[IncomingDoc].[Contact]
  LEFT JOIN [ELMA].[dbo].[User] AS [U1] ON [U1].[Id] = [ELMA].[dbo].[IncomingDoc].[To]
  LEFT JOIN [ELMA].[dbo].[User] AS [U2] ON [U2].[Id] = [ELMA].[dbo].[IncomingDoc].[ForwardTo]
  LEFT JOIN [ELMA].[dbo].[Project] ON [ELMA].[dbo].[Project].[Id] = [ELMA].[dbo].[IncomingDoc].[Project]
  LEFT JOIN [ELMA].[dbo].[OutgoingDoc] ON [ELMA].[dbo].[OutgoingDoc].[Id] = [ELMA].[dbo].[IncomingDoc].[OutgoingDoc]
  LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV1] ON [DV1].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV1].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 1
  LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV2] ON [DV2].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV2].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 0
  LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F1] ON [F1].[Id] = [DV1].[File]  
  LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F2] ON [F2].[Uid] = [DV2].[File]  
  LEFT JOIN [ELMA].[dbo].[Document] ON [ELMA].[dbo].[Document].[Id] = [ELMA].[dbo].[IncomingDoc].[Id]
  LEFT JOIN [ELMA].[dbo].[LifeCycleStatus] AS [S] ON [S].[Id] = [ELMA].[dbo].[Document].[Status]
  WHERE --[ELMA].[dbo].[IncomingDoc].[Subj] NOT LIKE 'тест%' AND [ELMA].[dbo].[IncomingDoc].[Subj] NOT LIKE 'test%'
  [ELMA].[dbo].[IncomingDoc].[Id] > 12193
  ORDER BY [ELMA].[dbo].[IncomingDoc].[ReceiveDate]

Кстати, осложнялась ситуация еще и тем, что вместе с данными нужно было выгрузить и импортировать все файлы.
Совершенной неожиданностью стало то, что разработчики elma в какой-то момент изменили способ хранения файлов, поэтому пришлось создавать два разных запроса и объединять их вместе для выгрузки файлов. При первой попытке выгрузки возникла проблема. Имена некоторых файлов повторялись и перезаписывали друг друга. Пришлось изменить в запросе имя конечного файла, добавив к нему id. Кроме, собственно, файла и его имени нужно было перенести в easla.com и дополнительные данные, хранящиеся вместе с файлом. Их тоже пришлось вписать в имя файла. Таким образом, конечное имя файла формировалось по принципу: id data filename.ext. Так как elma хранит файлы в отдельном каталоге, результат запроса планировалось преобразовать в bat файл для выгрузки файлов в нужное место. В конечном счете, для выгрузки файлов входящих документов получился вот такой запрос:

ELMA_export_incoming_files.sql

SELECT 
'copy "\ssv11c$ELMA3-Standart.cfgUserConfigFiles' + [FNAME] + '" "c:tempelmaincoming' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL([ENDNAME],[FNAME]),'«',''),'»',''),'–','-'),'.zip.zip','.zip'),'.docx','.docx'),'  ',' ') + '"'
FROM (
	SELECT [ELMA].[dbo].[IncomingDoc].[Id] AS [Id], [ELMA].[dbo].[IncomingDoc].[Subj] AS [Subj], [ELMA].[dbo].[IncomingDoc].[ReceiveDate] AS [RD], LTRIM(STR([F0].[Id])) + REVERSE(SUBSTRING(REVERSE([F0].[Name]), 0, CHARINDEX('.',REVERSE([F0].[Name])) + 1)) AS [FNAME], LTRIM(STR([F0].[Id]) + ' ' + [Name]) AS [ENDNAME]
	FROM [ELMA].[dbo].[IncomingDoc]
    LEFT JOIN [ELMA].[dbo].[IncomingDoc_DocAttachments] ON [ELMA].[dbo].[IncomingDoc_DocAttachments].[Parent] = [ELMA].[dbo].[IncomingDoc].[Id]
    LEFT OUTER JOIN [ELMA].[dbo].[FS_FILES] AS [F0] ON [F0].[Uid] = [ELMA].[dbo].[IncomingDoc_DocAttachments].[DocAttachment]	    
	UNION
	
	SELECT [ELMA].[dbo].[IncomingDoc].[Id] AS [Id], [ELMA].[dbo].[IncomingDoc].[Subj] AS [Subj], [ELMA].[dbo].[IncomingDoc].[ReceiveDate] AS [RD], LTRIM(STR(ISNULL([F1].[Id],[F2].[Id]))) + REVERSE(SUBSTRING(REVERSE(ISNULL([F1].[Name],[F2].[Name])), 0, CHARINDEX('.',REVERSE(ISNULL([F1].[Name],[F2].[Name]))) + 1)) AS [FNAME], NULL AS [ENDNAME]
	FROM [ELMA].[dbo].[IncomingDoc]
    LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV1] ON [DV1].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV1].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 1
    LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV2] ON [DV2].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV2].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 0
    LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F1] ON [F1].[Id] = [DV1].[File]  
    LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F2] ON [F2].[Uid] = [DV2].[File]  
) AS [F]
WHERE [FNAME] IS NOT NULL 
ORDER BY [RD]

Загрузил csv файл, загрузил все файлы входящих. Процедура оказалась долгой, т.к. общий объем файлов был несколько гигабайт. Хорошо, что импорт данных по 1000 записей, т.к. без накладок не обошлось. Обязательно в каждой тысяче всплывало по 10-15 ошибок. Выявить ошибки удалось перед процедурой импорта, с помощью предварительного просмотра. Очень удобно. В общем, каждая тысяча требовала предварительной подготовки.
Таким же образом импортировал все исходящие документы.
После этого, в объектах была написана процедура преобразования имен файлов. Она удаляла id, а data, переносила в revdata файла в easla.com. Таким образом, файлы приложений получили исходные имена filename.ext.

function updateAttachmentsFileName()
{
    $files = cobjectref()->attributeref('crs_management_incoming_attachments')->availableFiles();
    foreach ($files as $f)
    {
        $parts = explode(' ', $f->nowname, 2);
        if (count($parts) == 2)
        {
            $f->nowname = $parts[1];
            $f->save();
        }
    }
}

Специально для входящих писем была написана процедура, которая заменяла описания ссылок на исходящие документы на их идентификаторы.

function updateOutgoing()
{
    if (empty(cobjectref()->attributeref('crs_management_incoming_outgoing')->value))
        return;
        
    $outgoing_doc = selectAll(      
        'crs_management',
        'crs_management_outgoing',
        array(),
        array('crs_management_outgoing_regnum'=>cobjectref()->attributeref('crs_management_incoming_outgoing')->value)
    );
    
    if (empty($outgoing_doc))
        return;
        
    cobjectref()->attributeref('crs_management_incoming_outgoing')->value = $outgoing_doc['id'];
}

Проверив работу этих процедур запустил пакетное обновление объектов. Медленно, но верно easla.com обновила все объекты! После этого, изменил тип атрибута ссылающегося на исходящий документ во входящем документе со «Строка» на «Объект», чтобы идентификаторы объекта стали объектами.
Таким образом, easla.com переименовала файлы и организовала

перекрестные ссылки

между входящими и исходящими документами!
В целом, процедура экспорта и импорта заняла примерно 3 рабочих дня. Загрузку файлов на easla.com осуществлял по вечерам, когда канал Интернет был свободен. Импорт данных по 1000 был удобен еще и потому, что старые письма можно было импортировать сразу, не беспокоясь о целостности данных. И только перед «боевым» запуском загрузил и импортировал остатки – последние пару сотен писем.
Миграцию осуществил в конце 2014 года, а запустил в эксплуатацию все описанные бизнес-процессы 12 января 2015 года.
Прошло уже больше года. Общий объем писем превысил 20 тысяч. Количество задач перевалило за 10 тысяч. Вот свежие данные из главного меню:

Итоги

Могу с уверенностью сказать, что год назад все сделал правильно. Вот основные выгоды:

  • Время на регистрацию писем сократилось до секунд или минут
  • Время на отправку исходящего письма сократилось с 30-40 минут до секунд
  • Появилась возможность размещать файлы исходящих писем на файлообменнике easla.com
  • Разработка письма стала проще, т.к. теперь файл в формате docx хранится в объекте easla.com, а не где попало у пользователя
  • Связь задач и писем позволяет формировать и выгружать сложные отчеты, которые приносят организации прибыль
  • Получил развитие процесс управления договорами, если раньше он был простым каталогом, то теперь он настоящий процесс со статусами, контролем выполнения, подписанием актов и поступлением средств.

В настоящий момент развитие получили и другие процессы: управление задачам, согласованиями, субподрядными договорами. Все то, что опасались ранее делать в elma, теперь сделано в easla.com!

P.S. Прошу не расценивать статью как антирекламу elma. Система не подошла нам, но вполне может подойти другим, если они не будут «выжимать из нее соки», как мы.

Страница с ошибкой при обращении к WordPress-сайту всегда вызывает неудобства, вне зависимости от того, ваш это сайт или чужой. Как и в случае со многими другими кодами ответов HTTP, ошибка 401 не содержит детальных данных для диагностики и решения проблемы.

Ошибка 401 может появиться в любом браузере. В большинстве случаев ее легко решить.

В этой статье мы расскажем, что означает 401 ошибка, почему она происходит, и какие методы ее устранения существуют.

Итак, приступим!

Содержание

  1. Код ошибки 401 – что это?
  2. Что вызывает ошибку 401
  3. Как исправить ошибку 401 (5 методов)

Код ошибки 401 – что это?

Коды состояния HTTP 400 возникают в случае проблем с выполнением запросов. В частности, ошибка 401 появляется, когда браузер отказывает вам в доступе к странице, которую вы хотите посетить.

В результате вместо загрузки страниц браузер выведет сообщение об ошибке. Ошибки 401 могут возникать в любом браузере, потому отображаемое сообщение может варьироваться.

К примеру, в Chrome и Edge вы, скорее всего, увидите иконку бумаги с простым сообщением о том, что запрашиваемая страница не отвечает. Вы увидите фразу «HTTP Error 401». Вам будет предложено связаться с владельцем сайта, если ошибка не пропадет:

В иных случаях и в других браузерах вы можете получить менее дружелюбное предупреждение. К примеру, может выводиться пустая страница с сообщением «401 Authorization Required»:

Другие вариации текста:

  • HTTP 401 Error – Unauthorized
  • 401 Unauthorized
  • Access Denied

Эти ошибки часто появляются на сайтах, где требуется вводить данные для входа. В большинстве случаев это означает, что что-то не так с учетными данными. Возможно, браузер перестал считать их действительными.

Эта ошибка похожа на HTTP 403 Forbidden Error, когда доступ к сайту для пользователя запрещен. Однако, в отличие от ошибки 403, сообщение об ошибке 401 указывает, что процесс аутентификации завершился неудачно.

Код ошибки передается через заголовок WWW-Authenticate, который отвечает за определение метода аутентификации, используемого для предоставления доступа к веб-странице или ресурсу.

Что вызывает ошибку 401

Если вы столкнулись с кодом ошибки в кодах 400, вы должны знать, что проблема произошла на стороне клиента (либо на стороне браузера). Случается, что виновником проблемы является браузер, но так бывает не всегда. Об этом мы еще расскажем позже.

Ошибки 401 возникают на ресурсах с ограниченным доступом – к примеру, на страницах, защищенных паролем. Потому можно предположить, что причина проблемы связана с данными аутентификации.

Устаревшие Cookie и кэш браузера

Одной из наиболее распространенных причин возникновения ошибки 401 является то, что кэш и файлы cookie вашего браузера устарели, что не позволяет выполнить авторизацию. Если ваш браузер использует недействительные данные для авторизации (либо вообще их не использует их), сервер отклонит запрос.

Несовместимые плагины

Также бывают ситуации, когда ошибка вызвана несовместимостью плагинов или какими-либо сбоями в них. К примеру, плагин безопасности может ошибочно принять вашу попытку входа за вредоносную активность, а потому будет возвращена ошибка 401 для защиты страницы.

Неверный URL или устаревшая ссылка

Бывает, что источником проблемы является незначительная оплошность. К примеру, был неверно введен URL, ссылка была устаревшей и т.д.

Как исправить ошибку 401 (5 методов)

Теперь, когда мы разобрались с причинами ошибки 401, пришло время обсудить, как ее устранить.

Давайте рассмотрим 5 методов, которые вы можете использовать.

  1. Проверьте ваш URL.

Начнем с самого простого потенциального решения: убедитесь, что вы использовали верный URL. Это может выглядеть банально, но 401 ошибки нередко появляются, если URL-адрес был введен неправильно.

Еще один вариант: ссылка, которую вы использовали для перехода на запрашиваемую страницу, указывает на неправильный URL. К примеру, ссылка устарела, ведет на страницу, которой больше нет (и редиректов не задано).

Стоит тщательно перепроверить URL-адрес, который вы использовали. Если вы набирали адрес самостоятельно, убедитесь, что все написано безошибочно. Если вы переходили по ссылке, убедитесь в том, что она ведет на страницу, к которой вы хотите получить доступ (либо попробуйте перейти на эту страницу непосредственно через сайт).

  1. Почистите кэш браузера.

Кэш браузера предназначен для улучшения процесса взаимодействия с сайтами в сети за счет сокращения времени загрузки страниц. К сожалению, иногда это может вести к нежелательным последствиям.

Как мы уже говорили выше, одной из распространенных причин появления ошибки 401 являются устаревшие или неправильные данные кэша или cookies. Потому, если URL введен верно, следующий шаг – чистка кэша браузера.

В итоге вы удалите любую недействительную информацию, которая хранится локально в вашем браузере и может приводить к прерываниям процесса аутентификации.  Аналогично, файлы cookie вашего браузера могут содержать аутентификационные данные, которые нужно обновить.

Если вы пользуетесь Chrome, вам нужно щелкнуть по иконке с меню в правом верхнем углу браузера и выбрать пункт Settings. В разделе «Privacy and security» нажмите «Clear browsing data:»

Далее вводим URL требуемого сайта и очищаем для него данные.

В других браузерах процесс очистки кэша и cookie может отличаться. К примеру, в Firefox нужно щелкать по иконке с библиотекой и выбирать History > Clear Recent History:

Информацию по остальным браузерам вы можете найти в поисковиках.

  1. Очистка DNS.

Еще один метод, который вы можете попробовать для устранения ошибки 401 – это очистка DNS. Эта причина встречается относительно редко, но стоит попробовать и такой подход, особенно если первые два ничего не дали.

Чтобы очистить DNS, перейдите в Windows к меню «Пуск» и там уже введите в строку поиска cmd. Нажмите Enter. Откроется командная строка. Далее вставьте команду ipconfig/flushdns, после чего снова нажмите Enter.

Если вы пользуетесь Mac, вы можете открыть командную строку следующим образом: Finder > Applications > Utilities > Terminal.

Введите команду sudo killall -HUP mDNSResponder и нажмите Enter. Затем вы можете обновить страницу, чтобы посмотреть, пропала ли ошибка 401 или нет.

  1. Деактивируйте ваши плагины

Проблема может возникать и по вине плагинов.

Некоторые плагины, особенно связанные с безопасностью, могут выдавать ошибку 401 при подозрении на вредоносную активность. Также у них могут быть проблемы с совместимостью. Потому лучше всего деактивировать все плагины и посмотреть, будет ли страница работать.

Вы можете деактивировать все плагины разом, перейдя в раздел Plugins > Installed Plugins в консоли WordPress. Выберите все плагины и в меню Bulk Actions задайте Deactivate, после чего щелкните по кнопке Apply:

После этого попробуйте перезагрузить страницу с ошибкой. Если ошибка пропала, вы можете вручную по одному активировать плагины заново, чтобы выявить виновника всех бед.

Далее вы уже можете либо удалить плагин, либо написать его разработчикам, чтобы они предоставили рабочее решение.

  1. Проверьте заголовок WWW-Authenticate

Если проблема все еще остается, то в таком случае она может быть связана с ошибками на сервере. А значит, исправить ее будет чуть сложнее.

Как мы уже писали ранее, ответ 401 передается через заголовок WWW-Authenticate, который отображается как “WWW-Authenticate: <type> realm=<realm>”. Он включает в себя строки данных, указывающие на то, какой тип аутентификации требуется для предоставления доступа.

Вам нужно посмотреть, был ли отправлен ответ в WWW-Authenticate, а точнее какая схема аутентификации была использована. По крайней мере, это позволит вам приблизиться на один шаг к решению.

Перейдите на страницу с ошибкой 401 и откройте консоль разработчика в Chrome. Вы можете щелкнуть правой кнопкой мыши на странице и выбрать Inspect (Ctrl+Shift+J).

Далее перейдите на вкладку Network и перезагрузите страницу. Это позволит сгенерировать список ресурсов. Выберите заголовок Status, чтобы отсортировать таблицу, и найдите код 401:

Выберите данную запись, после чего перейдите на вкладку Headers. В Response Headers найдите заголовок WWW-Authenticate:

Информация, представленная в заголовке ответа, в частности, в схеме аутентификации, даст вам больше сведений о том, что произошло, и укажет на решение. Это позволит вам понять, какой тип аутентификации требуется серверу.

К примеру, в приведенном выше примере мы видим, что схема аутентификации задана как «Basic». Это означает, что запрос аутентификации требует только ID и password. Для получения более подробной информации и инструкций мы рекомендуем обратиться к HTTP Authentication Scheme Registry.

Источник: kinsta.com

Категория ~
Что делать (ошибки и проблемы)
– Автор:

Игорь (Администратор)

Сегодня рассмотрим такую специфическую ошибку как 401 Unauthorized Error. Почему специфическую? Потому что обычные пользователи интернета практически никогда не встречаются с данной ошибкой. Но обо всем по порядку.

Что значит ошибка 401 Unauthorized?

Ошибка 401 Unauthorized: что означает и как исправить?

Ошибка 401 Unauthorized («Отказ в доступе») — эта ошибка означает, что при попытке открыть веб-страницу сайта пользователем возникли проблемы с его авторизацией или аутентификацией.

Основная суть. Пользователь пытается открыть страницу. Сайт возвращает страницу с HTTP заголовком WWW-Authenticate (кстати, страница также с кодом 401 Unauthorized), в котором перечислены параметры системы аутентификации. Браузер запрашивает логин и пароль у пользователя, которые передаются в заголовке Authorization обратно к сайту (в соответствии с ранее полученными настройками системы безопасности). Если проверка прошла, то пользователю предоставляется дальше доступ к странице. В противном случае появляется ошибка 401 Unauthorized.

Кстати, стоит понимать, что данная ошибка отличается от 403 Forbidden, хотя и также связана с настройками безопасности.

Возможные причины возникновения ошибки 401 Unauthorized:

1. Некорректно введенные логин или пароль (или их отсутствие). Пользователь что-то некорректно ввел.

2. Недостаточно прав для доступа. Например, в каждом сайте вполне нормальным явлением считается то, что у обычного пользователя нет доступа к административной части сайта.

3. Ошибки в настройках или коде сайта. Такое тоже бывает.

Варианты возможных текстовых уведомлений:

1. HTTP Error 401 — Ошибка авторизации.

2. Требуется авторизация.

3. 401 Несанкционированный доступ.

4. 401 Unauthorized.

5. Authorization Required.

Что делать при ошибке 401 Unauthorized, если вы обычный посетитель сайта?

Рассмотрим что вы можете сделать, если вы обычный пользователь и столкнулись с ошибкой 401 Unauthorized:

1. Введите корректные логин и пароль. Ошибка 401 означает ошибку в авторизации или аутентификации, поэтому стоит проверить правильность введенных вами логина и пароля.

2. Проверьте корректность URL адреса страницы веб-сайта. Если вы не ожидали увидеть 401 Unauthorized (скажем, постоянно открывали сайт без проблем), то вполне нормальным действием будет проверить корректность адреса.

3. Попробуйте открыть страницу через время или с другого браузера. Вполне может быть так, что автор сайта что-то делает с этим самым веб-сайтом. Поэтому стоит подождать какое-то время и попробовать еще раз открыть веб-страницу. Так же может быть так, что ошибка 401 возникает из-за браузера (мало ли чего), поэтому стоит попробовать открыть страницу другим браузером (или с другого компьютера).

Кстати, обзор в тему Зачем пользователю несколько браузеров?

4. Напишите автору сайта. Как минимум узнаете причину или возможное время восстановления доступа.

Как исправить ошибку 401 Unauthorized, если вы владелец сайта?

Теперь рассмотрим как исправить ошибку 401 Unauthorized владельцу сайта:

1. Проверьте URL и логин с паролем. Владелец сайта это тоже пользователь сайта, поэтому проверить адрес страницы и корректность ввода логина с паролем будет не лишним действием.

2. Проверьте настройки и код сайта. Если же вам сайт делал кто-то иной, то попросите его проверить.

3. Напишите хостеру. Если вы все проверили и проблем не обнаружили, то нужно писать хостеру.

Понравилась заметка? Тогда время подписываться в социальных сетях и делать репосты!

☕ Понравился обзор? Поделитесь с друзьями!

  • Ошибка 500 Internal Server Error: что означает и как исправить?

    Ошибка 500 Internal Server Error: что означает и как исправить?
    Что делать (ошибки и проблемы)

  • Ошибка 404 Page Not Found: что означает и как исправить?

    Ошибка 404 Page Not Found: что означает и как исправить?
    Что делать (ошибки и проблемы)

  • Ошибка 403 Forbidden: что означает и как исправить?

    Ошибка 403 Forbidden: что означает и как исправить?
    Что делать (ошибки и проблемы)

  • Ошибка 502 Bad Gateway: что означает и как исправить?

    Ошибка 502 Bad Gateway: что означает и как исправить?
    Что делать (ошибки и проблемы)

  • Ошибка 503 Service Unavailable: что означает и как исправить?

    Ошибка 503 Service Unavailable: что означает и как исправить?
    Что делать (ошибки и проблемы)

  • Коды и ошибки 301, 302, 303, 304

    Коды и ошибки 301, 302, 303, 304
    Что делать (ошибки и проблемы)

Добавить комментарий / отзыв

This article describes the most common errors and ways of fixing them. 

1. Error:  Error initializing ELMA configuration —> System.InvalidOperationException: Cannot check database exists —> System.Data.SqlClient.SqlException: User login failed «IIS APPPOOLElma3-Standart».

  • Reason: You are logged in to the IIS server under an account without administrator permissions.
  • Solution: To fix this IIS server error, open the Internet Information Services (IIS) Manager (in Start — Administrative Tools). On the Application Pools tab open Advanced Settings of the ELMA3-Express pool (in the context menu). In the Process Model table, in the Identity field, specify the LocalSystem account or another account with administrator permissions. Restart the web server.

2. ErrorThe underlying connection was closed: An expected error occurred on a receive: Unable to read data from the transport connection: Remote host has disconnected.: Remote host has disconnected

  • Reason: The ELMA server has been started with insufficient access permissions
  • Solution: If the server is Cassini-based, press win+R and run the services.msc command. Find the ELMA Web Server, right click on it, select Properties, and open the Log On tab. If the server is IIS-based, then go to the IIS Manager, open the Connections window, find the Application Pools item, and the ELMA server pool. Right-click on the on the pool and select Advanced settings. In the Identity field, specify the LocalSystem account or another account with administrator permissions. Restart the web server.

3. Error: *System.UnauthorizedAccessException: Access to the path «С:ELMA3-ExpressUserConfigconfiguration.packges» is denied.

  • Solution: Delete the *.packages file from the UserConfig folder.

4. Error: The server is not started because of an error

  • Reason: The database names in SQL Server Management Studio and in the configuration.config file do not match.
  • Solution: Change the database name in the configuration.config file

5. Error: Error creating a database backup copy

  • Reason: Not enough disk space
  • Solution: Free up the disk space

6. ErrorEleWise.ELMA.Runtime.Db.DbStructureException: Error updating the database structure —> System.Data.DataException: Failed to execute request DROP INDEX UK_principal_name ON sysdiagrams —> System.Data.SqlClient.SqlException: DROP INDEX is unacceptable in the index «sysdiagrams.UK_principal_name». It is used to force apply the UNIQUE KEY restriction.

  • Reason: The System Tables section in SQL Server Management Studio must not contain tables.
  • Solution: Stop the ELMA server and open SQL Server Management Studio, in the list select the required database and expand the list of tables. The System Tables section must not contain tables — if there are tables, delete them. Start the ELMA server. 

7. Error: Error caused by active connections to the database

  • Reason: After restoring a database from a backup, a server with different time may still have information on an active connection.
  • Solution: Create a backup copy and execute a query to the database. Query: Delete from DB_ACTIVECONNECTIONS

8. Error: EleWise.ELMA.Runtime.Db.DbStructureException: Error updating the database structure —> NHibernate.TransactionException: Commit failed with SQL exception —> FirebirdSql.Data.FirebirdClient.FbException: unsuccessful metadata update

object INDEX is in use —> FirebirdSql.Data.Common.IscException: unsuccessful metadata update

  • Reason: Update error
  • Solution: Create a database backup and restore it. (For the system to work correctly with FireBird, you should perform this operation once every two weeks) 

9. Error: *EleWise.ELMA.Runtime.Exceptions.ConfigurationInitializeException: Error initializing the ELMA configuration —> System.InvalidOperationException: Unable to connect to the database —> FirebirdSql.Data.FirebirdClient.FbException: Unable to complete network request to host «127.0.0.1». —> FirebirdSql.Data.Common.IscException: Unable to complete network request to host «127.0.0.1».

  • ReasonAn error in the configuration.config file, line <add name=»MainDB» connectionString=»data source=127.0.0.1;initial catalog={CONFIGDIR}base.fdb;user id=sysdba;password=masterkey;character set=UNICODE_FSS;dialect=3;server type=0″ />
  • SolutionMake sure that there are no misprints and the correct character case is used in the line <add name=»MainDB» connectionString=»data source=127.0.0.1;initial catalog={CONFIGDIR}base.fdb;user id=sysdba;password=masterkey;character set=UNICODE_FSS;dialect=3;server type=0″ />.

10. Error: *EleWise.ELMA.Runtime.Exceptions.ConfigurationInitializeException: Error initializing the ELMA configuration —> System.InvalidOperationException: Unable to connect to the database —> System.Data.SqlClient.SqlException: Unable to open the «ELMA» database, requested by the login. Unable to log in. 
User log in error «NT AUTHORITYsystem».

  • Reason: You logged in to the Cassini server under an account without administrator permissions.
  • Solution: Start the ELMA server under an account with Windows administrator permissions. Go to Control Panel -> Administrative Tools -> Services, find the ELMA web server, right-click on it, select Properties, in the opened window switch to the Log On tab, check the This account box and enter the login and password of the account with administrator permissions.

Addition: MS SQL 2008 and higher server error Login failed for user ’NT AUTHORITYsystem’. Reason: unable to open explicitly specified «ELMA» database. [CLIENT: <local machine>]. Error: 18456, severity: 14, status: 38.

  • Reason: The authentication is correct, the server is started with the administrator permissions, but the database is not available (or there are no permissions).
  • Solution: Add the sysadmin role to the NT AUTHORITYsystem group on the SQL server. Open the Microsoft SQL Server Management Studio, Security section — > Logins and go to the properties of the NT AUTHORITYsystem group. Check the sysadmin box in the server role menu.

11. Error: *EleWise.ELMA.Runtime.Exceptions.ConfigurationInitializeException: Error initializing the ELMA configuration —> System.InvalidOperationException: Unable to connect to the database —> System.Data.SqlClient.SqlException: Solution CREATE DATABASE is forbidden in the «master» database.
Failed to connect the file «F:ELMA3-StandartUserConfigELMA3.mdf» as the «ELMA3» database.

  • Reason: An error in the configuration.config file, line AttachDbFilename={CONFIGDIR}ELMA3.mdf;
  • Solution: Delete the line «AttachDbFilename={CONFIGDIR}ELMA3.mdf» in the configuration.config file. Save the file and restart the web server.

12. Error: When working in the web part, a dialog box with the Start preconditions check failed error is displayed. 

An error also occurs when signing in to the Designer.

  • Reason: You can see an empty parameter in the error dialog box – server name.

  • Solution: Connect to the MSSQL server as administrator and execute the SQL-query:
 

EXEC sp_dropserver N'elma-local-loop'
GO

EXEC sp_addlinkedserver N'elma-local-loop', N' ', N'SQLNCLI', N'localhostSQLSERVER2014'
GO

EXEC sp_serveroption [elma-local-loop], N'remote proc transaction promotion', 'false'
EXEC sp_serveroption [elma-local-loop], N'rpc out', 'true'
GO​

where localhostSQLSERVER2014 – the name of the database server.

To make sure that the problem is solved, run the following query:

select * from sys.servers where lower([name]) = 'elma-local-loop'

The result will look like this:

13. Error. Error initializing the ELMA configuration: The database version <version name> does not meet the minimum requirements (provided version – <used database version>, required at least <database version, required for correct ELMA operation>

  • Reason – the used database version does not meet the minimum system requirements for the used ELMA edition.
  • Solution – update the used database version to the one required for the ELMA edition.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Electronic workbench ошибка 0xc0000142 win 10
  • Electrolux стиральная машина ошибка е00