Skip to content

Commit 97cb19f

Browse files
authored
Introduce new "identity" option. (#51)
This option defines whether identity name & signature should be included when composing outgoing e-mail, or is anonymous data (name from recipient & no signature) should be used instead for privacy.
1 parent 2951879 commit 97cb19f

File tree

7 files changed

+323
-116
lines changed

7 files changed

+323
-116
lines changed

config.inc.php.dist

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ $config = array();
1616
*/
1717
//$config['custom_from_compose_contains'] = '';
1818

19+
/*
20+
** Policy for using parameters (name, signature) of matched identity.
21+
*/
22+
//$config['custom_from_compose_identity'] = 'loose'; // 'exact', 'loose'
23+
1924
/*
2025
** List of allowed matching rules by header type. This define how addresses
2126
** from various e-mail headers can be used to guess custom address (only if

custom_from.php

+154-85
Large diffs are not rendered by default.

localization/de_DE.inc

+9-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
$labels = array();
44
$labels['preference'] = 'Antwortadresse (Custom From)';
55
$labels['preference_compose'] = 'Benutzerdefinierte Adresse beim Antworten auf eine E-Mail';
6-
$labels['preference_compose_contains'] = '...und enthält Text (optional)';
7-
$labels['preference_compose_subject'] = 'Aktivieren, wenn ein Empfänger';
8-
$labels['preference_compose_subject_always'] = 'Immer automatisch aktivieren';
9-
$labels['preference_compose_subject_domain'] = 'Verwendet dieselbe Domäne wie eine Identität';
10-
$labels['preference_compose_subject_exact'] = 'Ist genau eine meiner Identitäten';
6+
$labels['preference_compose_contains'] = '...und Empfängeradresse enthält;
7+
$labels['preference_compose_identity'] = 'Verwenden Sie den Namen und die Unterschrift der Identität';
8+
$labels['preference_compose_identity_exact'] = 'Wenn die Adresse genau übereinstimmt';
9+
$labels['preference_compose_identity_loose'] = 'Stets';
10+
$labels['preference_compose_subject'] = 'Aktivieren, wenn ein Empfänger';';
11+
$labels['preference_compose_subject_always'] = 'Immer mit Standardidentität aktivieren';
12+
$labels['preference_compose_subject_domain'] = 'Verwendet dieselbe Domäne wie einer der Empfänger';
13+
$labels['preference_compose_subject_exact'] = 'Ist einer der Empfänger';
1114
$labels['preference_compose_subject_never'] = 'Niemals automatisch aktivieren';
12-
$labels['preference_compose_subject_prefix'] = 'Ist eine meiner Identitäten mit +Suffix';
15+
$labels['preference_compose_subject_prefix'] = 'Ist einer der Empfänger mit dem Suffix +';
1316
$labels['custom_from_off'] = 'Identität auswählen';
1417
$labels['custom_from_off_hint'] = 'Absender aus Liste auswählen';
1518
$labels['custom_from_on'] = 'Frei wählbare Identität';

localization/en_US.inc

+9-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
$labels = array();
44
$labels['preference'] = 'Reply address (Custom From)';
55
$labels['preference_compose'] = 'Custom address when replying to an e-mail';
6-
$labels['preference_compose_contains'] = '...and contains text (optional)';
7-
$labels['preference_compose_subject'] = 'Enable when one recipient';
8-
$labels['preference_compose_subject_always'] = 'Always enable automatically';
9-
$labels['preference_compose_subject_domain'] = 'Uses same domain than an identity';
10-
$labels['preference_compose_subject_exact'] = 'Is exactly one of my identities';
6+
$labels['preference_compose_contains'] = '...and recipient address contains';
7+
$labels['preference_compose_identity'] = 'Use identity\'s name and signature';
8+
$labels['preference_compose_identity_exact'] = 'If address matches exactly';
9+
$labels['preference_compose_identity_loose'] = 'Always';
10+
$labels['preference_compose_subject'] = 'Enable when one of my identities';
11+
$labels['preference_compose_subject_always'] = 'Always enable with default identity';
12+
$labels['preference_compose_subject_domain'] = 'Uses same domain than one of recipients';
13+
$labels['preference_compose_subject_exact'] = 'Is one of the recipients';
1114
$labels['preference_compose_subject_never'] = 'Never enable automatically';
12-
$labels['preference_compose_subject_prefix'] = 'Is one of my identities with +suffix';
15+
$labels['preference_compose_subject_prefix'] = 'Is one of recipients with +suffix';
1316
$labels['custom_from_off'] = 'Select identity';
1417
$labels['custom_from_off_hint'] = 'Select sender from identities list';
1518
$labels['custom_from_on'] = 'Custom identity';

localization/fr_FR.inc

+9-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
$labels = array();
44
$labels['preference'] = 'Adresse de réponse (Custom From)';
55
$labels['preference_compose'] = 'Adresse personnalisée en réponse à un e-mail';
6-
$labels['preference_compose_contains'] = '...et contient le texte (optionel)';
7-
$labels['preference_compose_subject'] = 'Activer quand l\'un des destinataires';
8-
$labels['preference_compose_subject_always'] = 'Toujours activer automatiquement';
9-
$labels['preference_compose_subject_domain'] = 'Utilise le même domaine qu\'une identité';
10-
$labels['preference_compose_subject_exact'] = 'Est exactement l\'une de mes identités';
6+
$labels['preference_compose_contains'] = '...et l\'adresse du destinataire contient';
7+
$labels['preference_compose_identity'] = 'Utiliser nom et signature de l\'identité';
8+
$labels['preference_compose_identity_exact'] = 'Si l\'adresse correspond exactement';
9+
$labels['preference_compose_identity_loose'] = 'Toujours';
10+
$labels['preference_compose_subject'] = 'Activer si l\'une de mes identités';
11+
$labels['preference_compose_subject_always'] = 'Toujours activer avec l\'identité par défaut';
12+
$labels['preference_compose_subject_domain'] = 'Utilise le domaine d\'un des destinataires';
13+
$labels['preference_compose_subject_exact'] = 'Est parmis les destinataires';
1114
$labels['preference_compose_subject_never'] = 'Ne jamais activer automatiquement';
12-
$labels['preference_compose_subject_prefix'] = 'Est l\'une de mes identités avec +suffixe';
15+
$labels['preference_compose_subject_prefix'] = 'Est l\'un des destinataires avec +suffixe';
1316
$labels['custom_from_off'] = 'Choisir l\'identité';
1417
$labels['custom_from_off_hint'] = 'Choisir l\'expéditeur dans la liste des identités';
1518
$labels['custom_from_on'] = 'Identité libre';

tests/CustomFromTest.php

+114-9
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,44 @@ final class CustomFromTest extends TestCase
1414
{
1515
const CONTAINS = 'custom_from_compose_contains';
1616
const DISABLE = 'custom_from_preference_disable';
17+
const IDENTITY = 'custom_from_compose_identity';
1718
const RULES = 'custom_from_header_rules';
1819
const SUBJECT = 'custom_from_compose_subject';
1920

21+
public static function identity_select_should_select_matched_identity_provider(): array
22+
{
23+
return array(
24+
array('1', 0),
25+
array('2', 1),
26+
array('3', null)
27+
);
28+
}
29+
30+
#[DataProvider('identity_select_should_select_matched_identity_provider')]
31+
public function test_identity_select_should_select_matched_identity($identity, $expected): void
32+
{
33+
$rcmail = rcmail::mock();
34+
$rcmail->mock_config(array());
35+
$rcmail->mock_user(array(), array());
36+
37+
$plugin = self::create_plugin();
38+
39+
rcube_utils::mock_input_value('_id', '42');
40+
41+
self::set_state($plugin, '42', $identity, null);
42+
43+
$params = $plugin->identity_select(array('identities' => array(
44+
array('identity_id' => '1'),
45+
array('identity_id' => '2')
46+
)));
47+
48+
if ($expected !== null) {
49+
$this->assertSame($params['selected'], $expected);
50+
} else {
51+
$this->assertSame(isset($params['selected']), false);
52+
}
53+
}
54+
2055
public static function storage_init_should_fetch_headers_provider(): array
2156
{
2257
return array(
@@ -69,90 +104,142 @@ public static function message_compose_should_set_state_provider(): array
69104
array('to' => '[email protected]'),
70105
array(self::RULES => 'to=e'),
71106
array(),
72-
array('email' => null, 'id' => '1')
107+
'1',
108+
null
73109
),
74110
// Subject rule "exact" shouldn't match suffix
75111
array(
76112
array('to' => '[email protected]'),
77113
array(self::RULES => 'to=e'),
78114
array(),
79115
null,
116+
null,
80117
),
81118
// Subject rule "prefix" should match address exactly
82119
array(
83120
array('to' => '[email protected]'),
84121
array(),
85122
array(),
86-
array('email' => null, 'id' => '1')
123+
'1',
124+
null
87125
),
88126
// Subject rule "prefix" should match address by prefix
89127
array(
90128
array('to' => '[email protected]'),
91129
array(),
92130
array(),
93-
array('email' => '[email protected]', 'id' => '1')
131+
'1',
132+
94133
),
95134
// Subject rule "prefix" should not match different user
96135
array(
97136
array('to' => '[email protected]'),
98137
array(),
99138
array(),
100139
null,
140+
null,
101141
),
102142
// Subject rule "domain" on custom header should match address by domain
103143
array(
104144
array('to' => '[email protected]', 'x-custom' => '[email protected]'),
105145
array(self::RULES => 'x-custom=d'),
106146
array(),
107-
array('email' => '[email protected]', 'id' => '3')
147+
'3',
148+
108149
),
109150
// Subject rule "domain" should not match different domain
110151
array(
111152
array('to' => '[email protected]'),
112153
array(self::RULES => 'to=d'),
113154
array(),
114155
null,
156+
null,
115157
),
116158
// Subject rule "other" should match anything
117159
array(
118160
array('to' => '[email protected]'),
119161
array(self::RULES => 'to=o'),
120162
array(),
121-
array('email' => '[email protected]', 'id' => '2')
163+
'2',
164+
122165
),
123166
// Subject rule is overridden by user prefrences
124167
array(
125168
array('to' => '[email protected]'),
126169
array(self::RULES => 'to=e'),
127170
array(self::SUBJECT => 'domain'),
128-
array('email' => '[email protected]', 'id' => '3')
171+
'3',
172+
129173
),
130174
// Contains constraint in configuration options matches address
131175
array(
132176
array('to' => '[email protected]'),
133177
array(self::CONTAINS => 'match'),
134178
array(self::SUBJECT => 'domain'),
135-
array('email' => '[email protected]', 'id' => '1')
179+
'1',
180+
136181
),
137182
// Contains constraint in configuration options rejects no match
138183
array(
139184
array('to' => '[email protected]'),
140185
array(self::CONTAINS => 'match'),
141186
array(self::SUBJECT => 'domain'),
187+
null,
142188
null
143189
),
144190
// Contains constraint in user preferences rejects no match
145191
array(
146192
array('to' => '[email protected]'),
147193
array(self::CONTAINS => 'other'),
148194
array(self::CONTAINS => 'match', self::SUBJECT => 'always'),
195+
null,
196+
null
197+
),
198+
// Identity behavior "default" returns matched identity with no sender on exact match
199+
array(
200+
array('to' => '[email protected]'),
201+
array(),
202+
array(self::SUBJECT => 'always'),
203+
'3',
204+
null
205+
),
206+
// Identity behavior "default" returns matched identity and sender with identity name on domain match
207+
array(
208+
array('to' => '[email protected]'),
209+
array(),
210+
array(self::SUBJECT => 'domain'),
211+
'3',
212+
213+
),
214+
// Identity behavior "loose" returns matched identity and sender with identity name on prefix match
215+
array(
216+
array('to' => 'SomeName <[email protected]>'),
217+
array(),
218+
array(self::IDENTITY => 'loose', self::SUBJECT => 'prefix'),
219+
'3',
220+
221+
),
222+
// Identity behavior "exact" returns matched identity with no sender on exact match
223+
array(
224+
array('to' => '[email protected]'),
225+
array(self::IDENTITY => 'exact'),
226+
array(self::SUBJECT => 'always'),
227+
'3',
149228
null
150229
),
230+
// Identity behavior "exact" returns no identity and sender with recipient name on prefix match
231+
array(
232+
array('to' => 'SomeName <[email protected]>'),
233+
array(),
234+
array(self::IDENTITY => 'exact', self::SUBJECT => 'prefix'),
235+
null,
236+
'SomeName <[email protected]>'
237+
)
151238
);
152239
}
153240

154241
#[DataProvider('message_compose_should_set_state_provider')]
155-
public function test_message_compose_should_set_state($message, $config_values, $user_prefs, $expected): void
242+
public function test_message_compose_should_set_state($message, $config_values, $user_prefs, $expected_identity, $expected_sender): void
156243
{
157244
$identity1 = array('identity_id' => '1', 'email' => '[email protected]', 'name' => 'Alice', 'standard' => '0');
158245
$identity2 = array('identity_id' => '2', 'email' => '[email protected]', 'name' => 'Bob', 'standard' => '1');
@@ -168,7 +255,9 @@ public function test_message_compose_should_set_state($message, $config_values,
168255
$plugin = self::create_plugin();
169256
$plugin->message_compose(array('id' => $compose_id, 'param' => array('uid' => $message_id)));
170257

171-
$this->assertSame($_SESSION["custom_from_$compose_id"], $expected);
258+
$state = self::get_state($plugin, $compose_id);
259+
260+
$this->assertSame($state, array($expected_identity, $expected_sender));
172261
}
173262

174263
private static function create_plugin()
@@ -178,4 +267,20 @@ private static function create_plugin()
178267

179268
return $plugin;
180269
}
270+
271+
private static function get_state($plugin, $compose_id)
272+
{
273+
$class = new ReflectionClass($plugin);
274+
$method = $class->getMethod('get_state');
275+
276+
return $method->invokeArgs(null, array($compose_id));
277+
}
278+
279+
private static function set_state($plugin, $compose_id, $identity, $sender)
280+
{
281+
$class = new ReflectionClass($plugin);
282+
$method = $class->getMethod('set_state');
283+
284+
return $method->invokeArgs(null, array($compose_id, $identity, $sender));
285+
}
181286
}

tests/rcmail_mock.php

+23-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php
22

3-
function format_email_recipient($email)
3+
function format_email_recipient($email, $name)
44
{
5-
return $email;
5+
return $name . ' <' . $email . '>';
66
}
77

88
class rcmail
@@ -83,9 +83,11 @@ public function get($name)
8383

8484
class rcube_mime
8585
{
86-
public static function decode_address_list($address)
86+
public static function decode_address_list($input)
8787
{
88-
return array(array('mailto' => $address, 'name' => $address));
88+
return preg_match('/(.*) <(.*)>/', $input, $match) === 1
89+
? array(array('mailto' => $match[2], 'name' => $match[1]))
90+
: array(array('mailto' => $input, 'name' => $input));
8991
}
9092
}
9193

@@ -113,3 +115,20 @@ public function list_identities()
113115
return $this->identities;
114116
}
115117
}
118+
119+
class rcube_utils
120+
{
121+
public const INPUT_GET = 1;
122+
123+
private static $input_values = array();
124+
125+
public static function get_input_value($name, $mode)
126+
{
127+
return $mode === self::INPUT_GET ? self::$input_values[$name] : null;
128+
}
129+
130+
public static function mock_input_value($name, $value)
131+
{
132+
self::$input_values[$name] = $value;
133+
}
134+
}

0 commit comments

Comments
 (0)