Line data Source code
1 : import 'dart:collection';
2 : import 'dart:convert';
3 :
4 : import 'package:cwtch/config.dart';
5 : import 'package:flutter/services.dart';
6 : import 'package:path_provider/path_provider.dart';
7 : import 'dart:async';
8 : import 'package:path/path.dart' as path;
9 :
10 : import 'cwtch.dart';
11 : import 'cwtchNotifier.dart';
12 :
13 : /*
14 : TODO: make a reusable plugin for other flutter apps
15 :
16 : import 'package:federated_plugin_platform_interface/federated_plugin_platform_interface.dart';
17 :
18 : /// It uses [FederatedPluginInterface]
19 : Future startCwtch() async {
20 : return await FederatedPluginInterface.instance.startCwtch();
21 : }
22 : */
23 :
24 : class CwtchGomobile implements Cwtch {
25 : static const appInfoPlatform = const MethodChannel('test.flutter.dev/applicationInfo');
26 : static const cwtchPlatform = const MethodChannel('cwtch');
27 :
28 : final appbusEventChannelName = 'test.flutter.dev/eventBus';
29 :
30 : late Future<dynamic> androidLibraryDir;
31 : late Future<dynamic> androidHomeDirectory;
32 : String androidHomeDirectoryStr = "";
33 : String _cwtchDir = "";
34 : late CwtchNotifier cwtchNotifier;
35 : bool _isL10nInit = false;
36 :
37 0 : @override
38 : Future<HashMap<String, String>> PlatformChannelInfo() async {
39 0 : HashMap<String, String> info = HashMap<String, String>();
40 :
41 0 : info.addAll({"appInfoPlatform.name": appInfoPlatform.name});
42 0 : info.addAll({"appInfoPlatform.codec": appInfoPlatform.codec.toString()});
43 0 : EnvironmentConfig.debugLog("getting foreground service info...");
44 0 : appInfoPlatform.invokeMapMethod('getForegroundServiceInfo').then((foregroundServiceInfoMap) {
45 0 : EnvironmentConfig.debugLog("parsing foreground service info...");
46 0 : foregroundServiceInfoMap?.entries.forEach((element) {
47 0 : info.addAll({element.key.toString(): element.value.toString()});
48 : });
49 : });
50 0 : EnvironmentConfig.debugLog("returning foreground service info...");
51 : return info;
52 : }
53 :
54 0 : CwtchGomobile(CwtchNotifier _cwtchNotifier) {
55 0 : print("gomobile.dart: CwtchGomobile()");
56 0 : cwtchNotifier = _cwtchNotifier;
57 0 : cwtchNotifier.setMessageSeenCallback((String profile, int conversation, DateTime time) => {this.SetConversationAttribute(profile, conversation, LastMessageSeenTimeKey, time.toIso8601String())});
58 0 : androidHomeDirectory = getApplicationDocumentsDirectory();
59 0 : androidLibraryDir = appInfoPlatform.invokeMethod('getNativeLibDir');
60 :
61 : // Method channel to receive libcwtch-go events via Kotlin and dispatch them to _handleAppbusEvent (sends to cwtchNotifier)
62 0 : final appbusEventChannel = MethodChannel(appbusEventChannelName);
63 0 : appbusEventChannel.setMethodCallHandler(this._handleAppbusEvent);
64 : }
65 :
66 0 : String getAssetsDir() {
67 : // TODO
68 : return "";
69 : }
70 :
71 : // Requires Start() to have been run to initialize
72 0 : Future<String> getCwtchDir() async {
73 0 : return _cwtchDir;
74 : }
75 :
76 : // ignore: non_constant_identifier_names
77 0 : Future<void> Start() async {
78 0 : print("gomobile.dart: Start()...");
79 0 : androidHomeDirectoryStr = (await androidHomeDirectory).path;
80 0 : _cwtchDir = path.join(androidHomeDirectoryStr, ".cwtch");
81 0 : if (EnvironmentConfig.BUILD_VER == dev_version) {
82 0 : _cwtchDir = path.join(_cwtchDir, "dev");
83 : }
84 0 : String torPath = path.join(await androidLibraryDir, "libtor.so");
85 0 : print("gomobile.dart: Start invokeMethod Start($_cwtchDir, $torPath)...");
86 0 : cwtchPlatform.invokeMethod("Start", {"appDir": _cwtchDir, "torPath": torPath});
87 : }
88 :
89 0 : @override
90 : // ignore: non_constant_identifier_names
91 : Future<void> ReconnectCwtchForeground() async {
92 0 : cwtchPlatform.invokeMethod("ReconnectCwtchForeground", {});
93 : }
94 :
95 : // Handle libcwtch-go events (received via kotlin) and dispatch to the cwtchNotifier
96 0 : Future<void> _handleAppbusEvent(MethodCall call) async {
97 0 : final String json = call.arguments;
98 0 : var obj = jsonDecode(json);
99 0 : cwtchNotifier.handleMessage(call.method, obj);
100 : }
101 :
102 : // ignore: non_constant_identifier_names
103 0 : void CreateProfile(String nick, String pass, bool autostart) {
104 0 : cwtchPlatform.invokeMethod("CreateProfile", {"nick": nick, "pass": pass, "autostart": autostart});
105 : }
106 :
107 : // ignore: non_constant_identifier_names
108 0 : void ActivatePeerEngine(String profile) {
109 0 : cwtchPlatform.invokeMethod("ActivatePeerEngine", {"profile": profile});
110 : }
111 :
112 : // ignore: non_constant_identifier_names
113 0 : void DeactivatePeerEngine(String profile) {
114 0 : cwtchPlatform.invokeMethod("DeactivatePeerEngine", {"profile": profile});
115 : }
116 :
117 : // ignore: non_constant_identifier_names
118 0 : void LoadProfiles(String pass) {
119 0 : cwtchPlatform.invokeMethod("LoadProfiles", {"pass": pass});
120 : }
121 :
122 : // ignore: non_constant_identifier_names
123 0 : void DeleteProfile(String onion, String pass) {
124 0 : cwtchPlatform.invokeMethod("DeleteProfile", {"ProfileOnion": onion, "pass": pass});
125 : }
126 :
127 : // ignore: non_constant_identifier_names
128 0 : Future<dynamic> GetMessage(String profile, int conversation, int index) {
129 0 : return cwtchPlatform.invokeMethod("GetMessage", {"ProfileOnion": profile, "conversation": conversation, "index": index});
130 : }
131 :
132 : // ignore: non_constant_identifier_names
133 0 : Future<dynamic> GetMessageByID(String profile, int conversation, int id) {
134 0 : return cwtchPlatform.invokeMethod("GetMessageByID", {"ProfileOnion": profile, "conversation": conversation, "id": id});
135 : }
136 :
137 : // ignore: non_constant_identifier_names
138 0 : Future<dynamic> GetMessages(String profile, int conversation, int index, int count) {
139 0 : return cwtchPlatform.invokeMethod("GetMessages", {"ProfileOnion": profile, "conversation": conversation, "index": index, "count": count});
140 : }
141 :
142 0 : @override
143 : // ignore: non_constant_identifier_names
144 : void SendProfileEvent(String onion, String jsonEvent) {
145 0 : cwtchPlatform.invokeMethod("SendProfileEvent", {"onion": onion, "jsonEvent": jsonEvent});
146 : }
147 :
148 0 : @override
149 : // ignore: non_constant_identifier_names
150 : void SendAppEvent(String jsonEvent) {
151 0 : cwtchPlatform.invokeMethod("SendAppEvent", {"jsonEvent": jsonEvent});
152 : }
153 :
154 0 : @override
155 0 : void dispose() => {};
156 :
157 0 : @override
158 : // ignore: non_constant_identifier_names
159 : void AcceptContact(String profileOnion, int conversation) {
160 0 : cwtchPlatform.invokeMethod("AcceptConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
161 : }
162 :
163 0 : @override
164 : // ignore: non_constant_identifier_names
165 : void BlockContact(String profileOnion, int conversation) {
166 0 : cwtchPlatform.invokeMethod("BlockContact", {"ProfileOnion": profileOnion, "conversation": conversation});
167 : }
168 :
169 0 : @override
170 : // ignore: non_constant_identifier_names
171 : void UnblockContact(String profileOnion, int conversation) {
172 0 : cwtchPlatform.invokeMethod("UnblockContact", {"ProfileOnion": profileOnion, "conversation": conversation});
173 : }
174 :
175 0 : @override
176 : // ignore: non_constant_identifier_names
177 : Future<dynamic> SendMessage(String profileOnion, int conversation, String message) {
178 0 : return cwtchPlatform.invokeMethod("SendMessage", {"ProfileOnion": profileOnion, "conversation": conversation, "message": message});
179 : }
180 :
181 0 : @override
182 : // ignore: non_constant_identifier_names
183 : Future<dynamic> SendInvitation(String profileOnion, int conversation, int target) {
184 0 : return cwtchPlatform.invokeMethod("SendInvitation", {"ProfileOnion": profileOnion, "conversation": conversation, "target": target});
185 : }
186 :
187 0 : @override
188 : // ignore: non_constant_identifier_names
189 : Future<dynamic> ShareFile(String profileOnion, int conversation, String filepath) {
190 0 : return cwtchPlatform.invokeMethod("ShareFile", {"ProfileOnion": profileOnion, "conversation": conversation, "filepath": filepath});
191 : }
192 :
193 0 : @override
194 : // ignore: non_constant_identifier_names
195 : void DownloadFile(String profileOnion, int conversation, String filepath, String manifestpath, String filekey) {
196 0 : cwtchPlatform.invokeMethod("DownloadFile", {"ProfileOnion": profileOnion, "conversation": conversation, "filepath": filepath, "manifestpath": manifestpath, "filekey": filekey});
197 : }
198 :
199 : // ignore: non_constant_identifier_names
200 0 : void CreateDownloadableFile(String profileOnion, int conversation, String filenameSuggestion, String filekey, String manifestpath) {
201 : cwtchPlatform
202 0 : .invokeMethod("CreateDownloadableFile", {"ProfileOnion": profileOnion, "conversation": conversation, "manifestpath": manifestpath, "filename": filenameSuggestion, "filekey": filekey});
203 : }
204 :
205 : // ignore: non_constant_identifier_names
206 0 : void ExportPreviewedFile(String sourceFile, String suggestion) {
207 0 : cwtchPlatform.invokeMethod("ExportPreviewedFile", {
208 : "Path": sourceFile,
209 : "FileName": suggestion,
210 : });
211 : }
212 :
213 0 : @override
214 : // ignore: non_constant_identifier_names
215 : void CheckDownloadStatus(String profileOnion, String fileKey) {
216 0 : cwtchPlatform.invokeMethod("CheckDownloadStatus", {"ProfileOnion": profileOnion, "fileKey": fileKey});
217 : }
218 :
219 0 : @override
220 : // ignore: non_constant_identifier_names
221 : void VerifyOrResumeDownload(String profileOnion, int conversation, String filekey) {
222 0 : cwtchPlatform.invokeMethod("VerifyOrResumeDownload", {"ProfileOnion": profileOnion, "conversation": conversation, "filekey": filekey});
223 : }
224 :
225 0 : @override
226 : // ignore: non_constant_identifier_names
227 : void ResetTor() {
228 0 : cwtchPlatform.invokeMethod("ResetTor", {});
229 : }
230 :
231 0 : @override
232 : // ignore: non_constant_identifier_names
233 : Future<dynamic> ImportBundle(String profileOnion, String bundle) {
234 0 : return cwtchPlatform.invokeMethod("ImportBundle", {"ProfileOnion": profileOnion, "bundle": bundle});
235 : }
236 :
237 0 : @override
238 : void CreateGroup(String profileOnion, String server, String groupName) {
239 0 : cwtchPlatform.invokeMethod("CreateGroup", {"ProfileOnion": profileOnion, "server": server, "groupName": groupName});
240 : }
241 :
242 0 : @override
243 : // ignore: non_constant_identifier_names
244 : void DeleteContact(String profileOnion, int conversation) {
245 0 : cwtchPlatform.invokeMethod("DeleteConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
246 : }
247 :
248 0 : @override
249 : // ignore: non_constant_identifier_names
250 : void ArchiveConversation(String profileOnion, int conversation) {
251 0 : cwtchPlatform.invokeMethod("ArchiveConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
252 : }
253 :
254 0 : @override
255 : // ignore: non_constant_identifier_names
256 : void SetProfileAttribute(String profile, String key, String val) {
257 0 : cwtchPlatform.invokeMethod("SetProfileAttribute", {"ProfileOnion": profile, "Key": key, "Val": val});
258 : }
259 :
260 0 : @override
261 : // ignore: non_constant_identifier_names
262 : void SetConversationAttribute(String profile, int conversation, String key, String val) {
263 0 : cwtchPlatform.invokeMethod("SetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "Key": key, "Val": val});
264 : }
265 :
266 0 : @override
267 : // ignore: non_constant_identifier_names
268 : void LoadServers(String password) {
269 0 : cwtchPlatform.invokeMethod("LoadServers", {"Password": password});
270 : }
271 :
272 0 : @override
273 : // ignore: non_constant_identifier_names
274 : void CreateServer(String password, String description, bool autostart) {
275 0 : cwtchPlatform.invokeMethod("CreateServer", {"Password": password, "Description": description, "Autostart": autostart});
276 : }
277 :
278 0 : @override
279 : // ignore: non_constant_identifier_names
280 : void DeleteServer(String serverOnion, String password) {
281 0 : cwtchPlatform.invokeMethod("DeleteServer", {"ServerOnion": serverOnion, "Password": password});
282 : }
283 :
284 0 : @override
285 : // ignore: non_constant_identifier_names
286 : void LaunchServers() {
287 0 : cwtchPlatform.invokeMethod("LaunchServers", {});
288 : }
289 :
290 0 : @override
291 : // ignore: non_constant_identifier_names
292 : void LaunchServer(String serverOnion) {
293 0 : cwtchPlatform.invokeMethod("LaunchServer", {"ServerOnion": serverOnion});
294 : }
295 :
296 0 : @override
297 : // ignore: non_constant_identifier_names
298 : void StopServer(String serverOnion) {
299 0 : cwtchPlatform.invokeMethod("StopServer", {"ServerOnion": serverOnion});
300 : }
301 :
302 0 : @override
303 : // ignore: non_constant_identifier_names
304 : void StopServers() {
305 0 : cwtchPlatform.invokeMethod("StopServers", {});
306 : }
307 :
308 0 : @override
309 : // ignore: non_constant_identifier_names
310 : void DestroyServers() {
311 0 : cwtchPlatform.invokeMethod("DestroyServers", {});
312 : }
313 :
314 0 : @override
315 : // ignore: non_constant_identifier_names
316 : void SetServerAttribute(String serverOnion, String key, String val) {
317 0 : cwtchPlatform.invokeMethod("SetServerAttribute", {"ServerOnion": serverOnion, "Key": key, "Val": val});
318 : }
319 :
320 0 : @override
321 : Future<void> Shutdown() async {
322 0 : print("gomobile.dart Shutdown");
323 0 : cwtchPlatform.invokeMethod("Shutdown", {});
324 : }
325 :
326 0 : @override
327 : Future GetMessageByContentHash(String profile, int conversation, String contentHash) {
328 0 : return cwtchPlatform.invokeMethod("GetMessageByContentHash", {"ProfileOnion": profile, "conversation": conversation, "contentHash": contentHash});
329 : }
330 :
331 0 : @override
332 : void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val) {
333 0 : cwtchPlatform.invokeMethod("SetMessageAttribute", {"ProfileOnion": profile, "conversation": conversation, "Channel": channel, "Message": message, "Key": key, "Val": val});
334 : }
335 :
336 0 : @override
337 : String? defaultDownloadPath() {
338 0 : return this.androidHomeDirectoryStr;
339 : }
340 :
341 0 : @override
342 : void ChangePassword(String profile, String pass, String newpass, String newpassAgain) {
343 0 : cwtchPlatform.invokeMethod("ChangePassword", {"ProfileOnion": profile, "OldPass": pass, "NewPass": newpass, "NewPassAgain": newpassAgain});
344 : }
345 :
346 0 : @override
347 : bool isL10nInit() {
348 0 : return _isL10nInit;
349 : }
350 :
351 0 : @override
352 : void l10nInit(String notificationSimple, String notificationConversationInfo) {
353 0 : cwtchNotifier.l10nInit(notificationSimple, notificationConversationInfo);
354 0 : cwtchPlatform.invokeMethod("L10nInit", {"notificationSimple": notificationSimple, "notificationConversationInfo": notificationConversationInfo});
355 0 : _isL10nInit = true;
356 : }
357 :
358 0 : @override
359 : // ignore: non_constant_identifier_names
360 : void ExportProfile(String profile, String file) {
361 0 : cwtchPlatform.invokeMethod("ExportProfile", {"ProfileOnion": profile, "file": file});
362 : }
363 :
364 0 : @override
365 : // ignore: non_constant_identifier_names
366 : Future<dynamic> ImportProfile(String file, String pass) {
367 0 : return cwtchPlatform.invokeMethod("ImportProfile", {"file": file, "pass": pass});
368 : }
369 :
370 0 : @override
371 : Future GetDebugInfo() {
372 : // FIXME: getDebugInfo is less useful for Android so for now
373 : // we don't implement it
374 0 : return Future.value("{}");
375 : }
376 :
377 0 : @override
378 : Future GetSharedFiles(String profile, int handle) {
379 0 : return cwtchPlatform.invokeMethod("GetSharedFiles", {"ProfileOnion": profile, "conversation": handle});
380 : }
381 :
382 0 : @override
383 : void RestartSharing(String profile, String filekey) {
384 0 : cwtchPlatform.invokeMethod("RestartFileShare", {"ProfileOnion": profile, "filekey": filekey});
385 : }
386 :
387 0 : @override
388 : void StopSharing(String profile, String filekey) {
389 0 : cwtchPlatform.invokeMethod("StopSharing", {"ProfileOnion": profile, "filekey": filekey});
390 : }
391 :
392 0 : @override
393 : void DeleteServerInfo(String profile, String handle) {
394 0 : cwtchPlatform.invokeMethod("DeleteServerInfo", {"ProfileOnion": profile, "handle": handle});
395 : }
396 :
397 0 : @override
398 : void UpdateSettings(String json) {
399 0 : cwtchPlatform.invokeMethod("UpdateSettings", {"json": json});
400 : }
401 :
402 0 : @override
403 : bool IsServersCompiled() {
404 : // never for android builds...
405 : return false;
406 : }
407 :
408 0 : @override
409 : Future<String> SummarizeConversation(String profile, int conversation) {
410 : // TODO: implement SummarizeConversation
411 0 : throw UnimplementedError();
412 : }
413 :
414 0 : @override
415 : Future<String> TranslateMessage(String profile, int conversation, int message, String language) {
416 : // TODO: implement TranslateMessage
417 0 : throw UnimplementedError();
418 : }
419 :
420 0 : @override
421 : bool IsBlodeuweddSupported() {
422 : // Blodeuwedd is not currently supported on lower end devices.
423 : return false;
424 : }
425 :
426 0 : @override
427 : Future<String?> GetProfileAttribute(String profile, String key) async {
428 0 : return await cwtchPlatform.invokeMethod("GetProfileAttribute", {"ProfileOnion": profile, "key": key}).then((dynamic json) {
429 0 : var value = jsonDecode(json);
430 0 : if (value["Exists"]) {
431 0 : return value["Value"];
432 : }
433 : return null;
434 : });
435 : }
436 :
437 0 : @override
438 : Future<String?> GetConversationAttribute(String profile, int conversation, String key) async {
439 0 : return await cwtchPlatform.invokeMethod("GetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "key": key}).then((dynamic json) {
440 0 : var value = jsonDecode(json);
441 0 : if (value["Exists"]) {
442 0 : return value["Value"];
443 : }
444 : return null;
445 : });
446 : }
447 :
448 0 : @override
449 : void AttemptReconnection(String profile, String onion) {
450 0 : cwtchPlatform.invokeMethod("PeerWithOnion", {"ProfileOnion": profile, "onion": onion});
451 : }
452 :
453 0 : @override
454 : void AttemptReconnectionServer(String profile, String onion) {
455 0 : cwtchPlatform.invokeMethod("QueueJoinServer", {"ProfileOnion": profile, "onion": onion});
456 : }
457 :
458 0 : @override
459 : void DisconnectFromPeer(String profile, String onion) {
460 0 : cwtchPlatform.invokeMethod("DisconnectFromPeer", {"ProfileOnion": profile, "onion": onion});
461 : }
462 :
463 0 : @override
464 : void DisconnectFromServer(String profile, String onion) {
465 0 : cwtchPlatform.invokeMethod("DisconnectFromServer", {"ProfileOnion": profile, "onion": onion});
466 : }
467 :
468 0 : @override
469 : Future<String> SearchConversations(String profile, String pattern) async {
470 0 : return await cwtchPlatform.invokeMethod("SearchConversations", {"ProfileOnion": profile, "pattern": pattern});
471 : }
472 :
473 0 : @override
474 : Future<void> ConfigureConnections(String profile, bool listen, bool peers, bool servers) async {
475 0 : cwtchPlatform.invokeMethod("ConfigureConnections", {"ProfileOnion": profile, "listen": listen, "peers": peers, "servers": servers});
476 : return;
477 : }
478 :
479 0 : @override
480 : void PublishServerUpdate(String profile) {
481 0 : cwtchPlatform.invokeMethod("PublishServerUpdate", {"ProfileOnion": profile});
482 : }
483 :
484 0 : @override
485 : bool IsLoaded() {
486 : return true;
487 : }
488 : }
|