forked from pozitronik/CloudMailRu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConnectionManager.pas
246 lines (212 loc) · 9.67 KB
/
ConnectionManager.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
unit ConnectionManager;
{Обеспечиваем управление множественными поключениями без необходимости постоянных переподключений. При первом обращении нужное подключение создаётся,
при последующих - отдаются уже созданные.}
interface
uses CloudMailRu, MRC_Helper, windows, Vcl.Controls, PLUGIN_Types, Settings, AskPassword;
type
TNamedConnection = record
Name: WideString;
Connection: TCloudMailRu;
end;
TConnectionManager = class
private
Connections: array of TNamedConnection;
IniFileName: WideString;
Proxy: TProxySettings;
Timeout: Integer;
CloudMaxFileSize: Integer;
PluginNum: Integer;
MyProgressProc: TProgressProcW;
MyLogProc: TLogProcW;
function ConnectionExists(connectionName: WideString): Integer; //проверяет существование подключение
function new(connectionName: WideString): Integer; //Добавляет подключение в пул
function GetMyPasswordNow(var AccountSettings: TAccountSettings): boolean; //Получает пароль из файла, из тоталовского менеджера или запрашивает прямой ввод
public
CryptoNum: Integer;
MyCryptProc: TCryptProcW;
constructor Create(IniFileName: WideString; PluginNum: Integer; MyProgressProc: TProgressProcW; MyLogProc: TLogProcW; ProxySettings: TProxySettings; Timeout, CloudMaxFileSize: Integer);
destructor Destroy(); override;
function get(connectionName: WideString; var OperationResult: Integer; doInit: boolean = true): TCloudMailRu; //возвращает готовое подклчение по имени
function set_(connectionName: WideString; cloud: TCloudMailRu): boolean;
function init(connectionName: WideString; ProxySettings: TProxySettings; Timeout: Integer): Integer; //инициализирует подключение по его имени, возвращает код состояния
function free(connectionName: WideString): Integer; //освобождает подключение по его имени, возвращает код состояния
function freeAll: Integer; //освобождает все подключения
function initialized(connectionName: WideString): boolean; //Проверяет, инициализировано ли подключение
end;
implementation
{TConnectionManager}
constructor TConnectionManager.Create(IniFileName: WideString; PluginNum: Integer; MyProgressProc: TProgressProcW; MyLogProc: TLogProcW; ProxySettings: TProxySettings; Timeout, CloudMaxFileSize: Integer);
begin
SetLength(Connections, 0);
self.IniFileName := IniFileName;
self.PluginNum := PluginNum;
self.MyProgressProc := MyProgressProc;
self.MyLogProc := MyLogProc;
self.Proxy := ProxySettings;
self.Timeout := Timeout;
self.CloudMaxFileSize := CloudMaxFileSize;
end;
destructor TConnectionManager.Destroy;
begin
freeAll();
end;
function TConnectionManager.get(connectionName: WideString; var OperationResult: Integer; doInit: boolean = true): TCloudMailRu;
var
ConnectionIndex: Integer;
begin
ConnectionIndex := ConnectionExists(connectionName);
if ConnectionIndex <> -1 then
begin
result := Connections[ConnectionIndex].Connection;
end else begin
result := Connections[new(connectionName)].Connection;
end;
if (doInit) then
begin
OperationResult := CLOUD_OPERATION_OK;
if not initialized(connectionName) then OperationResult := init(connectionName, self.Proxy, self.Timeout);
if (OperationResult = CLOUD_OPERATION_OK) then result := get(connectionName, OperationResult, false);
end;
{если подключиться не удалось, все функции облака будут возвращать негативный результат, но без AV}
end;
function TConnectionManager.set_(connectionName: WideString; cloud: TCloudMailRu): boolean;
var
ConnectionIndex: Integer;
begin
ConnectionIndex := ConnectionExists(connectionName);
if ConnectionIndex = -1 then exit(false);
Connections[ConnectionIndex].Connection := cloud;
result := true;
end;
function TConnectionManager.init(connectionName: WideString; ProxySettings: TProxySettings; Timeout: Integer): Integer;
var
cloud: TCloudMailRu;
AccountSettings: TAccountSettings;
begin
result := CLOUD_OPERATION_OK;
AccountSettings := GetAccountSettingsFromIniFile(IniFileName, connectionName);
if not GetMyPasswordNow(AccountSettings) then exit(CLOUD_OPERATION_ERROR_STATUS_UNKNOWN); //INVALID_HANDLE_VALUE
MyLogProc(PluginNum, MSGTYPE_CONNECT, PWideChar('CONNECT \' + connectionName));
cloud := TCloudMailRu.Create(AccountSettings, self.CloudMaxFileSize, self.Proxy, Timeout, MyProgressProc, PluginNum, MyLogProc);
if not set_(connectionName, cloud) then exit(CLOUD_OPERATION_ERROR_STATUS_UNKNOWN); //INVALID_HANDLE_VALUE
if not(get(connectionName, result, false).login()) then
begin
result := CLOUD_OPERATION_FAILED;
free(connectionName);
end;
//cloud.Destroy;
end;
function TConnectionManager.initialized(connectionName: WideString): boolean;
var
dump: Integer;
begin
result := Assigned(get(connectionName, dump, false));
end;
function TConnectionManager.new(connectionName: WideString): Integer;
begin
SetLength(Connections, Length(Connections) + 1);
Connections[Length(Connections) - 1].Name := connectionName;
result := Length(Connections) - 1;
end;
function TConnectionManager.ConnectionExists(connectionName: WideString): Integer;
var
I: Integer;
begin
result := -1;
for I := 0 to Length(Connections) - 1 do
begin
if Connections[I].Name = connectionName then exit(I);
end;
end;
function TConnectionManager.free(connectionName: WideString): Integer;
begin
result := CLOUD_OPERATION_OK;
get(connectionName, result, false).free;
set_(connectionName, nil);
end;
function TConnectionManager.freeAll: Integer;
var
I: Integer;
begin
result := CLOUD_OPERATION_OK;
for I := 0 to Length(Connections) - 1 do
begin
if initialized(Connections[I].Name) then
begin
Connections[I].Connection.free;
set_(Connections[I].Name, nil);
end;
end;
SetLength(Connections, 0);
end;
function TConnectionManager.GetMyPasswordNow(var AccountSettings: TAccountSettings): boolean;
var
CryptResult: Integer;
AskResult: Integer;
TmpString: WideString;
buf: PWideChar;
begin
if AccountSettings.public_account then exit(true);
if AccountSettings.use_tc_password_manager then
begin //пароль должен браться из TC
GetMem(buf, 1024);
CryptResult := MyCryptProc(PluginNum, CryptoNum, FS_CRYPT_LOAD_PASSWORD_NO_UI, PWideChar(AccountSettings.Name), buf, 1024); //Пытаемся взять пароль по-тихому
if CryptResult = FS_FILE_NOTFOUND then
begin
MyLogProc(PluginNum, msgtype_details, PWideChar('No master password entered yet'));
CryptResult := MyCryptProc(PluginNum, CryptoNum, FS_CRYPT_LOAD_PASSWORD, PWideChar(AccountSettings.Name), buf, 1024);
end;
if CryptResult = FS_FILE_OK then //Успешно получили пароль
begin
AccountSettings.password := buf;
//Result := true;
end;
if CryptResult = FS_FILE_NOTSUPPORTED then //пользователь отменил ввод главного пароля
begin
MyLogProc(PluginNum, msgtype_importanterror, PWideChar('CryptProc returns error: Decrypt failed'));
end;
if CryptResult = FS_FILE_READERROR then
begin
MyLogProc(PluginNum, msgtype_importanterror, PWideChar('CryptProc returns error: Password not found in password store'));
end;
FreeMemory(buf);
end; //else // ничего не делаем, пароль уже должен быть в настройках (взят в открытом виде из инишника)
if AccountSettings.password = '' then //но пароля нет, не в инишнике, не в тотале
begin
AskResult := TAskPasswordForm.AskPassword(FindTCWindow, AccountSettings.Name, AccountSettings.password, AccountSettings.use_tc_password_manager);
if AskResult <> mrOK then
begin //не указали пароль в диалоге
exit(false); //отказались вводить пароль
end else begin
if AccountSettings.use_tc_password_manager then
begin
case MyCryptProc(PluginNum, CryptoNum, FS_CRYPT_SAVE_PASSWORD, PWideChar(AccountSettings.Name), PWideChar(AccountSettings.password), SizeOf(AccountSettings.password)) of
FS_FILE_OK:
begin //TC скушал пароль, запомним в инишник галочку
MyLogProc(PluginNum, msgtype_details, PWideChar('Password saved in TC password manager'));
TmpString := AccountSettings.password;
AccountSettings.password := '';
SetAccountSettingsToIniFile(IniFileName, AccountSettings);
AccountSettings.password := TmpString;
end;
FS_FILE_NOTSUPPORTED: //Сохранение не получилось
begin
MyLogProc(PluginNum, msgtype_importanterror, PWideChar('CryptProc returns error: Encrypt failed'));
end;
FS_FILE_WRITEERROR: //Сохранение опять не получилось
begin
MyLogProc(PluginNum, msgtype_importanterror, PWideChar('Password NOT saved: Could not write password to password store'));
end;
FS_FILE_NOTFOUND: //Не указан мастер-пароль
begin
MyLogProc(PluginNum, msgtype_importanterror, PWideChar('Password NOT saved: No master password entered yet'));
end;
//Ошибки здесь не значат, что пароль мы не получили - он может быть введён в диалоге
end;
end;
result := true;
end;
end
else result := true; //пароль взят из инишника напрямую
end;
end.