Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/lib/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export 'utils/broadcast_channel/broadcast_channel.dart';
export 'utils/list_utils.dart';
export 'utils/mail/domain.dart';
export 'utils/mail/mail_address.dart';
export 'utils/mail/named_address.dart';
export 'utils/application_manager.dart';
export 'utils/preview_eml_file_utils.dart';
export 'utils/logger/log_tracking.dart';
Expand Down
14 changes: 14 additions & 0 deletions core/lib/utils/mail/named_address.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:equatable/equatable.dart';

class NamedAddress with EquatableMixin {
final String name;
final String address;

NamedAddress({required this.name, required this.address});

@override
List<Object?> get props => [name, address];

@override
String toString() => name.isNotEmpty ? '$name <$address>' : address;
}
59 changes: 59 additions & 0 deletions core/lib/utils/string_convert.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:typed_data';

import 'package:core/utils/app_logger.dart';
import 'package:core/domain/exceptions/string_exception.dart';
import 'package:core/utils/mail/named_address.dart';
import 'package:html/parser.dart';
import 'package:http_parser/http_parser.dart';

Expand Down Expand Up @@ -137,4 +138,62 @@ class StringConvert {
log('StringConvert::isTextTable:isMarkdown = $isMarkdown | isAscii = $isAsciiArt');
return isMarkdown || isAsciiArt;
}

static List<NamedAddress> extractNamedAddresses(String input) {
try {
if (input.contains('%')) {
input = Uri.decodeComponent(input);
}

if (input.length % 4 == 0 &&
input.contains(RegExp(r'^[A-Za-z0-9+/=]+$'))) {
try {
input = utf8.decode(base64.decode(input));
} catch (_) {}
}

input = input.replaceAll('\n', ' ');
final results = <NamedAddress>[];

final pattern = RegExp(r'''(?:"([^"]+)"|'([^']+)'|)\s*<([^>]+)>''');

int currentIndex = 0;
final matches = pattern.allMatches(input).toList();

for (final match in matches) {
if (match.start > currentIndex) {
final between = input.substring(currentIndex, match.start);
results.addAll(_splitPlainAddresses(between, emailSeparatorPattern));
}

final name = match.group(1) ?? match.group(2) ?? '';
final email = match.group(3) ?? '';
results.add(NamedAddress(name: name.trim(), address: email.trim()));

currentIndex = match.end;
}

if (currentIndex < input.length) {
final tail = input.substring(currentIndex);
results.addAll(_splitPlainAddresses(tail, emailSeparatorPattern));
}
log('StringConvert::extractNamedAddresses:results = $results');
return results;
} catch (_) {
return [];
}
}

static List<NamedAddress> _splitPlainAddresses(
String input,
String emailSeparatorPattern,
) {
final separator = RegExp(emailSeparatorPattern);
return input
.split(separator)
.map((e) => e.trim())
.where((e) => e.isNotEmpty)
.map((e) => NamedAddress(name: '', address: e))
.toList();
}
}
Loading
Loading