Passed
Push — master ( ae19cb...d3647d )
by Roeland
15:17 queued 10s
created
apps/settings/templates/settings/admin/sharing.php 2 patches
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -35,22 +35,22 @@  discard block
 block discarded – undo
35 35
 	<p id="enable">
36 36
 		<input type="checkbox" name="shareapi_enabled" id="shareAPIEnabled" class="checkbox"
37 37
 			   value="1" <?php if ($_['shareAPIEnabled'] === 'yes') {
38
-	print_unescaped('checked="checked"');
38
+    print_unescaped('checked="checked"');
39 39
 } ?> />
40 40
 		<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API'));?></label><br/>
41 41
 	</p>
42 42
 
43 43
 	<p id="internalShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
44
-	p('hidden');
44
+    p('hidden');
45 45
 } ?>">
46 46
 		<input type="checkbox" name="shareapi_default_internal_expire_date" id="shareapiDefaultInternalExpireDate" class="checkbox"
47 47
 			   value="1" <?php if ($_['shareDefaultInternalExpireDateSet'] === 'yes') {
48
-	print_unescaped('checked="checked"');
48
+    print_unescaped('checked="checked"');
49 49
 } ?> />
50 50
 		<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares'));?></label><br/>
51 51
 	</p>
52 52
 	<p id="setDefaultInternalExpireDate" class="double-indent <?php if ($_['shareDefaultInternalExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
53
-	p('hidden');
53
+    p('hidden');
54 54
 }?>">
55 55
 		<?php p($l->t('Expire after ')); ?>
56 56
 		<input type="text" name='shareapi_internal_expire_after_n_days' id="shareapiInternalExpireAfterNDays" placeholder="<?php p('7')?>"
@@ -58,49 +58,49 @@  discard block
 block discarded – undo
58 58
 		<?php p($l->t('days')); ?>
59 59
 		<input type="checkbox" name="shareapi_enforce_internal_expire_date" id="shareapiInternalEnforceExpireDate" class="checkbox"
60 60
 			   value="1" <?php if ($_['shareInternalEnforceExpireDate'] === 'yes') {
61
-	print_unescaped('checked="checked"');
61
+    print_unescaped('checked="checked"');
62 62
 } ?> />
63 63
 		<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
64 64
 	</p>
65 65
 
66 66
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
67
-	p('hidden');
67
+    p('hidden');
68 68
 }?>">
69 69
 		<input type="checkbox" name="shareapi_allow_links" id="allowLinks" class="checkbox"
70 70
 			   value="1" <?php if ($_['allowLinks'] === 'yes') {
71
-	print_unescaped('checked="checked"');
71
+    print_unescaped('checked="checked"');
72 72
 } ?> />
73 73
 		<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/>
74 74
 	</p>
75 75
 
76 76
 	<p id="publicLinkSettings" class="indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareAPIEnabled'] === 'no') {
77
-	p('hidden');
77
+    p('hidden');
78 78
 } ?>">
79 79
 		<input type="checkbox" name="shareapi_allow_public_upload" id="allowPublicUpload" class="checkbox"
80 80
 			   value="1" <?php if ($_['allowPublicUpload'] == 'yes') {
81
-	print_unescaped('checked="checked"');
81
+    print_unescaped('checked="checked"');
82 82
 } ?> />
83 83
 		<label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/>
84 84
 		<input type="checkbox" name="shareapi_enable_link_password_by_default" id="enableLinkPasswordByDefault" class="checkbox"
85 85
 			   value="1" <?php if ($_['enableLinkPasswordByDefault'] === 'yes') {
86
-	print_unescaped('checked="checked"');
86
+    print_unescaped('checked="checked"');
87 87
 } ?> />
88 88
 		<label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password'));?></label><br/>
89 89
 		<input type="checkbox" name="shareapi_enforce_links_password" id="enforceLinkPassword" class="checkbox"
90 90
 			   value="1" <?php if ($_['enforceLinkPassword']) {
91
-	print_unescaped('checked="checked"');
91
+    print_unescaped('checked="checked"');
92 92
 } ?> />
93 93
 		<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection'));?></label><br/>
94 94
 
95 95
 		<input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox"
96 96
 			   value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') {
97
-	print_unescaped('checked="checked"');
97
+    print_unescaped('checked="checked"');
98 98
 } ?> />
99 99
 		<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/>
100 100
 
101 101
 	</p>
102 102
 	<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
103
-	p('hidden');
103
+    p('hidden');
104 104
 }?>">
105 105
 		<?php p($l->t('Expire after ')); ?>
106 106
 		<input type="text" name='shareapi_expire_after_n_days' id="shareapiExpireAfterNDays" placeholder="<?php p('7')?>"
@@ -108,48 +108,48 @@  discard block
 block discarded – undo
108 108
 		<?php p($l->t('days')); ?>
109 109
 		<input type="checkbox" name="shareapi_enforce_expire_date" id="shareapiEnforceExpireDate" class="checkbox"
110 110
 			   value="1" <?php if ($_['shareEnforceExpireDate'] === 'yes') {
111
-	print_unescaped('checked="checked"');
111
+    print_unescaped('checked="checked"');
112 112
 } ?> />
113 113
 		<label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
114 114
 	</p>
115 115
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
116
-	p('hidden');
116
+    p('hidden');
117 117
 }?>">
118 118
 		<input type="checkbox" name="shareapi_allow_resharing" id="allowResharing" class="checkbox"
119 119
 			   value="1" <?php if ($_['allowResharing'] === 'yes') {
120
-	print_unescaped('checked="checked"');
120
+    print_unescaped('checked="checked"');
121 121
 } ?> />
122 122
 		<label for="allowResharing"><?php p($l->t('Allow resharing'));?></label><br/>
123 123
 	</p>
124 124
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
125
-	p('hidden');
125
+    p('hidden');
126 126
 }?>">
127 127
 		<input type="checkbox" name="shareapi_allow_group_sharing" id="allowGroupSharing" class="checkbox"
128 128
 			   value="1" <?php if ($_['allowGroupSharing'] === 'yes') {
129
-	print_unescaped('checked="checked"');
129
+    print_unescaped('checked="checked"');
130 130
 } ?> />
131 131
 		<label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups'));?></label><br />
132 132
 	</p>
133 133
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
134
-	p('hidden');
134
+    p('hidden');
135 135
 }?>">
136 136
 		<input type="checkbox" name="shareapi_only_share_with_group_members" id="onlyShareWithGroupMembers" class="checkbox"
137 137
 			   value="1" <?php if ($_['onlyShareWithGroupMembers']) {
138
-	print_unescaped('checked="checked"');
138
+    print_unescaped('checked="checked"');
139 139
 } ?> />
140 140
 		<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups'));?></label><br/>
141 141
 	</p>
142 142
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
143
-	p('hidden');
143
+    p('hidden');
144 144
 }?>">
145 145
 		<input type="checkbox" name="shareapi_exclude_groups" id="shareapiExcludeGroups" class="checkbox"
146 146
 			   value="1" <?php if ($_['shareExcludeGroups']) {
147
-	print_unescaped('checked="checked"');
147
+    print_unescaped('checked="checked"');
148 148
 } ?> />
149 149
 		<label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing'));?></label><br/>
150 150
 	</p>
151 151
 	<p id="selectExcludedGroups" class="indent <?php if (!$_['shareExcludeGroups'] || $_['shareAPIEnabled'] === 'no') {
152
-	p('hidden');
152
+    p('hidden');
153 153
 } ?>">
154 154
 		<input name="shareapi_exclude_groups_list" type="hidden" id="excludedGroups" value="<?php p($_['shareExcludedGroupsList']) ?>" style="width: 400px" class="noJSAutoUpdate"/>
155 155
 		<br />
@@ -157,45 +157,45 @@  discard block
 block discarded – undo
157 157
 	</p>
158 158
 
159 159
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
160
-	p('hidden');
160
+    p('hidden');
161 161
 }?>">
162 162
 		<input type="checkbox" name="shareapi_allow_share_dialog_user_enumeration" value="1" id="shareapi_allow_share_dialog_user_enumeration" class="checkbox"
163 163
 			<?php if ($_['allowShareDialogUserEnumeration'] === 'yes') {
164
-	print_unescaped('checked="checked"');
164
+    print_unescaped('checked="checked"');
165 165
 } ?> />
166 166
 		<label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog'));?></label><br />
167 167
 	</p>
168 168
 
169 169
 	<p id="shareapi_restrict_user_enumeration_to_group_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
170
-	p('hidden');
170
+    p('hidden');
171 171
 }?>">
172 172
 		<input type="checkbox" name="shareapi_restrict_user_enumeration_to_group" value="1" id="shareapi_restrict_user_enumeration_to_group" class="checkbox"
173 173
 			<?php if ($_['restrictUserEnumerationToGroup'] === 'yes') {
174
-	print_unescaped('checked="checked"');
174
+    print_unescaped('checked="checked"');
175 175
 } ?> />
176 176
 		<label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups'));?></label><br />
177 177
 	</p>
178 178
 
179 179
 	<p id="shareapi_restrict_user_enumeration_to_phone_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
180
-	p('hidden');
180
+    p('hidden');
181 181
 }?>">
182 182
 		<input type="checkbox" name="shareapi_restrict_user_enumeration_to_phone" value="1" id="shareapi_restrict_user_enumeration_to_phone" class="checkbox"
183 183
 			<?php if ($_['restrictUserEnumerationToPhone'] === 'yes') {
184
-	print_unescaped('checked="checked"');
184
+    print_unescaped('checked="checked"');
185 185
 } ?> />
186 186
 		<label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phonebook matches'));?></label><br />
187 187
 	</p>
188 188
 	<p id="shareapi_restrict_user_enumeration_combinewarning_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
189
-	p('hidden');
189
+    p('hidden');
190 190
 }?>">
191 191
 		<em><?php p($l->t('If autocompletion "same group" and "phonebook matches" are enabled a match in either is enough to show the user.'));?></em><br />
192 192
 	</p>
193 193
 	<p id="shareapi_restrict_user_enumeration_full_match_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
194
-	p('hidden');
194
+    p('hidden');
195 195
 }?>">
196 196
 		<input type="checkbox" name="shareapi_restrict_user_enumeration_full_match" value="1" id="shareapi_restrict_user_enumeration_full_match" class="checkbox"
197 197
 				<?php if ($_['restrictUserEnumerationFullMatch'] === 'yes') {
198
-	print_unescaped('checked="checked"');
198
+    print_unescaped('checked="checked"');
199 199
 } ?> />
200 200
 		<label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow username autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)'));?></label><br />
201 201
 	</p>
@@ -203,13 +203,13 @@  discard block
 block discarded – undo
203 203
 	<p>
204 204
 		<input type="checkbox" id="publicShareDisclaimer" class="checkbox noJSAutoUpdate"
205 205
 			<?php if ($_['publicShareDisclaimerText'] !== null) {
206
-	print_unescaped('checked="checked"');
206
+    print_unescaped('checked="checked"');
207 207
 } ?> />
208 208
 		<label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)'));?></label>
209 209
 		<span id="publicShareDisclaimerStatus" class="msg" style="display:none"></span>
210 210
 		<br/>
211 211
 		<textarea placeholder="<?php p($l->t('This text will be shown on the public link upload page when the file list is hidden.')) ?>" id="publicShareDisclaimerText" <?php if ($_['publicShareDisclaimerText'] === null) {
212
-	print_unescaped('class="hidden"');
212
+    print_unescaped('class="hidden"');
213 213
 } ?>><?php p($_['publicShareDisclaimerText']) ?></textarea>
214 214
 	</p>
215 215
 
@@ -217,12 +217,12 @@  discard block
 block discarded – undo
217 217
 	<input type="hidden" name="shareapi_default_permissions" id="shareApiDefaultPermissions" class="checkbox"
218 218
 		   value="<?php p($_['shareApiDefaultPermissions']) ?>" />
219 219
 	<p id="shareApiDefaultPermissionsSection" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
220
-	p('hidden');
220
+    p('hidden');
221 221
 } ?>">
222 222
 		<?php foreach ($_['shareApiDefaultPermissionsCheckboxes'] as $perm): ?>
223 223
 			<input type="checkbox" name="shareapi_default_permission_<?php p($perm['id']) ?>" id="shareapi_default_permission_<?php p($perm['id']) ?>"
224 224
 				   class="noautosave checkbox" value="<?php p($perm['value']) ?>" <?php if (($_['shareApiDefaultPermissions'] & $perm['value']) !== 0) {
225
-	print_unescaped('checked="checked"');
225
+    print_unescaped('checked="checked"');
226 226
 } ?> />
227 227
 			<label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']);?></label>
228 228
 		<?php endforeach ?>
Please login to merge, or discard this patch.
Spacing   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -27,17 +27,17 @@  discard block
 block discarded – undo
27 27
 ?>
28 28
 
29 29
 <div class="section" id="shareAPI">
30
-	<h2><?php p($l->t('Sharing'));?></h2>
30
+	<h2><?php p($l->t('Sharing')); ?></h2>
31 31
 	<a target="_blank" rel="noreferrer noopener" class="icon-info"
32
-	   title="<?php p($l->t('Open documentation'));?>"
32
+	   title="<?php p($l->t('Open documentation')); ?>"
33 33
 	   href="<?php p(link_to_docs('admin-sharing')); ?>"></a>
34
-        <p class="settings-hint"><?php p($l->t('As admin you can fine-tune the sharing behavior. Please see the documentation for more information.'));?></p>
34
+        <p class="settings-hint"><?php p($l->t('As admin you can fine-tune the sharing behavior. Please see the documentation for more information.')); ?></p>
35 35
 	<p id="enable">
36 36
 		<input type="checkbox" name="shareapi_enabled" id="shareAPIEnabled" class="checkbox"
37 37
 			   value="1" <?php if ($_['shareAPIEnabled'] === 'yes') {
38 38
 	print_unescaped('checked="checked"');
39 39
 } ?> />
40
-		<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API'));?></label><br/>
40
+		<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API')); ?></label><br/>
41 41
 	</p>
42 42
 
43 43
 	<p id="internalShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
 			   value="1" <?php if ($_['shareDefaultInternalExpireDateSet'] === 'yes') {
48 48
 	print_unescaped('checked="checked"');
49 49
 } ?> />
50
-		<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares'));?></label><br/>
50
+		<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for shares')); ?></label><br/>
51 51
 	</p>
52 52
 	<p id="setDefaultInternalExpireDate" class="double-indent <?php if ($_['shareDefaultInternalExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
53 53
 	p('hidden');
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
 			   value="1" <?php if ($_['shareInternalEnforceExpireDate'] === 'yes') {
61 61
 	print_unescaped('checked="checked"');
62 62
 } ?> />
63
-		<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
63
+		<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date')); ?></label><br/>
64 64
 	</p>
65 65
 
66 66
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
 			   value="1" <?php if ($_['allowLinks'] === 'yes') {
71 71
 	print_unescaped('checked="checked"');
72 72
 } ?> />
73
-		<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails'));?></label><br/>
73
+		<label for="allowLinks"><?php p($l->t('Allow users to share via link and emails')); ?></label><br/>
74 74
 	</p>
75 75
 
76 76
 	<p id="publicLinkSettings" class="indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareAPIEnabled'] === 'no') {
@@ -80,23 +80,23 @@  discard block
 block discarded – undo
80 80
 			   value="1" <?php if ($_['allowPublicUpload'] == 'yes') {
81 81
 	print_unescaped('checked="checked"');
82 82
 } ?> />
83
-		<label for="allowPublicUpload"><?php p($l->t('Allow public uploads'));?></label><br/>
83
+		<label for="allowPublicUpload"><?php p($l->t('Allow public uploads')); ?></label><br/>
84 84
 		<input type="checkbox" name="shareapi_enable_link_password_by_default" id="enableLinkPasswordByDefault" class="checkbox"
85 85
 			   value="1" <?php if ($_['enableLinkPasswordByDefault'] === 'yes') {
86 86
 	print_unescaped('checked="checked"');
87 87
 } ?> />
88
-		<label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password'));?></label><br/>
88
+		<label for="enableLinkPasswordByDefault"><?php p($l->t('Always ask for a password')); ?></label><br/>
89 89
 		<input type="checkbox" name="shareapi_enforce_links_password" id="enforceLinkPassword" class="checkbox"
90 90
 			   value="1" <?php if ($_['enforceLinkPassword']) {
91 91
 	print_unescaped('checked="checked"');
92 92
 } ?> />
93
-		<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection'));?></label><br/>
93
+		<label for="enforceLinkPassword"><?php p($l->t('Enforce password protection')); ?></label><br/>
94 94
 
95 95
 		<input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox"
96 96
 			   value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') {
97 97
 	print_unescaped('checked="checked"');
98 98
 } ?> />
99
-		<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/>
99
+		<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date')); ?></label><br/>
100 100
 
101 101
 	</p>
102 102
 	<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') {
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
 			   value="1" <?php if ($_['shareEnforceExpireDate'] === 'yes') {
111 111
 	print_unescaped('checked="checked"');
112 112
 } ?> />
113
-		<label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
113
+		<label for="shareapiEnforceExpireDate"><?php p($l->t('Enforce expiration date')); ?></label><br/>
114 114
 	</p>
115 115
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
116 116
 	p('hidden');
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
 			   value="1" <?php if ($_['allowResharing'] === 'yes') {
120 120
 	print_unescaped('checked="checked"');
121 121
 } ?> />
122
-		<label for="allowResharing"><?php p($l->t('Allow resharing'));?></label><br/>
122
+		<label for="allowResharing"><?php p($l->t('Allow resharing')); ?></label><br/>
123 123
 	</p>
124 124
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
125 125
 	p('hidden');
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
 			   value="1" <?php if ($_['allowGroupSharing'] === 'yes') {
129 129
 	print_unescaped('checked="checked"');
130 130
 } ?> />
131
-		<label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups'));?></label><br />
131
+		<label for="allowGroupSharing"><?php p($l->t('Allow sharing with groups')); ?></label><br />
132 132
 	</p>
133 133
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
134 134
 	p('hidden');
@@ -137,7 +137,7 @@  discard block
 block discarded – undo
137 137
 			   value="1" <?php if ($_['onlyShareWithGroupMembers']) {
138 138
 	print_unescaped('checked="checked"');
139 139
 } ?> />
140
-		<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups'));?></label><br/>
140
+		<label for="onlyShareWithGroupMembers"><?php p($l->t('Restrict users to only share with users in their groups')); ?></label><br/>
141 141
 	</p>
142 142
 	<p class="<?php if ($_['shareAPIEnabled'] === 'no') {
143 143
 	p('hidden');
@@ -146,7 +146,7 @@  discard block
 block discarded – undo
146 146
 			   value="1" <?php if ($_['shareExcludeGroups']) {
147 147
 	print_unescaped('checked="checked"');
148 148
 } ?> />
149
-		<label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing'));?></label><br/>
149
+		<label for="shareapiExcludeGroups"><?php p($l->t('Exclude groups from sharing')); ?></label><br/>
150 150
 	</p>
151 151
 	<p id="selectExcludedGroups" class="indent <?php if (!$_['shareExcludeGroups'] || $_['shareAPIEnabled'] === 'no') {
152 152
 	p('hidden');
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 			<?php if ($_['allowShareDialogUserEnumeration'] === 'yes') {
164 164
 	print_unescaped('checked="checked"');
165 165
 } ?> />
166
-		<label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog'));?></label><br />
166
+		<label for="shareapi_allow_share_dialog_user_enumeration"><?php p($l->t('Allow username autocompletion in share dialog')); ?></label><br />
167 167
 	</p>
168 168
 
169 169
 	<p id="shareapi_restrict_user_enumeration_to_group_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
 			<?php if ($_['restrictUserEnumerationToGroup'] === 'yes') {
174 174
 	print_unescaped('checked="checked"');
175 175
 } ?> />
176
-		<label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups'));?></label><br />
176
+		<label for="shareapi_restrict_user_enumeration_to_group"><?php p($l->t('Allow username autocompletion to users within the same groups')); ?></label><br />
177 177
 	</p>
178 178
 
179 179
 	<p id="shareapi_restrict_user_enumeration_to_phone_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
@@ -183,12 +183,12 @@  discard block
 block discarded – undo
183 183
 			<?php if ($_['restrictUserEnumerationToPhone'] === 'yes') {
184 184
 	print_unescaped('checked="checked"');
185 185
 } ?> />
186
-		<label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phonebook matches'));?></label><br />
186
+		<label for="shareapi_restrict_user_enumeration_to_phone"><?php p($l->t('Allow username autocompletion to users based on phonebook matches')); ?></label><br />
187 187
 	</p>
188 188
 	<p id="shareapi_restrict_user_enumeration_combinewarning_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no' || $_['allowShareDialogUserEnumeration'] === 'no') {
189 189
 	p('hidden');
190 190
 }?>">
191
-		<em><?php p($l->t('If autocompletion "same group" and "phonebook matches" are enabled a match in either is enough to show the user.'));?></em><br />
191
+		<em><?php p($l->t('If autocompletion "same group" and "phonebook matches" are enabled a match in either is enough to show the user.')); ?></em><br />
192 192
 	</p>
193 193
 	<p id="shareapi_restrict_user_enumeration_full_match_setting" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
194 194
 	p('hidden');
@@ -197,7 +197,7 @@  discard block
 block discarded – undo
197 197
 				<?php if ($_['restrictUserEnumerationFullMatch'] === 'yes') {
198 198
 	print_unescaped('checked="checked"');
199 199
 } ?> />
200
-		<label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow username autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)'));?></label><br />
200
+		<label for="shareapi_restrict_user_enumeration_full_match"><?php p($l->t('Allow username autocompletion when entering the full name or email address (ignoring missing phonebook match and being in the same group)')); ?></label><br />
201 201
 	</p>
202 202
 
203 203
 	<p>
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 			<?php if ($_['publicShareDisclaimerText'] !== null) {
206 206
 	print_unescaped('checked="checked"');
207 207
 } ?> />
208
-		<label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)'));?></label>
208
+		<label for="publicShareDisclaimer"><?php p($l->t('Show disclaimer text on the public link upload page (only shown when the file list is hidden)')); ?></label>
209 209
 		<span id="publicShareDisclaimerStatus" class="msg" style="display:none"></span>
210 210
 		<br/>
211 211
 		<textarea placeholder="<?php p($l->t('This text will be shown on the public link upload page when the file list is hidden.')) ?>" id="publicShareDisclaimerText" <?php if ($_['publicShareDisclaimerText'] === null) {
@@ -213,7 +213,7 @@  discard block
 block discarded – undo
213 213
 } ?>><?php p($_['publicShareDisclaimerText']) ?></textarea>
214 214
 	</p>
215 215
 
216
-	<h3><?php p($l->t('Default share permissions'));?></h3>
216
+	<h3><?php p($l->t('Default share permissions')); ?></h3>
217 217
 	<input type="hidden" name="shareapi_default_permissions" id="shareApiDefaultPermissions" class="checkbox"
218 218
 		   value="<?php p($_['shareApiDefaultPermissions']) ?>" />
219 219
 	<p id="shareApiDefaultPermissionsSection" class="indent <?php if ($_['shareAPIEnabled'] === 'no') {
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 				   class="noautosave checkbox" value="<?php p($perm['value']) ?>" <?php if (($_['shareApiDefaultPermissions'] & $perm['value']) !== 0) {
225 225
 	print_unescaped('checked="checked"');
226 226
 } ?> />
227
-			<label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']);?></label>
227
+			<label for="shareapi_default_permission_<?php p($perm['id']) ?>"><?php p($perm['label']); ?></label>
228 228
 		<?php endforeach ?>
229 229
 	</p>
230 230
 </div>
Please login to merge, or discard this patch.
apps/sharebymail/templates/settings-admin.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -11,12 +11,12 @@
 block discarded – undo
11 11
 
12 12
 	<p>
13 13
 		<input id="sendPasswordMail" type="checkbox" class="checkbox" <?php if ($_['sendPasswordMail']) {
14
-	p('checked');
14
+    p('checked');
15 15
 } ?> />
16 16
 		<label for="sendPasswordMail"><?php p($l->t('Send password by mail')); ?></label><br/>
17 17
 
18 18
 		<input id="replyToInitiator" type="checkbox" class="checkbox" <?php if ($_['replyToInitiator']) {
19
-	p('checked');
19
+    p('checked');
20 20
 } ?> />
21 21
 		<label for="replyToInitiator"><?php p($l->t('Reply to initiator')); ?></label>
22 22
 	</p>
Please login to merge, or discard this patch.
apps/sharebymail/lib/ShareByMailProvider.php 2 patches
Indentation   +1118 added lines, -1118 removed lines patch added patch discarded remove patch
@@ -72,1129 +72,1129 @@
 block discarded – undo
72 72
  */
73 73
 class ShareByMailProvider implements IShareProvider {
74 74
 
75
-	/** @var  IDBConnection */
76
-	private $dbConnection;
77
-
78
-	/** @var ILogger */
79
-	private $logger;
80
-
81
-	/** @var ISecureRandom */
82
-	private $secureRandom;
83
-
84
-	/** @var IUserManager */
85
-	private $userManager;
86
-
87
-	/** @var IRootFolder */
88
-	private $rootFolder;
89
-
90
-	/** @var IL10N */
91
-	private $l;
92
-
93
-	/** @var IMailer */
94
-	private $mailer;
95
-
96
-	/** @var IURLGenerator */
97
-	private $urlGenerator;
98
-
99
-	/** @var IManager  */
100
-	private $activityManager;
101
-
102
-	/** @var SettingsManager */
103
-	private $settingsManager;
104
-
105
-	/** @var Defaults */
106
-	private $defaults;
107
-
108
-	/** @var IHasher */
109
-	private $hasher;
110
-
111
-	/** @var IEventDispatcher */
112
-	private $eventDispatcher;
113
-
114
-	/** @var IShareManager */
115
-	private $shareManager;
116
-
117
-	/**
118
-	 * Return the identifier of this provider.
119
-	 *
120
-	 * @return string Containing only [a-zA-Z0-9]
121
-	 */
122
-	public function identifier() {
123
-		return 'ocMailShare';
124
-	}
125
-
126
-	public function __construct(IDBConnection $connection,
127
-								ISecureRandom $secureRandom,
128
-								IUserManager $userManager,
129
-								IRootFolder $rootFolder,
130
-								IL10N $l,
131
-								ILogger $logger,
132
-								IMailer $mailer,
133
-								IURLGenerator $urlGenerator,
134
-								IManager $activityManager,
135
-								SettingsManager $settingsManager,
136
-								Defaults $defaults,
137
-								IHasher $hasher,
138
-								IEventDispatcher $eventDispatcher,
139
-								IShareManager $shareManager) {
140
-		$this->dbConnection = $connection;
141
-		$this->secureRandom = $secureRandom;
142
-		$this->userManager = $userManager;
143
-		$this->rootFolder = $rootFolder;
144
-		$this->l = $l;
145
-		$this->logger = $logger;
146
-		$this->mailer = $mailer;
147
-		$this->urlGenerator = $urlGenerator;
148
-		$this->activityManager = $activityManager;
149
-		$this->settingsManager = $settingsManager;
150
-		$this->defaults = $defaults;
151
-		$this->hasher = $hasher;
152
-		$this->eventDispatcher = $eventDispatcher;
153
-		$this->shareManager = $shareManager;
154
-	}
155
-
156
-	/**
157
-	 * Share a path
158
-	 *
159
-	 * @param IShare $share
160
-	 * @return IShare The share object
161
-	 * @throws ShareNotFound
162
-	 * @throws \Exception
163
-	 */
164
-	public function create(IShare $share) {
165
-		$shareWith = $share->getSharedWith();
166
-		/*
75
+    /** @var  IDBConnection */
76
+    private $dbConnection;
77
+
78
+    /** @var ILogger */
79
+    private $logger;
80
+
81
+    /** @var ISecureRandom */
82
+    private $secureRandom;
83
+
84
+    /** @var IUserManager */
85
+    private $userManager;
86
+
87
+    /** @var IRootFolder */
88
+    private $rootFolder;
89
+
90
+    /** @var IL10N */
91
+    private $l;
92
+
93
+    /** @var IMailer */
94
+    private $mailer;
95
+
96
+    /** @var IURLGenerator */
97
+    private $urlGenerator;
98
+
99
+    /** @var IManager  */
100
+    private $activityManager;
101
+
102
+    /** @var SettingsManager */
103
+    private $settingsManager;
104
+
105
+    /** @var Defaults */
106
+    private $defaults;
107
+
108
+    /** @var IHasher */
109
+    private $hasher;
110
+
111
+    /** @var IEventDispatcher */
112
+    private $eventDispatcher;
113
+
114
+    /** @var IShareManager */
115
+    private $shareManager;
116
+
117
+    /**
118
+     * Return the identifier of this provider.
119
+     *
120
+     * @return string Containing only [a-zA-Z0-9]
121
+     */
122
+    public function identifier() {
123
+        return 'ocMailShare';
124
+    }
125
+
126
+    public function __construct(IDBConnection $connection,
127
+                                ISecureRandom $secureRandom,
128
+                                IUserManager $userManager,
129
+                                IRootFolder $rootFolder,
130
+                                IL10N $l,
131
+                                ILogger $logger,
132
+                                IMailer $mailer,
133
+                                IURLGenerator $urlGenerator,
134
+                                IManager $activityManager,
135
+                                SettingsManager $settingsManager,
136
+                                Defaults $defaults,
137
+                                IHasher $hasher,
138
+                                IEventDispatcher $eventDispatcher,
139
+                                IShareManager $shareManager) {
140
+        $this->dbConnection = $connection;
141
+        $this->secureRandom = $secureRandom;
142
+        $this->userManager = $userManager;
143
+        $this->rootFolder = $rootFolder;
144
+        $this->l = $l;
145
+        $this->logger = $logger;
146
+        $this->mailer = $mailer;
147
+        $this->urlGenerator = $urlGenerator;
148
+        $this->activityManager = $activityManager;
149
+        $this->settingsManager = $settingsManager;
150
+        $this->defaults = $defaults;
151
+        $this->hasher = $hasher;
152
+        $this->eventDispatcher = $eventDispatcher;
153
+        $this->shareManager = $shareManager;
154
+    }
155
+
156
+    /**
157
+     * Share a path
158
+     *
159
+     * @param IShare $share
160
+     * @return IShare The share object
161
+     * @throws ShareNotFound
162
+     * @throws \Exception
163
+     */
164
+    public function create(IShare $share) {
165
+        $shareWith = $share->getSharedWith();
166
+        /*
167 167
 		 * Check if file is not already shared with the remote user
168 168
 		 */
169
-		$alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_EMAIL, $share->getNode(), 1, 0);
170
-		if (!empty($alreadyShared)) {
171
-			$message = 'Sharing %1$s failed, this item is already shared with %2$s';
172
-			$message_t = $this->l->t('Sharing %1$s failed, this item is already shared with %2$s', [$share->getNode()->getName(), $shareWith]);
173
-			$this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
174
-			throw new \Exception($message_t);
175
-		}
176
-
177
-		// if the admin enforces a password for all mail shares we create a
178
-		// random password and send it to the recipient
179
-		$password = $share->getPassword() ?: '';
180
-		$passwordEnforced = $this->shareManager->shareApiLinkEnforcePassword();
181
-		if ($passwordEnforced && empty($password)) {
182
-			$password = $this->autoGeneratePassword($share);
183
-		}
184
-
185
-		if (!empty($password)) {
186
-			$share->setPassword($this->hasher->hash($password));
187
-		}
188
-
189
-		$shareId = $this->createMailShare($share);
190
-		$send = $this->sendPassword($share, $password);
191
-		if ($passwordEnforced && $send === false) {
192
-			$this->sendPasswordToOwner($share, $password);
193
-		}
194
-
195
-		$this->createShareActivity($share);
196
-		$data = $this->getRawShare($shareId);
197
-
198
-		return $this->createShareObject($data);
199
-	}
200
-
201
-	/**
202
-	 * auto generate password in case of password enforcement on mail shares
203
-	 *
204
-	 * @param IShare $share
205
-	 * @return string
206
-	 * @throws \Exception
207
-	 */
208
-	protected function autoGeneratePassword($share) {
209
-		$initiatorUser = $this->userManager->get($share->getSharedBy());
210
-		$initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
211
-		$allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
212
-
213
-		if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
214
-			throw new \Exception(
215
-				$this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
216
-			);
217
-		}
218
-
219
-		$passwordEvent = new GenerateSecurePasswordEvent();
220
-		$this->eventDispatcher->dispatchTyped($passwordEvent);
221
-
222
-		$password = $passwordEvent->getPassword();
223
-		if ($password === null) {
224
-			$password = $this->secureRandom->generate(8, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
225
-		}
226
-
227
-		return $password;
228
-	}
229
-
230
-	/**
231
-	 * create activity if a file/folder was shared by mail
232
-	 *
233
-	 * @param IShare $share
234
-	 * @param string $type
235
-	 */
236
-	protected function createShareActivity(IShare $share, string $type = 'share') {
237
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
238
-
239
-		$this->publishActivity(
240
-			$type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_SELF : Activity::SUBJECT_UNSHARED_EMAIL_SELF,
241
-			[$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
242
-			$share->getSharedBy(),
243
-			$share->getNode()->getId(),
244
-			(string) $userFolder->getRelativePath($share->getNode()->getPath())
245
-		);
246
-
247
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
248
-			$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
249
-			$fileId = $share->getNode()->getId();
250
-			$nodes = $ownerFolder->getById($fileId);
251
-			$ownerPath = $nodes[0]->getPath();
252
-			$this->publishActivity(
253
-				$type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_BY : Activity::SUBJECT_UNSHARED_EMAIL_BY,
254
-				[$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
255
-				$share->getShareOwner(),
256
-				$fileId,
257
-				(string) $ownerFolder->getRelativePath($ownerPath)
258
-			);
259
-		}
260
-	}
261
-
262
-	/**
263
-	 * create activity if a file/folder was shared by mail
264
-	 *
265
-	 * @param IShare $share
266
-	 * @param string $sharedWith
267
-	 * @param bool $sendToSelf
268
-	 */
269
-	protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
270
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
271
-
272
-		if ($sendToSelf) {
273
-			$this->publishActivity(
274
-				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
275
-				[$userFolder->getRelativePath($share->getNode()->getPath())],
276
-				$share->getSharedBy(),
277
-				$share->getNode()->getId(),
278
-				(string) $userFolder->getRelativePath($share->getNode()->getPath())
279
-			);
280
-		} else {
281
-			$this->publishActivity(
282
-				Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
283
-				[$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
284
-				$share->getSharedBy(),
285
-				$share->getNode()->getId(),
286
-				(string) $userFolder->getRelativePath($share->getNode()->getPath())
287
-			);
288
-		}
289
-	}
290
-
291
-
292
-	/**
293
-	 * publish activity if a file/folder was shared by mail
294
-	 *
295
-	 * @param string $subject
296
-	 * @param array $parameters
297
-	 * @param string $affectedUser
298
-	 * @param int $fileId
299
-	 * @param string $filePath
300
-	 */
301
-	protected function publishActivity(string $subject, array $parameters, string $affectedUser, int $fileId, string $filePath) {
302
-		$event = $this->activityManager->generateEvent();
303
-		$event->setApp('sharebymail')
304
-			->setType('shared')
305
-			->setSubject($subject, $parameters)
306
-			->setAffectedUser($affectedUser)
307
-			->setObject('files', $fileId, $filePath);
308
-		$this->activityManager->publish($event);
309
-	}
310
-
311
-	/**
312
-	 * @param IShare $share
313
-	 * @return int
314
-	 * @throws \Exception
315
-	 */
316
-	protected function createMailShare(IShare $share) {
317
-		$share->setToken($this->generateToken());
318
-		$shareId = $this->addShareToDB(
319
-			$share->getNodeId(),
320
-			$share->getNodeType(),
321
-			$share->getSharedWith(),
322
-			$share->getSharedBy(),
323
-			$share->getShareOwner(),
324
-			$share->getPermissions(),
325
-			$share->getToken(),
326
-			$share->getPassword(),
327
-			$share->getSendPasswordByTalk(),
328
-			$share->getHideDownload(),
329
-			$share->getLabel(),
330
-			$share->getExpirationDate()
331
-		);
332
-
333
-		try {
334
-			$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
335
-				['token' => $share->getToken()]);
336
-			$this->sendMailNotification(
337
-				$share->getNode()->getName(),
338
-				$link,
339
-				$share->getSharedBy(),
340
-				$share->getSharedWith(),
341
-				$share->getExpirationDate()
342
-			);
343
-		} catch (HintException $hintException) {
344
-			$this->logger->logException($hintException, [
345
-				'message' => 'Failed to send share by mail.',
346
-				'level' => ILogger::ERROR,
347
-				'app' => 'sharebymail',
348
-			]);
349
-			$this->removeShareFromTable($shareId);
350
-			throw $hintException;
351
-		} catch (\Exception $e) {
352
-			$this->logger->logException($e, [
353
-				'message' => 'Failed to send share by mail.',
354
-				'level' => ILogger::ERROR,
355
-				'app' => 'sharebymail',
356
-			]);
357
-			$this->removeShareFromTable($shareId);
358
-			throw new HintException('Failed to send share by mail',
359
-				$this->l->t('Failed to send share by email'));
360
-		}
361
-
362
-		return $shareId;
363
-	}
364
-
365
-	/**
366
-	 * @param string $filename
367
-	 * @param string $link
368
-	 * @param string $initiator
369
-	 * @param string $shareWith
370
-	 * @param \DateTime|null $expiration
371
-	 * @throws \Exception If mail couldn't be sent
372
-	 */
373
-	protected function sendMailNotification($filename,
374
-											$link,
375
-											$initiator,
376
-											$shareWith,
377
-											\DateTime $expiration = null) {
378
-		$initiatorUser = $this->userManager->get($initiator);
379
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
380
-		$message = $this->mailer->createMessage();
381
-
382
-		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [
383
-			'filename' => $filename,
384
-			'link' => $link,
385
-			'initiator' => $initiatorDisplayName,
386
-			'expiration' => $expiration,
387
-			'shareWith' => $shareWith,
388
-		]);
389
-
390
-		$emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
391
-		$emailTemplate->addHeader();
392
-		$emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
393
-		$text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
394
-
395
-		$emailTemplate->addBodyText(
396
-			htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')),
397
-			$text
398
-		);
399
-		$emailTemplate->addBodyButton(
400
-			$this->l->t('Open »%s«', [$filename]),
401
-			$link
402
-		);
403
-
404
-		$message->setTo([$shareWith]);
405
-
406
-		// The "From" contains the sharers name
407
-		$instanceName = $this->defaults->getName();
408
-		$senderName = $instanceName;
409
-		if ($this->settingsManager->replyToInitiator()) {
410
-			$senderName = $this->l->t(
411
-				'%1$s via %2$s',
412
-				[
413
-					$initiatorDisplayName,
414
-					$instanceName
415
-				]
416
-			);
417
-		}
418
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
419
-
420
-		// The "Reply-To" is set to the sharer if an mail address is configured
421
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
422
-		$initiatorEmail = $initiatorUser->getEMailAddress();
423
-		if ($this->settingsManager->replyToInitiator() && $initiatorEmail !== null) {
424
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
425
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
426
-		} else {
427
-			$emailTemplate->addFooter();
428
-		}
429
-
430
-		$message->useTemplate($emailTemplate);
431
-		$this->mailer->send($message);
432
-	}
433
-
434
-	/**
435
-	 * send password to recipient of a mail share
436
-	 *
437
-	 * @param IShare $share
438
-	 * @param string $password
439
-	 * @return bool
440
-	 */
441
-	protected function sendPassword(IShare $share, $password) {
442
-		$filename = $share->getNode()->getName();
443
-		$initiator = $share->getSharedBy();
444
-		$shareWith = $share->getSharedWith();
445
-
446
-		if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) {
447
-			return false;
448
-		}
449
-
450
-		$initiatorUser = $this->userManager->get($initiator);
451
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
452
-		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
453
-
454
-		$plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
455
-		$htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
456
-
457
-		$message = $this->mailer->createMessage();
458
-
459
-		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [
460
-			'filename' => $filename,
461
-			'password' => $password,
462
-			'initiator' => $initiatorDisplayName,
463
-			'initiatorEmail' => $initiatorEmailAddress,
464
-			'shareWith' => $shareWith,
465
-		]);
466
-
467
-		$emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName]));
468
-		$emailTemplate->addHeader();
469
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
470
-		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
471
-		$emailTemplate->addBodyText($this->l->t('It is protected with the following password:'));
472
-		$emailTemplate->addBodyText($password);
473
-
474
-		// The "From" contains the sharers name
475
-		$instanceName = $this->defaults->getName();
476
-		$senderName = $instanceName;
477
-		if ($this->settingsManager->replyToInitiator()) {
478
-			$senderName = $this->l->t(
479
-				'%1$s via %2$s',
480
-				[
481
-					$initiatorDisplayName,
482
-					$instanceName
483
-				]
484
-			);
485
-		}
486
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
487
-		if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
488
-			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
489
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
490
-		} else {
491
-			$emailTemplate->addFooter();
492
-		}
493
-
494
-		$message->setTo([$shareWith]);
495
-		$message->useTemplate($emailTemplate);
496
-		$this->mailer->send($message);
497
-
498
-		$this->createPasswordSendActivity($share, $shareWith, false);
499
-
500
-		return true;
501
-	}
502
-
503
-	protected function sendNote(IShare $share) {
504
-		$recipient = $share->getSharedWith();
505
-
506
-
507
-		$filename = $share->getNode()->getName();
508
-		$initiator = $share->getSharedBy();
509
-		$note = $share->getNote();
510
-
511
-		$initiatorUser = $this->userManager->get($initiator);
512
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
513
-		$initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
514
-
515
-		$plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]);
516
-		$htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]);
517
-
518
-		$message = $this->mailer->createMessage();
519
-
520
-		$emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote');
521
-
522
-		$emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName]));
523
-		$emailTemplate->addHeader();
524
-		$emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading);
525
-		$emailTemplate->addBodyText(htmlspecialchars($note), $note);
526
-
527
-		$link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
528
-			['token' => $share->getToken()]);
529
-		$emailTemplate->addBodyButton(
530
-			$this->l->t('Open »%s«', [$filename]),
531
-			$link
532
-		);
533
-
534
-		// The "From" contains the sharers name
535
-		$instanceName = $this->defaults->getName();
536
-		$senderName = $instanceName;
537
-		if ($this->settingsManager->replyToInitiator()) {
538
-			$senderName = $this->l->t(
539
-				'%1$s via %2$s',
540
-				[
541
-					$initiatorDisplayName,
542
-					$instanceName
543
-				]
544
-			);
545
-		}
546
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
547
-		if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
548
-			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
549
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
550
-		} else {
551
-			$emailTemplate->addFooter();
552
-		}
553
-
554
-		$message->setTo([$recipient]);
555
-		$message->useTemplate($emailTemplate);
556
-		$this->mailer->send($message);
557
-	}
558
-
559
-	/**
560
-	 * send auto generated password to the owner. This happens if the admin enforces
561
-	 * a password for mail shares and forbid to send the password by mail to the recipient
562
-	 *
563
-	 * @param IShare $share
564
-	 * @param string $password
565
-	 * @return bool
566
-	 * @throws \Exception
567
-	 */
568
-	protected function sendPasswordToOwner(IShare $share, $password) {
569
-		$filename = $share->getNode()->getName();
570
-		$initiator = $this->userManager->get($share->getSharedBy());
571
-		$initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
572
-		$initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
573
-		$shareWith = $share->getSharedWith();
574
-
575
-		if ($initiatorEMailAddress === null) {
576
-			throw new \Exception(
577
-				$this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
578
-			);
579
-		}
580
-
581
-		$bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already sent to the recipient. Due to the security policies defined by the administrator of %3$s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.', [$filename, $shareWith, $this->defaults->getName()]);
582
-
583
-		$message = $this->mailer->createMessage();
584
-		$emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [
585
-			'filename' => $filename,
586
-			'password' => $password,
587
-			'initiator' => $initiatorDisplayName,
588
-			'initiatorEmail' => $initiatorEMailAddress,
589
-			'shareWith' => $shareWith,
590
-		]);
591
-
592
-		$emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared by you with %2$s', [$filename, $shareWith]));
593
-		$emailTemplate->addHeader();
594
-		$emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
595
-		$emailTemplate->addBodyText($bodyPart);
596
-		$emailTemplate->addBodyText($this->l->t('This is the password:'));
597
-		$emailTemplate->addBodyText($password);
598
-		$emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
599
-		$emailTemplate->addFooter();
600
-
601
-		$instanceName = $this->defaults->getName();
602
-		$senderName = $this->l->t(
603
-			'%1$s via %2$s',
604
-			[
605
-				$initiatorDisplayName,
606
-				$instanceName
607
-			]
608
-		);
609
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
610
-		$message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
611
-		$message->useTemplate($emailTemplate);
612
-		$this->mailer->send($message);
613
-
614
-		$this->createPasswordSendActivity($share, $shareWith, true);
615
-
616
-		return true;
617
-	}
618
-
619
-	/**
620
-	 * generate share token
621
-	 *
622
-	 * @return string
623
-	 */
624
-	protected function generateToken($size = 15) {
625
-		$token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
626
-		return $token;
627
-	}
628
-
629
-	/**
630
-	 * Get all children of this share
631
-	 *
632
-	 * @param IShare $parent
633
-	 * @return IShare[]
634
-	 */
635
-	public function getChildren(IShare $parent) {
636
-		$children = [];
637
-
638
-		$qb = $this->dbConnection->getQueryBuilder();
639
-		$qb->select('*')
640
-			->from('share')
641
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
642
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
643
-			->orderBy('id');
644
-
645
-		$cursor = $qb->execute();
646
-		while ($data = $cursor->fetch()) {
647
-			$children[] = $this->createShareObject($data);
648
-		}
649
-		$cursor->closeCursor();
650
-
651
-		return $children;
652
-	}
653
-
654
-	/**
655
-	 * add share to the database and return the ID
656
-	 *
657
-	 * @param int $itemSource
658
-	 * @param string $itemType
659
-	 * @param string $shareWith
660
-	 * @param string $sharedBy
661
-	 * @param string $uidOwner
662
-	 * @param int $permissions
663
-	 * @param string $token
664
-	 * @param string $password
665
-	 * @param bool $sendPasswordByTalk
666
-	 * @param bool $hideDownload
667
-	 * @param string $label
668
-	 * @param \DateTime|null $expirationTime
669
-	 * @return int
670
-	 */
671
-	protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password, $sendPasswordByTalk, $hideDownload, $label, $expirationTime) {
672
-		$qb = $this->dbConnection->getQueryBuilder();
673
-		$qb->insert('share')
674
-			->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))
675
-			->setValue('item_type', $qb->createNamedParameter($itemType))
676
-			->setValue('item_source', $qb->createNamedParameter($itemSource))
677
-			->setValue('file_source', $qb->createNamedParameter($itemSource))
678
-			->setValue('share_with', $qb->createNamedParameter($shareWith))
679
-			->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
680
-			->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
681
-			->setValue('permissions', $qb->createNamedParameter($permissions))
682
-			->setValue('token', $qb->createNamedParameter($token))
683
-			->setValue('password', $qb->createNamedParameter($password))
684
-			->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL))
685
-			->setValue('stime', $qb->createNamedParameter(time()))
686
-			->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT))
687
-			->setValue('label', $qb->createNamedParameter($label));
688
-
689
-		if ($expirationTime !== null) {
690
-			$qb->setValue('expiration', $qb->createNamedParameter($expirationTime, IQueryBuilder::PARAM_DATE));
691
-		}
692
-
693
-		/*
169
+        $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_EMAIL, $share->getNode(), 1, 0);
170
+        if (!empty($alreadyShared)) {
171
+            $message = 'Sharing %1$s failed, this item is already shared with %2$s';
172
+            $message_t = $this->l->t('Sharing %1$s failed, this item is already shared with %2$s', [$share->getNode()->getName(), $shareWith]);
173
+            $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
174
+            throw new \Exception($message_t);
175
+        }
176
+
177
+        // if the admin enforces a password for all mail shares we create a
178
+        // random password and send it to the recipient
179
+        $password = $share->getPassword() ?: '';
180
+        $passwordEnforced = $this->shareManager->shareApiLinkEnforcePassword();
181
+        if ($passwordEnforced && empty($password)) {
182
+            $password = $this->autoGeneratePassword($share);
183
+        }
184
+
185
+        if (!empty($password)) {
186
+            $share->setPassword($this->hasher->hash($password));
187
+        }
188
+
189
+        $shareId = $this->createMailShare($share);
190
+        $send = $this->sendPassword($share, $password);
191
+        if ($passwordEnforced && $send === false) {
192
+            $this->sendPasswordToOwner($share, $password);
193
+        }
194
+
195
+        $this->createShareActivity($share);
196
+        $data = $this->getRawShare($shareId);
197
+
198
+        return $this->createShareObject($data);
199
+    }
200
+
201
+    /**
202
+     * auto generate password in case of password enforcement on mail shares
203
+     *
204
+     * @param IShare $share
205
+     * @return string
206
+     * @throws \Exception
207
+     */
208
+    protected function autoGeneratePassword($share) {
209
+        $initiatorUser = $this->userManager->get($share->getSharedBy());
210
+        $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
211
+        $allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
212
+
213
+        if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
214
+            throw new \Exception(
215
+                $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
216
+            );
217
+        }
218
+
219
+        $passwordEvent = new GenerateSecurePasswordEvent();
220
+        $this->eventDispatcher->dispatchTyped($passwordEvent);
221
+
222
+        $password = $passwordEvent->getPassword();
223
+        if ($password === null) {
224
+            $password = $this->secureRandom->generate(8, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
225
+        }
226
+
227
+        return $password;
228
+    }
229
+
230
+    /**
231
+     * create activity if a file/folder was shared by mail
232
+     *
233
+     * @param IShare $share
234
+     * @param string $type
235
+     */
236
+    protected function createShareActivity(IShare $share, string $type = 'share') {
237
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
238
+
239
+        $this->publishActivity(
240
+            $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_SELF : Activity::SUBJECT_UNSHARED_EMAIL_SELF,
241
+            [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
242
+            $share->getSharedBy(),
243
+            $share->getNode()->getId(),
244
+            (string) $userFolder->getRelativePath($share->getNode()->getPath())
245
+        );
246
+
247
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
248
+            $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
249
+            $fileId = $share->getNode()->getId();
250
+            $nodes = $ownerFolder->getById($fileId);
251
+            $ownerPath = $nodes[0]->getPath();
252
+            $this->publishActivity(
253
+                $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_BY : Activity::SUBJECT_UNSHARED_EMAIL_BY,
254
+                [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
255
+                $share->getShareOwner(),
256
+                $fileId,
257
+                (string) $ownerFolder->getRelativePath($ownerPath)
258
+            );
259
+        }
260
+    }
261
+
262
+    /**
263
+     * create activity if a file/folder was shared by mail
264
+     *
265
+     * @param IShare $share
266
+     * @param string $sharedWith
267
+     * @param bool $sendToSelf
268
+     */
269
+    protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
270
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
271
+
272
+        if ($sendToSelf) {
273
+            $this->publishActivity(
274
+                Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
275
+                [$userFolder->getRelativePath($share->getNode()->getPath())],
276
+                $share->getSharedBy(),
277
+                $share->getNode()->getId(),
278
+                (string) $userFolder->getRelativePath($share->getNode()->getPath())
279
+            );
280
+        } else {
281
+            $this->publishActivity(
282
+                Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
283
+                [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
284
+                $share->getSharedBy(),
285
+                $share->getNode()->getId(),
286
+                (string) $userFolder->getRelativePath($share->getNode()->getPath())
287
+            );
288
+        }
289
+    }
290
+
291
+
292
+    /**
293
+     * publish activity if a file/folder was shared by mail
294
+     *
295
+     * @param string $subject
296
+     * @param array $parameters
297
+     * @param string $affectedUser
298
+     * @param int $fileId
299
+     * @param string $filePath
300
+     */
301
+    protected function publishActivity(string $subject, array $parameters, string $affectedUser, int $fileId, string $filePath) {
302
+        $event = $this->activityManager->generateEvent();
303
+        $event->setApp('sharebymail')
304
+            ->setType('shared')
305
+            ->setSubject($subject, $parameters)
306
+            ->setAffectedUser($affectedUser)
307
+            ->setObject('files', $fileId, $filePath);
308
+        $this->activityManager->publish($event);
309
+    }
310
+
311
+    /**
312
+     * @param IShare $share
313
+     * @return int
314
+     * @throws \Exception
315
+     */
316
+    protected function createMailShare(IShare $share) {
317
+        $share->setToken($this->generateToken());
318
+        $shareId = $this->addShareToDB(
319
+            $share->getNodeId(),
320
+            $share->getNodeType(),
321
+            $share->getSharedWith(),
322
+            $share->getSharedBy(),
323
+            $share->getShareOwner(),
324
+            $share->getPermissions(),
325
+            $share->getToken(),
326
+            $share->getPassword(),
327
+            $share->getSendPasswordByTalk(),
328
+            $share->getHideDownload(),
329
+            $share->getLabel(),
330
+            $share->getExpirationDate()
331
+        );
332
+
333
+        try {
334
+            $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
335
+                ['token' => $share->getToken()]);
336
+            $this->sendMailNotification(
337
+                $share->getNode()->getName(),
338
+                $link,
339
+                $share->getSharedBy(),
340
+                $share->getSharedWith(),
341
+                $share->getExpirationDate()
342
+            );
343
+        } catch (HintException $hintException) {
344
+            $this->logger->logException($hintException, [
345
+                'message' => 'Failed to send share by mail.',
346
+                'level' => ILogger::ERROR,
347
+                'app' => 'sharebymail',
348
+            ]);
349
+            $this->removeShareFromTable($shareId);
350
+            throw $hintException;
351
+        } catch (\Exception $e) {
352
+            $this->logger->logException($e, [
353
+                'message' => 'Failed to send share by mail.',
354
+                'level' => ILogger::ERROR,
355
+                'app' => 'sharebymail',
356
+            ]);
357
+            $this->removeShareFromTable($shareId);
358
+            throw new HintException('Failed to send share by mail',
359
+                $this->l->t('Failed to send share by email'));
360
+        }
361
+
362
+        return $shareId;
363
+    }
364
+
365
+    /**
366
+     * @param string $filename
367
+     * @param string $link
368
+     * @param string $initiator
369
+     * @param string $shareWith
370
+     * @param \DateTime|null $expiration
371
+     * @throws \Exception If mail couldn't be sent
372
+     */
373
+    protected function sendMailNotification($filename,
374
+                                            $link,
375
+                                            $initiator,
376
+                                            $shareWith,
377
+                                            \DateTime $expiration = null) {
378
+        $initiatorUser = $this->userManager->get($initiator);
379
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
380
+        $message = $this->mailer->createMessage();
381
+
382
+        $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [
383
+            'filename' => $filename,
384
+            'link' => $link,
385
+            'initiator' => $initiatorDisplayName,
386
+            'expiration' => $expiration,
387
+            'shareWith' => $shareWith,
388
+        ]);
389
+
390
+        $emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
391
+        $emailTemplate->addHeader();
392
+        $emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
393
+        $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
394
+
395
+        $emailTemplate->addBodyText(
396
+            htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')),
397
+            $text
398
+        );
399
+        $emailTemplate->addBodyButton(
400
+            $this->l->t('Open »%s«', [$filename]),
401
+            $link
402
+        );
403
+
404
+        $message->setTo([$shareWith]);
405
+
406
+        // The "From" contains the sharers name
407
+        $instanceName = $this->defaults->getName();
408
+        $senderName = $instanceName;
409
+        if ($this->settingsManager->replyToInitiator()) {
410
+            $senderName = $this->l->t(
411
+                '%1$s via %2$s',
412
+                [
413
+                    $initiatorDisplayName,
414
+                    $instanceName
415
+                ]
416
+            );
417
+        }
418
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
419
+
420
+        // The "Reply-To" is set to the sharer if an mail address is configured
421
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
422
+        $initiatorEmail = $initiatorUser->getEMailAddress();
423
+        if ($this->settingsManager->replyToInitiator() && $initiatorEmail !== null) {
424
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
425
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
426
+        } else {
427
+            $emailTemplate->addFooter();
428
+        }
429
+
430
+        $message->useTemplate($emailTemplate);
431
+        $this->mailer->send($message);
432
+    }
433
+
434
+    /**
435
+     * send password to recipient of a mail share
436
+     *
437
+     * @param IShare $share
438
+     * @param string $password
439
+     * @return bool
440
+     */
441
+    protected function sendPassword(IShare $share, $password) {
442
+        $filename = $share->getNode()->getName();
443
+        $initiator = $share->getSharedBy();
444
+        $shareWith = $share->getSharedWith();
445
+
446
+        if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) {
447
+            return false;
448
+        }
449
+
450
+        $initiatorUser = $this->userManager->get($initiator);
451
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
452
+        $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
453
+
454
+        $plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
455
+        $htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
456
+
457
+        $message = $this->mailer->createMessage();
458
+
459
+        $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [
460
+            'filename' => $filename,
461
+            'password' => $password,
462
+            'initiator' => $initiatorDisplayName,
463
+            'initiatorEmail' => $initiatorEmailAddress,
464
+            'shareWith' => $shareWith,
465
+        ]);
466
+
467
+        $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName]));
468
+        $emailTemplate->addHeader();
469
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
470
+        $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
471
+        $emailTemplate->addBodyText($this->l->t('It is protected with the following password:'));
472
+        $emailTemplate->addBodyText($password);
473
+
474
+        // The "From" contains the sharers name
475
+        $instanceName = $this->defaults->getName();
476
+        $senderName = $instanceName;
477
+        if ($this->settingsManager->replyToInitiator()) {
478
+            $senderName = $this->l->t(
479
+                '%1$s via %2$s',
480
+                [
481
+                    $initiatorDisplayName,
482
+                    $instanceName
483
+                ]
484
+            );
485
+        }
486
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
487
+        if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
488
+            $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
489
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
490
+        } else {
491
+            $emailTemplate->addFooter();
492
+        }
493
+
494
+        $message->setTo([$shareWith]);
495
+        $message->useTemplate($emailTemplate);
496
+        $this->mailer->send($message);
497
+
498
+        $this->createPasswordSendActivity($share, $shareWith, false);
499
+
500
+        return true;
501
+    }
502
+
503
+    protected function sendNote(IShare $share) {
504
+        $recipient = $share->getSharedWith();
505
+
506
+
507
+        $filename = $share->getNode()->getName();
508
+        $initiator = $share->getSharedBy();
509
+        $note = $share->getNote();
510
+
511
+        $initiatorUser = $this->userManager->get($initiator);
512
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
513
+        $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
514
+
515
+        $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]);
516
+        $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]);
517
+
518
+        $message = $this->mailer->createMessage();
519
+
520
+        $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote');
521
+
522
+        $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName]));
523
+        $emailTemplate->addHeader();
524
+        $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading);
525
+        $emailTemplate->addBodyText(htmlspecialchars($note), $note);
526
+
527
+        $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
528
+            ['token' => $share->getToken()]);
529
+        $emailTemplate->addBodyButton(
530
+            $this->l->t('Open »%s«', [$filename]),
531
+            $link
532
+        );
533
+
534
+        // The "From" contains the sharers name
535
+        $instanceName = $this->defaults->getName();
536
+        $senderName = $instanceName;
537
+        if ($this->settingsManager->replyToInitiator()) {
538
+            $senderName = $this->l->t(
539
+                '%1$s via %2$s',
540
+                [
541
+                    $initiatorDisplayName,
542
+                    $instanceName
543
+                ]
544
+            );
545
+        }
546
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
547
+        if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
548
+            $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
549
+            $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
550
+        } else {
551
+            $emailTemplate->addFooter();
552
+        }
553
+
554
+        $message->setTo([$recipient]);
555
+        $message->useTemplate($emailTemplate);
556
+        $this->mailer->send($message);
557
+    }
558
+
559
+    /**
560
+     * send auto generated password to the owner. This happens if the admin enforces
561
+     * a password for mail shares and forbid to send the password by mail to the recipient
562
+     *
563
+     * @param IShare $share
564
+     * @param string $password
565
+     * @return bool
566
+     * @throws \Exception
567
+     */
568
+    protected function sendPasswordToOwner(IShare $share, $password) {
569
+        $filename = $share->getNode()->getName();
570
+        $initiator = $this->userManager->get($share->getSharedBy());
571
+        $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
572
+        $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
573
+        $shareWith = $share->getSharedWith();
574
+
575
+        if ($initiatorEMailAddress === null) {
576
+            throw new \Exception(
577
+                $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
578
+            );
579
+        }
580
+
581
+        $bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already sent to the recipient. Due to the security policies defined by the administrator of %3$s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.', [$filename, $shareWith, $this->defaults->getName()]);
582
+
583
+        $message = $this->mailer->createMessage();
584
+        $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [
585
+            'filename' => $filename,
586
+            'password' => $password,
587
+            'initiator' => $initiatorDisplayName,
588
+            'initiatorEmail' => $initiatorEMailAddress,
589
+            'shareWith' => $shareWith,
590
+        ]);
591
+
592
+        $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared by you with %2$s', [$filename, $shareWith]));
593
+        $emailTemplate->addHeader();
594
+        $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
595
+        $emailTemplate->addBodyText($bodyPart);
596
+        $emailTemplate->addBodyText($this->l->t('This is the password:'));
597
+        $emailTemplate->addBodyText($password);
598
+        $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
599
+        $emailTemplate->addFooter();
600
+
601
+        $instanceName = $this->defaults->getName();
602
+        $senderName = $this->l->t(
603
+            '%1$s via %2$s',
604
+            [
605
+                $initiatorDisplayName,
606
+                $instanceName
607
+            ]
608
+        );
609
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
610
+        $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
611
+        $message->useTemplate($emailTemplate);
612
+        $this->mailer->send($message);
613
+
614
+        $this->createPasswordSendActivity($share, $shareWith, true);
615
+
616
+        return true;
617
+    }
618
+
619
+    /**
620
+     * generate share token
621
+     *
622
+     * @return string
623
+     */
624
+    protected function generateToken($size = 15) {
625
+        $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
626
+        return $token;
627
+    }
628
+
629
+    /**
630
+     * Get all children of this share
631
+     *
632
+     * @param IShare $parent
633
+     * @return IShare[]
634
+     */
635
+    public function getChildren(IShare $parent) {
636
+        $children = [];
637
+
638
+        $qb = $this->dbConnection->getQueryBuilder();
639
+        $qb->select('*')
640
+            ->from('share')
641
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
642
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
643
+            ->orderBy('id');
644
+
645
+        $cursor = $qb->execute();
646
+        while ($data = $cursor->fetch()) {
647
+            $children[] = $this->createShareObject($data);
648
+        }
649
+        $cursor->closeCursor();
650
+
651
+        return $children;
652
+    }
653
+
654
+    /**
655
+     * add share to the database and return the ID
656
+     *
657
+     * @param int $itemSource
658
+     * @param string $itemType
659
+     * @param string $shareWith
660
+     * @param string $sharedBy
661
+     * @param string $uidOwner
662
+     * @param int $permissions
663
+     * @param string $token
664
+     * @param string $password
665
+     * @param bool $sendPasswordByTalk
666
+     * @param bool $hideDownload
667
+     * @param string $label
668
+     * @param \DateTime|null $expirationTime
669
+     * @return int
670
+     */
671
+    protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password, $sendPasswordByTalk, $hideDownload, $label, $expirationTime) {
672
+        $qb = $this->dbConnection->getQueryBuilder();
673
+        $qb->insert('share')
674
+            ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))
675
+            ->setValue('item_type', $qb->createNamedParameter($itemType))
676
+            ->setValue('item_source', $qb->createNamedParameter($itemSource))
677
+            ->setValue('file_source', $qb->createNamedParameter($itemSource))
678
+            ->setValue('share_with', $qb->createNamedParameter($shareWith))
679
+            ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
680
+            ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
681
+            ->setValue('permissions', $qb->createNamedParameter($permissions))
682
+            ->setValue('token', $qb->createNamedParameter($token))
683
+            ->setValue('password', $qb->createNamedParameter($password))
684
+            ->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL))
685
+            ->setValue('stime', $qb->createNamedParameter(time()))
686
+            ->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT))
687
+            ->setValue('label', $qb->createNamedParameter($label));
688
+
689
+        if ($expirationTime !== null) {
690
+            $qb->setValue('expiration', $qb->createNamedParameter($expirationTime, IQueryBuilder::PARAM_DATE));
691
+        }
692
+
693
+        /*
694 694
 		 * Added to fix https://github.com/owncloud/core/issues/22215
695 695
 		 * Can be removed once we get rid of ajax/share.php
696 696
 		 */
697
-		$qb->setValue('file_target', $qb->createNamedParameter(''));
698
-
699
-		$qb->execute();
700
-		return $qb->getLastInsertId();
701
-	}
702
-
703
-	/**
704
-	 * Update a share
705
-	 *
706
-	 * @param IShare $share
707
-	 * @param string|null $plainTextPassword
708
-	 * @return IShare The share object
709
-	 */
710
-	public function update(IShare $share, $plainTextPassword = null) {
711
-		$originalShare = $this->getShareById($share->getId());
712
-
713
-		// a real password was given
714
-		$validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
715
-
716
-		if ($validPassword && ($originalShare->getPassword() !== $share->getPassword() ||
717
-								($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) {
718
-			$this->sendPassword($share, $plainTextPassword);
719
-		}
720
-		/*
697
+        $qb->setValue('file_target', $qb->createNamedParameter(''));
698
+
699
+        $qb->execute();
700
+        return $qb->getLastInsertId();
701
+    }
702
+
703
+    /**
704
+     * Update a share
705
+     *
706
+     * @param IShare $share
707
+     * @param string|null $plainTextPassword
708
+     * @return IShare The share object
709
+     */
710
+    public function update(IShare $share, $plainTextPassword = null) {
711
+        $originalShare = $this->getShareById($share->getId());
712
+
713
+        // a real password was given
714
+        $validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
715
+
716
+        if ($validPassword && ($originalShare->getPassword() !== $share->getPassword() ||
717
+                                ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) {
718
+            $this->sendPassword($share, $plainTextPassword);
719
+        }
720
+        /*
721 721
 		 * We allow updating the permissions and password of mail shares
722 722
 		 */
723
-		$qb = $this->dbConnection->getQueryBuilder();
724
-		$qb->update('share')
725
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
726
-			->set('permissions', $qb->createNamedParameter($share->getPermissions()))
727
-			->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
728
-			->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
729
-			->set('password', $qb->createNamedParameter($share->getPassword()))
730
-			->set('label', $qb->createNamedParameter($share->getLabel()))
731
-			->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL))
732
-			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
733
-			->set('note', $qb->createNamedParameter($share->getNote()))
734
-			->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT))
735
-			->execute();
736
-
737
-		if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') {
738
-			$this->sendNote($share);
739
-		}
740
-
741
-		return $share;
742
-	}
743
-
744
-	/**
745
-	 * @inheritdoc
746
-	 */
747
-	public function move(IShare $share, $recipient) {
748
-		/**
749
-		 * nothing to do here, mail shares are only outgoing shares
750
-		 */
751
-		return $share;
752
-	}
753
-
754
-	/**
755
-	 * Delete a share (owner unShares the file)
756
-	 *
757
-	 * @param IShare $share
758
-	 */
759
-	public function delete(IShare $share) {
760
-		try {
761
-			$this->createShareActivity($share, 'unshare');
762
-		} catch (\Exception $e) {
763
-		}
764
-
765
-		$this->removeShareFromTable($share->getId());
766
-	}
767
-
768
-	/**
769
-	 * @inheritdoc
770
-	 */
771
-	public function deleteFromSelf(IShare $share, $recipient) {
772
-		// nothing to do here, mail shares are only outgoing shares
773
-	}
774
-
775
-	public function restore(IShare $share, string $recipient): IShare {
776
-		throw new GenericShareException('not implemented');
777
-	}
778
-
779
-	/**
780
-	 * @inheritdoc
781
-	 */
782
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
783
-		$qb = $this->dbConnection->getQueryBuilder();
784
-		$qb->select('*')
785
-			->from('share');
786
-
787
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
788
-
789
-		/**
790
-		 * Reshares for this user are shares where they are the owner.
791
-		 */
792
-		if ($reshares === false) {
793
-			//Special case for old shares created via the web UI
794
-			$or1 = $qb->expr()->andX(
795
-				$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
796
-				$qb->expr()->isNull('uid_initiator')
797
-			);
798
-
799
-			$qb->andWhere(
800
-				$qb->expr()->orX(
801
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
802
-					$or1
803
-				)
804
-			);
805
-		} else {
806
-			$qb->andWhere(
807
-				$qb->expr()->orX(
808
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
809
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
810
-				)
811
-			);
812
-		}
813
-
814
-		if ($node !== null) {
815
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
816
-		}
817
-
818
-		if ($limit !== -1) {
819
-			$qb->setMaxResults($limit);
820
-		}
821
-
822
-		$qb->setFirstResult($offset);
823
-		$qb->orderBy('id');
824
-
825
-		$cursor = $qb->execute();
826
-		$shares = [];
827
-		while ($data = $cursor->fetch()) {
828
-			$shares[] = $this->createShareObject($data);
829
-		}
830
-		$cursor->closeCursor();
831
-
832
-		return $shares;
833
-	}
834
-
835
-	/**
836
-	 * @inheritdoc
837
-	 */
838
-	public function getShareById($id, $recipientId = null) {
839
-		$qb = $this->dbConnection->getQueryBuilder();
840
-
841
-		$qb->select('*')
842
-			->from('share')
843
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
844
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
845
-
846
-		$cursor = $qb->execute();
847
-		$data = $cursor->fetch();
848
-		$cursor->closeCursor();
849
-
850
-		if ($data === false) {
851
-			throw new ShareNotFound();
852
-		}
853
-
854
-		try {
855
-			$share = $this->createShareObject($data);
856
-		} catch (InvalidShare $e) {
857
-			throw new ShareNotFound();
858
-		}
859
-
860
-		return $share;
861
-	}
862
-
863
-	/**
864
-	 * Get shares for a given path
865
-	 *
866
-	 * @param \OCP\Files\Node $path
867
-	 * @return IShare[]
868
-	 */
869
-	public function getSharesByPath(Node $path) {
870
-		$qb = $this->dbConnection->getQueryBuilder();
871
-
872
-		$cursor = $qb->select('*')
873
-			->from('share')
874
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
875
-			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
876
-			->execute();
877
-
878
-		$shares = [];
879
-		while ($data = $cursor->fetch()) {
880
-			$shares[] = $this->createShareObject($data);
881
-		}
882
-		$cursor->closeCursor();
883
-
884
-		return $shares;
885
-	}
886
-
887
-	/**
888
-	 * @inheritdoc
889
-	 */
890
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
891
-		/** @var IShare[] $shares */
892
-		$shares = [];
893
-
894
-		//Get shares directly with this user
895
-		$qb = $this->dbConnection->getQueryBuilder();
896
-		$qb->select('*')
897
-			->from('share');
898
-
899
-		// Order by id
900
-		$qb->orderBy('id');
901
-
902
-		// Set limit and offset
903
-		if ($limit !== -1) {
904
-			$qb->setMaxResults($limit);
905
-		}
906
-		$qb->setFirstResult($offset);
907
-
908
-		$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
909
-		$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
910
-
911
-		// Filter by node if provided
912
-		if ($node !== null) {
913
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
914
-		}
915
-
916
-		$cursor = $qb->execute();
917
-
918
-		while ($data = $cursor->fetch()) {
919
-			$shares[] = $this->createShareObject($data);
920
-		}
921
-		$cursor->closeCursor();
922
-
923
-
924
-		return $shares;
925
-	}
926
-
927
-	/**
928
-	 * Get a share by token
929
-	 *
930
-	 * @param string $token
931
-	 * @return IShare
932
-	 * @throws ShareNotFound
933
-	 */
934
-	public function getShareByToken($token) {
935
-		$qb = $this->dbConnection->getQueryBuilder();
936
-
937
-		$cursor = $qb->select('*')
938
-			->from('share')
939
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
940
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
941
-			->execute();
942
-
943
-		$data = $cursor->fetch();
944
-
945
-		if ($data === false) {
946
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
947
-		}
948
-
949
-		try {
950
-			$share = $this->createShareObject($data);
951
-		} catch (InvalidShare $e) {
952
-			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
953
-		}
954
-
955
-		return $share;
956
-	}
957
-
958
-	/**
959
-	 * remove share from table
960
-	 *
961
-	 * @param string $shareId
962
-	 */
963
-	protected function removeShareFromTable($shareId) {
964
-		$qb = $this->dbConnection->getQueryBuilder();
965
-		$qb->delete('share')
966
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
967
-		$qb->execute();
968
-	}
969
-
970
-	/**
971
-	 * Create a share object from an database row
972
-	 *
973
-	 * @param array $data
974
-	 * @return IShare
975
-	 * @throws InvalidShare
976
-	 * @throws ShareNotFound
977
-	 */
978
-	protected function createShareObject($data) {
979
-		$share = new Share($this->rootFolder, $this->userManager);
980
-		$share->setId((int)$data['id'])
981
-			->setShareType((int)$data['share_type'])
982
-			->setPermissions((int)$data['permissions'])
983
-			->setTarget($data['file_target'])
984
-			->setMailSend((bool)$data['mail_send'])
985
-			->setNote($data['note'])
986
-			->setToken($data['token']);
987
-
988
-		$shareTime = new \DateTime();
989
-		$shareTime->setTimestamp((int)$data['stime']);
990
-		$share->setShareTime($shareTime);
991
-		$share->setSharedWith($data['share_with']);
992
-		$share->setPassword($data['password']);
993
-		$share->setLabel($data['label']);
994
-		$share->setSendPasswordByTalk((bool)$data['password_by_talk']);
995
-		$share->setHideDownload((bool)$data['hide_download']);
996
-
997
-		if ($data['uid_initiator'] !== null) {
998
-			$share->setShareOwner($data['uid_owner']);
999
-			$share->setSharedBy($data['uid_initiator']);
1000
-		} else {
1001
-			//OLD SHARE
1002
-			$share->setSharedBy($data['uid_owner']);
1003
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
1004
-
1005
-			$owner = $path->getOwner();
1006
-			$share->setShareOwner($owner->getUID());
1007
-		}
1008
-
1009
-		if ($data['expiration'] !== null) {
1010
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
1011
-			if ($expiration !== false) {
1012
-				$share->setExpirationDate($expiration);
1013
-			}
1014
-		}
1015
-
1016
-		$share->setNodeId((int)$data['file_source']);
1017
-		$share->setNodeType($data['item_type']);
1018
-
1019
-		$share->setProviderId($this->identifier());
1020
-
1021
-		return $share;
1022
-	}
1023
-
1024
-	/**
1025
-	 * Get the node with file $id for $user
1026
-	 *
1027
-	 * @param string $userId
1028
-	 * @param int $id
1029
-	 * @return \OCP\Files\File|\OCP\Files\Folder
1030
-	 * @throws InvalidShare
1031
-	 */
1032
-	private function getNode($userId, $id) {
1033
-		try {
1034
-			$userFolder = $this->rootFolder->getUserFolder($userId);
1035
-		} catch (NoUserException $e) {
1036
-			throw new InvalidShare();
1037
-		}
1038
-
1039
-		$nodes = $userFolder->getById($id);
1040
-
1041
-		if (empty($nodes)) {
1042
-			throw new InvalidShare();
1043
-		}
1044
-
1045
-		return $nodes[0];
1046
-	}
1047
-
1048
-	/**
1049
-	 * A user is deleted from the system
1050
-	 * So clean up the relevant shares.
1051
-	 *
1052
-	 * @param string $uid
1053
-	 * @param int $shareType
1054
-	 */
1055
-	public function userDeleted($uid, $shareType) {
1056
-		$qb = $this->dbConnection->getQueryBuilder();
1057
-
1058
-		$qb->delete('share')
1059
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
1060
-			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
1061
-			->execute();
1062
-	}
1063
-
1064
-	/**
1065
-	 * This provider does not support group shares
1066
-	 *
1067
-	 * @param string $gid
1068
-	 */
1069
-	public function groupDeleted($gid) {
1070
-	}
1071
-
1072
-	/**
1073
-	 * This provider does not support group shares
1074
-	 *
1075
-	 * @param string $uid
1076
-	 * @param string $gid
1077
-	 */
1078
-	public function userDeletedFromGroup($uid, $gid) {
1079
-	}
1080
-
1081
-	/**
1082
-	 * get database row of a give share
1083
-	 *
1084
-	 * @param $id
1085
-	 * @return array
1086
-	 * @throws ShareNotFound
1087
-	 */
1088
-	protected function getRawShare($id) {
1089
-
1090
-		// Now fetch the inserted share and create a complete share object
1091
-		$qb = $this->dbConnection->getQueryBuilder();
1092
-		$qb->select('*')
1093
-			->from('share')
1094
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
1095
-
1096
-		$cursor = $qb->execute();
1097
-		$data = $cursor->fetch();
1098
-		$cursor->closeCursor();
1099
-
1100
-		if ($data === false) {
1101
-			throw new ShareNotFound;
1102
-		}
1103
-
1104
-		return $data;
1105
-	}
1106
-
1107
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
1108
-		$qb = $this->dbConnection->getQueryBuilder();
1109
-		$qb->select('*')
1110
-			->from('share', 's')
1111
-			->andWhere($qb->expr()->orX(
1112
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1113
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1114
-			))
1115
-			->andWhere(
1116
-				$qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))
1117
-			);
1118
-
1119
-		/**
1120
-		 * Reshares for this user are shares where they are the owner.
1121
-		 */
1122
-		if ($reshares === false) {
1123
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1124
-		} else {
1125
-			$qb->andWhere(
1126
-				$qb->expr()->orX(
1127
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1128
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1129
-				)
1130
-			);
1131
-		}
1132
-
1133
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1134
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1135
-
1136
-		$qb->orderBy('id');
1137
-
1138
-		$cursor = $qb->execute();
1139
-		$shares = [];
1140
-		while ($data = $cursor->fetch()) {
1141
-			$shares[$data['fileid']][] = $this->createShareObject($data);
1142
-		}
1143
-		$cursor->closeCursor();
1144
-
1145
-		return $shares;
1146
-	}
1147
-
1148
-	/**
1149
-	 * @inheritdoc
1150
-	 */
1151
-	public function getAccessList($nodes, $currentAccess) {
1152
-		$ids = [];
1153
-		foreach ($nodes as $node) {
1154
-			$ids[] = $node->getId();
1155
-		}
1156
-
1157
-		$qb = $this->dbConnection->getQueryBuilder();
1158
-		$qb->select('share_with')
1159
-			->from('share')
1160
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
1161
-			->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1162
-			->andWhere($qb->expr()->orX(
1163
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1164
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1165
-			))
1166
-			->setMaxResults(1);
1167
-		$cursor = $qb->execute();
1168
-
1169
-		$mail = $cursor->fetch() !== false;
1170
-		$cursor->closeCursor();
1171
-
1172
-		return ['public' => $mail];
1173
-	}
1174
-
1175
-	public function getAllShares(): iterable {
1176
-		$qb = $this->dbConnection->getQueryBuilder();
1177
-
1178
-		$qb->select('*')
1179
-			->from('share')
1180
-			->where(
1181
-				$qb->expr()->orX(
1182
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_EMAIL))
1183
-				)
1184
-			);
1185
-
1186
-		$cursor = $qb->execute();
1187
-		while ($data = $cursor->fetch()) {
1188
-			try {
1189
-				$share = $this->createShareObject($data);
1190
-			} catch (InvalidShare $e) {
1191
-				continue;
1192
-			} catch (ShareNotFound $e) {
1193
-				continue;
1194
-			}
1195
-
1196
-			yield $share;
1197
-		}
1198
-		$cursor->closeCursor();
1199
-	}
723
+        $qb = $this->dbConnection->getQueryBuilder();
724
+        $qb->update('share')
725
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
726
+            ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
727
+            ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
728
+            ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
729
+            ->set('password', $qb->createNamedParameter($share->getPassword()))
730
+            ->set('label', $qb->createNamedParameter($share->getLabel()))
731
+            ->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL))
732
+            ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
733
+            ->set('note', $qb->createNamedParameter($share->getNote()))
734
+            ->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT))
735
+            ->execute();
736
+
737
+        if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') {
738
+            $this->sendNote($share);
739
+        }
740
+
741
+        return $share;
742
+    }
743
+
744
+    /**
745
+     * @inheritdoc
746
+     */
747
+    public function move(IShare $share, $recipient) {
748
+        /**
749
+         * nothing to do here, mail shares are only outgoing shares
750
+         */
751
+        return $share;
752
+    }
753
+
754
+    /**
755
+     * Delete a share (owner unShares the file)
756
+     *
757
+     * @param IShare $share
758
+     */
759
+    public function delete(IShare $share) {
760
+        try {
761
+            $this->createShareActivity($share, 'unshare');
762
+        } catch (\Exception $e) {
763
+        }
764
+
765
+        $this->removeShareFromTable($share->getId());
766
+    }
767
+
768
+    /**
769
+     * @inheritdoc
770
+     */
771
+    public function deleteFromSelf(IShare $share, $recipient) {
772
+        // nothing to do here, mail shares are only outgoing shares
773
+    }
774
+
775
+    public function restore(IShare $share, string $recipient): IShare {
776
+        throw new GenericShareException('not implemented');
777
+    }
778
+
779
+    /**
780
+     * @inheritdoc
781
+     */
782
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
783
+        $qb = $this->dbConnection->getQueryBuilder();
784
+        $qb->select('*')
785
+            ->from('share');
786
+
787
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
788
+
789
+        /**
790
+         * Reshares for this user are shares where they are the owner.
791
+         */
792
+        if ($reshares === false) {
793
+            //Special case for old shares created via the web UI
794
+            $or1 = $qb->expr()->andX(
795
+                $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
796
+                $qb->expr()->isNull('uid_initiator')
797
+            );
798
+
799
+            $qb->andWhere(
800
+                $qb->expr()->orX(
801
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
802
+                    $or1
803
+                )
804
+            );
805
+        } else {
806
+            $qb->andWhere(
807
+                $qb->expr()->orX(
808
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
809
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
810
+                )
811
+            );
812
+        }
813
+
814
+        if ($node !== null) {
815
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
816
+        }
817
+
818
+        if ($limit !== -1) {
819
+            $qb->setMaxResults($limit);
820
+        }
821
+
822
+        $qb->setFirstResult($offset);
823
+        $qb->orderBy('id');
824
+
825
+        $cursor = $qb->execute();
826
+        $shares = [];
827
+        while ($data = $cursor->fetch()) {
828
+            $shares[] = $this->createShareObject($data);
829
+        }
830
+        $cursor->closeCursor();
831
+
832
+        return $shares;
833
+    }
834
+
835
+    /**
836
+     * @inheritdoc
837
+     */
838
+    public function getShareById($id, $recipientId = null) {
839
+        $qb = $this->dbConnection->getQueryBuilder();
840
+
841
+        $qb->select('*')
842
+            ->from('share')
843
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
844
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
845
+
846
+        $cursor = $qb->execute();
847
+        $data = $cursor->fetch();
848
+        $cursor->closeCursor();
849
+
850
+        if ($data === false) {
851
+            throw new ShareNotFound();
852
+        }
853
+
854
+        try {
855
+            $share = $this->createShareObject($data);
856
+        } catch (InvalidShare $e) {
857
+            throw new ShareNotFound();
858
+        }
859
+
860
+        return $share;
861
+    }
862
+
863
+    /**
864
+     * Get shares for a given path
865
+     *
866
+     * @param \OCP\Files\Node $path
867
+     * @return IShare[]
868
+     */
869
+    public function getSharesByPath(Node $path) {
870
+        $qb = $this->dbConnection->getQueryBuilder();
871
+
872
+        $cursor = $qb->select('*')
873
+            ->from('share')
874
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
875
+            ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
876
+            ->execute();
877
+
878
+        $shares = [];
879
+        while ($data = $cursor->fetch()) {
880
+            $shares[] = $this->createShareObject($data);
881
+        }
882
+        $cursor->closeCursor();
883
+
884
+        return $shares;
885
+    }
886
+
887
+    /**
888
+     * @inheritdoc
889
+     */
890
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
891
+        /** @var IShare[] $shares */
892
+        $shares = [];
893
+
894
+        //Get shares directly with this user
895
+        $qb = $this->dbConnection->getQueryBuilder();
896
+        $qb->select('*')
897
+            ->from('share');
898
+
899
+        // Order by id
900
+        $qb->orderBy('id');
901
+
902
+        // Set limit and offset
903
+        if ($limit !== -1) {
904
+            $qb->setMaxResults($limit);
905
+        }
906
+        $qb->setFirstResult($offset);
907
+
908
+        $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
909
+        $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
910
+
911
+        // Filter by node if provided
912
+        if ($node !== null) {
913
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
914
+        }
915
+
916
+        $cursor = $qb->execute();
917
+
918
+        while ($data = $cursor->fetch()) {
919
+            $shares[] = $this->createShareObject($data);
920
+        }
921
+        $cursor->closeCursor();
922
+
923
+
924
+        return $shares;
925
+    }
926
+
927
+    /**
928
+     * Get a share by token
929
+     *
930
+     * @param string $token
931
+     * @return IShare
932
+     * @throws ShareNotFound
933
+     */
934
+    public function getShareByToken($token) {
935
+        $qb = $this->dbConnection->getQueryBuilder();
936
+
937
+        $cursor = $qb->select('*')
938
+            ->from('share')
939
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
940
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
941
+            ->execute();
942
+
943
+        $data = $cursor->fetch();
944
+
945
+        if ($data === false) {
946
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
947
+        }
948
+
949
+        try {
950
+            $share = $this->createShareObject($data);
951
+        } catch (InvalidShare $e) {
952
+            throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
953
+        }
954
+
955
+        return $share;
956
+    }
957
+
958
+    /**
959
+     * remove share from table
960
+     *
961
+     * @param string $shareId
962
+     */
963
+    protected function removeShareFromTable($shareId) {
964
+        $qb = $this->dbConnection->getQueryBuilder();
965
+        $qb->delete('share')
966
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
967
+        $qb->execute();
968
+    }
969
+
970
+    /**
971
+     * Create a share object from an database row
972
+     *
973
+     * @param array $data
974
+     * @return IShare
975
+     * @throws InvalidShare
976
+     * @throws ShareNotFound
977
+     */
978
+    protected function createShareObject($data) {
979
+        $share = new Share($this->rootFolder, $this->userManager);
980
+        $share->setId((int)$data['id'])
981
+            ->setShareType((int)$data['share_type'])
982
+            ->setPermissions((int)$data['permissions'])
983
+            ->setTarget($data['file_target'])
984
+            ->setMailSend((bool)$data['mail_send'])
985
+            ->setNote($data['note'])
986
+            ->setToken($data['token']);
987
+
988
+        $shareTime = new \DateTime();
989
+        $shareTime->setTimestamp((int)$data['stime']);
990
+        $share->setShareTime($shareTime);
991
+        $share->setSharedWith($data['share_with']);
992
+        $share->setPassword($data['password']);
993
+        $share->setLabel($data['label']);
994
+        $share->setSendPasswordByTalk((bool)$data['password_by_talk']);
995
+        $share->setHideDownload((bool)$data['hide_download']);
996
+
997
+        if ($data['uid_initiator'] !== null) {
998
+            $share->setShareOwner($data['uid_owner']);
999
+            $share->setSharedBy($data['uid_initiator']);
1000
+        } else {
1001
+            //OLD SHARE
1002
+            $share->setSharedBy($data['uid_owner']);
1003
+            $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
1004
+
1005
+            $owner = $path->getOwner();
1006
+            $share->setShareOwner($owner->getUID());
1007
+        }
1008
+
1009
+        if ($data['expiration'] !== null) {
1010
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
1011
+            if ($expiration !== false) {
1012
+                $share->setExpirationDate($expiration);
1013
+            }
1014
+        }
1015
+
1016
+        $share->setNodeId((int)$data['file_source']);
1017
+        $share->setNodeType($data['item_type']);
1018
+
1019
+        $share->setProviderId($this->identifier());
1020
+
1021
+        return $share;
1022
+    }
1023
+
1024
+    /**
1025
+     * Get the node with file $id for $user
1026
+     *
1027
+     * @param string $userId
1028
+     * @param int $id
1029
+     * @return \OCP\Files\File|\OCP\Files\Folder
1030
+     * @throws InvalidShare
1031
+     */
1032
+    private function getNode($userId, $id) {
1033
+        try {
1034
+            $userFolder = $this->rootFolder->getUserFolder($userId);
1035
+        } catch (NoUserException $e) {
1036
+            throw new InvalidShare();
1037
+        }
1038
+
1039
+        $nodes = $userFolder->getById($id);
1040
+
1041
+        if (empty($nodes)) {
1042
+            throw new InvalidShare();
1043
+        }
1044
+
1045
+        return $nodes[0];
1046
+    }
1047
+
1048
+    /**
1049
+     * A user is deleted from the system
1050
+     * So clean up the relevant shares.
1051
+     *
1052
+     * @param string $uid
1053
+     * @param int $shareType
1054
+     */
1055
+    public function userDeleted($uid, $shareType) {
1056
+        $qb = $this->dbConnection->getQueryBuilder();
1057
+
1058
+        $qb->delete('share')
1059
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
1060
+            ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
1061
+            ->execute();
1062
+    }
1063
+
1064
+    /**
1065
+     * This provider does not support group shares
1066
+     *
1067
+     * @param string $gid
1068
+     */
1069
+    public function groupDeleted($gid) {
1070
+    }
1071
+
1072
+    /**
1073
+     * This provider does not support group shares
1074
+     *
1075
+     * @param string $uid
1076
+     * @param string $gid
1077
+     */
1078
+    public function userDeletedFromGroup($uid, $gid) {
1079
+    }
1080
+
1081
+    /**
1082
+     * get database row of a give share
1083
+     *
1084
+     * @param $id
1085
+     * @return array
1086
+     * @throws ShareNotFound
1087
+     */
1088
+    protected function getRawShare($id) {
1089
+
1090
+        // Now fetch the inserted share and create a complete share object
1091
+        $qb = $this->dbConnection->getQueryBuilder();
1092
+        $qb->select('*')
1093
+            ->from('share')
1094
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
1095
+
1096
+        $cursor = $qb->execute();
1097
+        $data = $cursor->fetch();
1098
+        $cursor->closeCursor();
1099
+
1100
+        if ($data === false) {
1101
+            throw new ShareNotFound;
1102
+        }
1103
+
1104
+        return $data;
1105
+    }
1106
+
1107
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
1108
+        $qb = $this->dbConnection->getQueryBuilder();
1109
+        $qb->select('*')
1110
+            ->from('share', 's')
1111
+            ->andWhere($qb->expr()->orX(
1112
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1113
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1114
+            ))
1115
+            ->andWhere(
1116
+                $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))
1117
+            );
1118
+
1119
+        /**
1120
+         * Reshares for this user are shares where they are the owner.
1121
+         */
1122
+        if ($reshares === false) {
1123
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
1124
+        } else {
1125
+            $qb->andWhere(
1126
+                $qb->expr()->orX(
1127
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
1128
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
1129
+                )
1130
+            );
1131
+        }
1132
+
1133
+        $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1134
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1135
+
1136
+        $qb->orderBy('id');
1137
+
1138
+        $cursor = $qb->execute();
1139
+        $shares = [];
1140
+        while ($data = $cursor->fetch()) {
1141
+            $shares[$data['fileid']][] = $this->createShareObject($data);
1142
+        }
1143
+        $cursor->closeCursor();
1144
+
1145
+        return $shares;
1146
+    }
1147
+
1148
+    /**
1149
+     * @inheritdoc
1150
+     */
1151
+    public function getAccessList($nodes, $currentAccess) {
1152
+        $ids = [];
1153
+        foreach ($nodes as $node) {
1154
+            $ids[] = $node->getId();
1155
+        }
1156
+
1157
+        $qb = $this->dbConnection->getQueryBuilder();
1158
+        $qb->select('share_with')
1159
+            ->from('share')
1160
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
1161
+            ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
1162
+            ->andWhere($qb->expr()->orX(
1163
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
1164
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
1165
+            ))
1166
+            ->setMaxResults(1);
1167
+        $cursor = $qb->execute();
1168
+
1169
+        $mail = $cursor->fetch() !== false;
1170
+        $cursor->closeCursor();
1171
+
1172
+        return ['public' => $mail];
1173
+    }
1174
+
1175
+    public function getAllShares(): iterable {
1176
+        $qb = $this->dbConnection->getQueryBuilder();
1177
+
1178
+        $qb->select('*')
1179
+            ->from('share')
1180
+            ->where(
1181
+                $qb->expr()->orX(
1182
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_EMAIL))
1183
+                )
1184
+            );
1185
+
1186
+        $cursor = $qb->execute();
1187
+        while ($data = $cursor->fetch()) {
1188
+            try {
1189
+                $share = $this->createShareObject($data);
1190
+            } catch (InvalidShare $e) {
1191
+                continue;
1192
+            } catch (ShareNotFound $e) {
1193
+                continue;
1194
+            }
1195
+
1196
+            yield $share;
1197
+        }
1198
+        $cursor->closeCursor();
1199
+    }
1200 1200
 }
Please login to merge, or discard this patch.
Spacing   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
 
222 222
 		$password = $passwordEvent->getPassword();
223 223
 		if ($password === null) {
224
-			$password = $this->secureRandom->generate(8, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
224
+			$password = $this->secureRandom->generate(8, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS);
225 225
 		}
226 226
 
227 227
 		return $password;
@@ -393,7 +393,7 @@  discard block
 block discarded – undo
393 393
 		$text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
394 394
 
395 395
 		$emailTemplate->addBodyText(
396
-			htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')),
396
+			htmlspecialchars($text.' '.$this->l->t('Click the button below to open it.')),
397 397
 			$text
398 398
 		);
399 399
 		$emailTemplate->addBodyButton(
@@ -422,7 +422,7 @@  discard block
 block discarded – undo
422 422
 		$initiatorEmail = $initiatorUser->getEMailAddress();
423 423
 		if ($this->settingsManager->replyToInitiator() && $initiatorEmail !== null) {
424 424
 			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
425
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
425
+			$emailTemplate->addFooter($instanceName.($this->defaults->getSlogan() !== '' ? ' - '.$this->defaults->getSlogan() : ''));
426 426
 		} else {
427 427
 			$emailTemplate->addFooter();
428 428
 		}
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
 		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
487 487
 		if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
488 488
 			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
489
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
489
+			$emailTemplate->addFooter($instanceName.' - '.$this->defaults->getSlogan());
490 490
 		} else {
491 491
 			$emailTemplate->addFooter();
492 492
 		}
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
 		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
547 547
 		if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
548 548
 			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
549
-			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
549
+			$emailTemplate->addFooter($instanceName.' - '.$this->defaults->getSlogan());
550 550
 		} else {
551 551
 			$emailTemplate->addFooter();
552 552
 		}
@@ -683,7 +683,7 @@  discard block
 block discarded – undo
683 683
 			->setValue('password', $qb->createNamedParameter($password))
684 684
 			->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL))
685 685
 			->setValue('stime', $qb->createNamedParameter(time()))
686
-			->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT))
686
+			->setValue('hide_download', $qb->createNamedParameter((int) $hideDownload, IQueryBuilder::PARAM_INT))
687 687
 			->setValue('label', $qb->createNamedParameter($label));
688 688
 
689 689
 		if ($expirationTime !== null) {
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
 			->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL))
732 732
 			->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
733 733
 			->set('note', $qb->createNamedParameter($share->getNote()))
734
-			->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT))
734
+			->set('hide_download', $qb->createNamedParameter((int) $share->getHideDownload(), IQueryBuilder::PARAM_INT))
735 735
 			->execute();
736 736
 
737 737
 		if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') {
@@ -977,22 +977,22 @@  discard block
 block discarded – undo
977 977
 	 */
978 978
 	protected function createShareObject($data) {
979 979
 		$share = new Share($this->rootFolder, $this->userManager);
980
-		$share->setId((int)$data['id'])
981
-			->setShareType((int)$data['share_type'])
982
-			->setPermissions((int)$data['permissions'])
980
+		$share->setId((int) $data['id'])
981
+			->setShareType((int) $data['share_type'])
982
+			->setPermissions((int) $data['permissions'])
983 983
 			->setTarget($data['file_target'])
984
-			->setMailSend((bool)$data['mail_send'])
984
+			->setMailSend((bool) $data['mail_send'])
985 985
 			->setNote($data['note'])
986 986
 			->setToken($data['token']);
987 987
 
988 988
 		$shareTime = new \DateTime();
989
-		$shareTime->setTimestamp((int)$data['stime']);
989
+		$shareTime->setTimestamp((int) $data['stime']);
990 990
 		$share->setShareTime($shareTime);
991 991
 		$share->setSharedWith($data['share_with']);
992 992
 		$share->setPassword($data['password']);
993 993
 		$share->setLabel($data['label']);
994
-		$share->setSendPasswordByTalk((bool)$data['password_by_talk']);
995
-		$share->setHideDownload((bool)$data['hide_download']);
994
+		$share->setSendPasswordByTalk((bool) $data['password_by_talk']);
995
+		$share->setHideDownload((bool) $data['hide_download']);
996 996
 
997 997
 		if ($data['uid_initiator'] !== null) {
998 998
 			$share->setShareOwner($data['uid_owner']);
@@ -1000,7 +1000,7 @@  discard block
 block discarded – undo
1000 1000
 		} else {
1001 1001
 			//OLD SHARE
1002 1002
 			$share->setSharedBy($data['uid_owner']);
1003
-			$path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
1003
+			$path = $this->getNode($share->getSharedBy(), (int) $data['file_source']);
1004 1004
 
1005 1005
 			$owner = $path->getOwner();
1006 1006
 			$share->setShareOwner($owner->getUID());
@@ -1013,7 +1013,7 @@  discard block
 block discarded – undo
1013 1013
 			}
1014 1014
 		}
1015 1015
 
1016
-		$share->setNodeId((int)$data['file_source']);
1016
+		$share->setNodeId((int) $data['file_source']);
1017 1017
 		$share->setNodeType($data['item_type']);
1018 1018
 
1019 1019
 		$share->setProviderId($this->identifier());
@@ -1130,7 +1130,7 @@  discard block
 block discarded – undo
1130 1130
 			);
1131 1131
 		}
1132 1132
 
1133
-		$qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1133
+		$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
1134 1134
 		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
1135 1135
 
1136 1136
 		$qb->orderBy('id');
Please login to merge, or discard this patch.
apps/sharebymail/lib/Capabilities.php 1 patch
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -32,33 +32,33 @@
 block discarded – undo
32 32
 
33 33
 class Capabilities implements ICapability {
34 34
 
35
-	/** @var IManager */
36
-	private $manager;
35
+    /** @var IManager */
36
+    private $manager;
37 37
 
38
-	public function __construct(IManager $manager) {
39
-		$this->manager = $manager;
40
-	}
38
+    public function __construct(IManager $manager) {
39
+        $this->manager = $manager;
40
+    }
41 41
 
42
-	public function getCapabilities(): array {
43
-		return [
44
-			'files_sharing' =>
45
-				[
46
-					'sharebymail' =>
47
-						[
48
-							'enabled' => $this->manager->shareApiAllowLinks(),
49
-							'upload_files_drop' => [
50
-								'enabled' => true,
51
-							],
52
-							'password' => [
53
-								'enabled' => true,
54
-								'enforced' => $this->manager->shareApiLinkEnforcePassword(),
55
-							],
56
-							'expire_date' => [
57
-								'enabled' => true,
58
-								'enforced' => $this->manager->shareApiLinkDefaultExpireDateEnforced(),
59
-							],
60
-						]
61
-				]
62
-		];
63
-	}
42
+    public function getCapabilities(): array {
43
+        return [
44
+            'files_sharing' =>
45
+                [
46
+                    'sharebymail' =>
47
+                        [
48
+                            'enabled' => $this->manager->shareApiAllowLinks(),
49
+                            'upload_files_drop' => [
50
+                                'enabled' => true,
51
+                            ],
52
+                            'password' => [
53
+                                'enabled' => true,
54
+                                'enforced' => $this->manager->shareApiLinkEnforcePassword(),
55
+                            ],
56
+                            'expire_date' => [
57
+                                'enabled' => true,
58
+                                'enforced' => $this->manager->shareApiLinkDefaultExpireDateEnforced(),
59
+                            ],
60
+                        ]
61
+                ]
62
+        ];
63
+    }
64 64
 }
Please login to merge, or discard this patch.
apps/sharebymail/lib/Settings/SettingsManager.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -31,34 +31,34 @@
 block discarded – undo
31 31
 
32 32
 class SettingsManager {
33 33
 
34
-	/** @var IConfig */
35
-	private $config;
34
+    /** @var IConfig */
35
+    private $config;
36 36
 
37
-	private $sendPasswordByMailDefault = 'yes';
37
+    private $sendPasswordByMailDefault = 'yes';
38 38
 
39
-	private $replyToInitiatorDefault = 'yes';
39
+    private $replyToInitiatorDefault = 'yes';
40 40
 
41
-	public function __construct(IConfig $config) {
42
-		$this->config = $config;
43
-	}
41
+    public function __construct(IConfig $config) {
42
+        $this->config = $config;
43
+    }
44 44
 
45
-	/**
46
-	 * should the password for a mail share be send to the recipient
47
-	 *
48
-	 * @return bool
49
-	 */
50
-	public function sendPasswordByMail(): bool {
51
-		$sendPasswordByMail = $this->config->getAppValue('sharebymail', 'sendpasswordmail', $this->sendPasswordByMailDefault);
52
-		return $sendPasswordByMail === 'yes';
53
-	}
45
+    /**
46
+     * should the password for a mail share be send to the recipient
47
+     *
48
+     * @return bool
49
+     */
50
+    public function sendPasswordByMail(): bool {
51
+        $sendPasswordByMail = $this->config->getAppValue('sharebymail', 'sendpasswordmail', $this->sendPasswordByMailDefault);
52
+        return $sendPasswordByMail === 'yes';
53
+    }
54 54
 
55
-	/**
56
-	 * should add reply to with initiator mail
57
-	 *
58
-	 * @return bool
59
-	 */
60
-	public function replyToInitiator(): bool {
61
-		$replyToInitiator = $this->config->getAppValue('sharebymail', 'replyToInitiator', $this->replyToInitiatorDefault);
62
-		return $replyToInitiator === 'yes';
63
-	}
55
+    /**
56
+     * should add reply to with initiator mail
57
+     *
58
+     * @return bool
59
+     */
60
+    public function replyToInitiator(): bool {
61
+        $replyToInitiator = $this->config->getAppValue('sharebymail', 'replyToInitiator', $this->replyToInitiatorDefault);
62
+        return $replyToInitiator === 'yes';
63
+    }
64 64
 }
Please login to merge, or discard this patch.
apps/sharebymail/lib/Settings/Admin.php 1 patch
Indentation   +31 added lines, -31 removed lines patch added patch discarded remove patch
@@ -28,40 +28,40 @@
 block discarded – undo
28 28
 
29 29
 class Admin implements ISettings {
30 30
 
31
-	/** @var SettingsManager */
32
-	private $settingsManager;
31
+    /** @var SettingsManager */
32
+    private $settingsManager;
33 33
 
34
-	public function __construct(SettingsManager $settingsManager) {
35
-		$this->settingsManager = $settingsManager;
36
-	}
34
+    public function __construct(SettingsManager $settingsManager) {
35
+        $this->settingsManager = $settingsManager;
36
+    }
37 37
 
38
-	/**
39
-	 * @return TemplateResponse
40
-	 */
41
-	public function getForm() {
42
-		$parameters = [
43
-			'sendPasswordMail' => $this->settingsManager->sendPasswordByMail(),
44
-			'replyToInitiator' => $this->settingsManager->replyToInitiator()
45
-		];
38
+    /**
39
+     * @return TemplateResponse
40
+     */
41
+    public function getForm() {
42
+        $parameters = [
43
+            'sendPasswordMail' => $this->settingsManager->sendPasswordByMail(),
44
+            'replyToInitiator' => $this->settingsManager->replyToInitiator()
45
+        ];
46 46
 
47
-		return new TemplateResponse('sharebymail', 'settings-admin', $parameters, '');
48
-	}
47
+        return new TemplateResponse('sharebymail', 'settings-admin', $parameters, '');
48
+    }
49 49
 
50
-	/**
51
-	 * @return string the section ID, e.g. 'sharing'
52
-	 */
53
-	public function getSection() {
54
-		return 'sharing';
55
-	}
50
+    /**
51
+     * @return string the section ID, e.g. 'sharing'
52
+     */
53
+    public function getSection() {
54
+        return 'sharing';
55
+    }
56 56
 
57
-	/**
58
-	 * @return int whether the form should be rather on the top or bottom of
59
-	 * the admin section. The forms are arranged in ascending order of the
60
-	 * priority values. It is required to return a value between 0 and 100.
61
-	 *
62
-	 * E.g.: 70
63
-	 */
64
-	public function getPriority() {
65
-		return 40;
66
-	}
57
+    /**
58
+     * @return int whether the form should be rather on the top or bottom of
59
+     * the admin section. The forms are arranged in ascending order of the
60
+     * priority values. It is required to return a value between 0 and 100.
61
+     *
62
+     * E.g.: 70
63
+     */
64
+    public function getPriority() {
65
+        return 40;
66
+    }
67 67
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareAPIController.php 1 patch
Indentation   +1692 added lines, -1692 removed lines patch added patch discarded remove patch
@@ -84,1699 +84,1699 @@
 block discarded – undo
84 84
  */
85 85
 class ShareAPIController extends OCSController {
86 86
 
87
-	/** @var IManager */
88
-	private $shareManager;
89
-	/** @var IGroupManager */
90
-	private $groupManager;
91
-	/** @var IUserManager */
92
-	private $userManager;
93
-	/** @var IRootFolder */
94
-	private $rootFolder;
95
-	/** @var IURLGenerator */
96
-	private $urlGenerator;
97
-	/** @var string */
98
-	private $currentUser;
99
-	/** @var IL10N */
100
-	private $l;
101
-	/** @var \OCP\Files\Node */
102
-	private $lockedNode;
103
-	/** @var IConfig */
104
-	private $config;
105
-	/** @var IAppManager */
106
-	private $appManager;
107
-	/** @var IServerContainer */
108
-	private $serverContainer;
109
-	/** @var IUserStatusManager */
110
-	private $userStatusManager;
111
-	/** @var IPreview */
112
-	private $previewManager;
113
-
114
-	/**
115
-	 * Share20OCS constructor.
116
-	 *
117
-	 * @param string $appName
118
-	 * @param IRequest $request
119
-	 * @param IManager $shareManager
120
-	 * @param IGroupManager $groupManager
121
-	 * @param IUserManager $userManager
122
-	 * @param IRootFolder $rootFolder
123
-	 * @param IURLGenerator $urlGenerator
124
-	 * @param string $userId
125
-	 * @param IL10N $l10n
126
-	 * @param IConfig $config
127
-	 * @param IAppManager $appManager
128
-	 * @param IServerContainer $serverContainer
129
-	 * @param IUserStatusManager $userStatusManager
130
-	 */
131
-	public function __construct(
132
-		string $appName,
133
-		IRequest $request,
134
-		IManager $shareManager,
135
-		IGroupManager $groupManager,
136
-		IUserManager $userManager,
137
-		IRootFolder $rootFolder,
138
-		IURLGenerator $urlGenerator,
139
-		string $userId = null,
140
-		IL10N $l10n,
141
-		IConfig $config,
142
-		IAppManager $appManager,
143
-		IServerContainer $serverContainer,
144
-		IUserStatusManager $userStatusManager,
145
-		IPreview $previewManager
146
-	) {
147
-		parent::__construct($appName, $request);
148
-
149
-		$this->shareManager = $shareManager;
150
-		$this->userManager = $userManager;
151
-		$this->groupManager = $groupManager;
152
-		$this->request = $request;
153
-		$this->rootFolder = $rootFolder;
154
-		$this->urlGenerator = $urlGenerator;
155
-		$this->currentUser = $userId;
156
-		$this->l = $l10n;
157
-		$this->config = $config;
158
-		$this->appManager = $appManager;
159
-		$this->serverContainer = $serverContainer;
160
-		$this->userStatusManager = $userStatusManager;
161
-		$this->previewManager = $previewManager;
162
-	}
163
-
164
-	/**
165
-	 * Convert an IShare to an array for OCS output
166
-	 *
167
-	 * @param \OCP\Share\IShare $share
168
-	 * @param Node|null $recipientNode
169
-	 * @return array
170
-	 * @throws NotFoundException In case the node can't be resolved.
171
-	 *
172
-	 * @suppress PhanUndeclaredClassMethod
173
-	 */
174
-	protected function formatShare(IShare $share, Node $recipientNode = null): array {
175
-		$sharedBy = $this->userManager->get($share->getSharedBy());
176
-		$shareOwner = $this->userManager->get($share->getShareOwner());
177
-
178
-		$result = [
179
-			'id' => $share->getId(),
180
-			'share_type' => $share->getShareType(),
181
-			'uid_owner' => $share->getSharedBy(),
182
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
183
-			// recipient permissions
184
-			'permissions' => $share->getPermissions(),
185
-			// current user permissions on this share
186
-			'can_edit' => $this->canEditShare($share),
187
-			'can_delete' => $this->canDeleteShare($share),
188
-			'stime' => $share->getShareTime()->getTimestamp(),
189
-			'parent' => null,
190
-			'expiration' => null,
191
-			'token' => null,
192
-			'uid_file_owner' => $share->getShareOwner(),
193
-			'note' => $share->getNote(),
194
-			'label' => $share->getLabel(),
195
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
196
-		];
197
-
198
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
199
-		if ($recipientNode) {
200
-			$node = $recipientNode;
201
-		} else {
202
-			$nodes = $userFolder->getById($share->getNodeId());
203
-			if (empty($nodes)) {
204
-				// fallback to guessing the path
205
-				$node = $userFolder->get($share->getTarget());
206
-				if ($node === null || $share->getTarget() === '') {
207
-					throw new NotFoundException();
208
-				}
209
-			} else {
210
-				$node = reset($nodes);
211
-			}
212
-		}
213
-
214
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
215
-		if ($node instanceof Folder) {
216
-			$result['item_type'] = 'folder';
217
-		} else {
218
-			$result['item_type'] = 'file';
219
-		}
220
-
221
-		$result['mimetype'] = $node->getMimetype();
222
-		$result['has_preview'] = $this->previewManager->isAvailable($node);
223
-		$result['storage_id'] = $node->getStorage()->getId();
224
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
225
-		$result['item_source'] = $node->getId();
226
-		$result['file_source'] = $node->getId();
227
-		$result['file_parent'] = $node->getParent()->getId();
228
-		$result['file_target'] = $share->getTarget();
229
-
230
-		$expiration = $share->getExpirationDate();
231
-		if ($expiration !== null) {
232
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
233
-		}
234
-
235
-		if ($share->getShareType() === IShare::TYPE_USER) {
236
-			$sharedWith = $this->userManager->get($share->getSharedWith());
237
-			$result['share_with'] = $share->getSharedWith();
238
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
239
-			$result['share_with_displayname_unique'] = $sharedWith !== null ? (
240
-				 $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
241
-			) : $share->getSharedWith();
242
-			$result['status'] = [];
243
-
244
-			$userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
245
-			$userStatus = array_shift($userStatuses);
246
-			if ($userStatus) {
247
-				$result['status'] = [
248
-					'status' => $userStatus->getStatus(),
249
-					'message' => $userStatus->getMessage(),
250
-					'icon' => $userStatus->getIcon(),
251
-					'clearAt' => $userStatus->getClearAt()
252
-						? (int)$userStatus->getClearAt()->format('U')
253
-						: null,
254
-				];
255
-			}
256
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
257
-			$group = $this->groupManager->get($share->getSharedWith());
258
-			$result['share_with'] = $share->getSharedWith();
259
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
260
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
261
-
262
-			// "share_with" and "share_with_displayname" for passwords of link
263
-			// shares was deprecated in Nextcloud 15, use "password" instead.
264
-			$result['share_with'] = $share->getPassword();
265
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
266
-
267
-			$result['password'] = $share->getPassword();
268
-
269
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
270
-
271
-			$result['token'] = $share->getToken();
272
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
273
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
274
-			$result['share_with'] = $share->getSharedWith();
275
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
276
-			$result['token'] = $share->getToken();
277
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
278
-			$result['share_with'] = $share->getSharedWith();
279
-			$result['password'] = $share->getPassword();
280
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
281
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
282
-			$result['token'] = $share->getToken();
283
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
284
-			// getSharedWith() returns either "name (type, owner)" or
285
-			// "name (type, owner) [id]", depending on the Circles app version.
286
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
287
-
288
-			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
289
-			if (empty($result['share_with_displayname'])) {
290
-				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
291
-				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
292
-			}
293
-
294
-			$result['share_with_avatar'] = $share->getSharedWithAvatar();
295
-
296
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
297
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
298
-			if (is_bool($shareWithLength)) {
299
-				$shareWithLength = -1;
300
-			}
301
-			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
302
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
303
-			$result['share_with'] = $share->getSharedWith();
304
-			$result['share_with_displayname'] = '';
305
-
306
-			try {
307
-				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
308
-			} catch (QueryException $e) {
309
-			}
310
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
311
-			$result['share_with'] = $share->getSharedWith();
312
-			$result['share_with_displayname'] = '';
313
-
314
-			try {
315
-				$result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
316
-			} catch (QueryException $e) {
317
-			}
318
-		}
319
-
320
-
321
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
322
-		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
323
-
324
-		return $result;
325
-	}
326
-
327
-	/**
328
-	 * Check if one of the users address books knows the exact property, if
329
-	 * yes we return the full name.
330
-	 *
331
-	 * @param string $query
332
-	 * @param string $property
333
-	 * @return string
334
-	 */
335
-	private function getDisplayNameFromAddressBook(string $query, string $property): string {
336
-		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
337
-		$result = \OC::$server->getContactsManager()->search($query, [$property]);
338
-		foreach ($result as $r) {
339
-			foreach ($r[$property] as $value) {
340
-				if ($value === $query && $r['FN']) {
341
-					return $r['FN'];
342
-				}
343
-			}
344
-		}
345
-
346
-		return $query;
347
-	}
348
-
349
-	/**
350
-	 * Get a specific share by id
351
-	 *
352
-	 * @NoAdminRequired
353
-	 *
354
-	 * @param string $id
355
-	 * @return DataResponse
356
-	 * @throws OCSNotFoundException
357
-	 */
358
-	public function getShare(string $id): DataResponse {
359
-		try {
360
-			$share = $this->getShareById($id);
361
-		} catch (ShareNotFound $e) {
362
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
363
-		}
364
-
365
-		try {
366
-			if ($this->canAccessShare($share)) {
367
-				$share = $this->formatShare($share);
368
-				return new DataResponse([$share]);
369
-			}
370
-		} catch (NotFoundException $e) {
371
-			// Fall trough
372
-		}
373
-
374
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
375
-	}
376
-
377
-	/**
378
-	 * Delete a share
379
-	 *
380
-	 * @NoAdminRequired
381
-	 *
382
-	 * @param string $id
383
-	 * @return DataResponse
384
-	 * @throws OCSNotFoundException
385
-	 */
386
-	public function deleteShare(string $id): DataResponse {
387
-		try {
388
-			$share = $this->getShareById($id);
389
-		} catch (ShareNotFound $e) {
390
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
391
-		}
392
-
393
-		try {
394
-			$this->lock($share->getNode());
395
-		} catch (LockedException $e) {
396
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
397
-		}
398
-
399
-		if (!$this->canAccessShare($share)) {
400
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
401
-		}
402
-
403
-		// if it's a group share or a room share
404
-		// we don't delete the share, but only the
405
-		// mount point. Allowing it to be restored
406
-		// from the deleted shares
407
-		if ($this->canDeleteShareFromSelf($share)) {
408
-			$this->shareManager->deleteFromSelf($share, $this->currentUser);
409
-		} else {
410
-			if (!$this->canDeleteShare($share)) {
411
-				throw new OCSForbiddenException($this->l->t('Could not delete share'));
412
-			}
413
-
414
-			$this->shareManager->deleteShare($share);
415
-		}
416
-
417
-		return new DataResponse();
418
-	}
419
-
420
-	/**
421
-	 * @NoAdminRequired
422
-	 *
423
-	 * @param string $path
424
-	 * @param int $permissions
425
-	 * @param int $shareType
426
-	 * @param string $shareWith
427
-	 * @param string $publicUpload
428
-	 * @param string $password
429
-	 * @param string $sendPasswordByTalk
430
-	 * @param string $expireDate
431
-	 * @param string $label
432
-	 *
433
-	 * @return DataResponse
434
-	 * @throws NotFoundException
435
-	 * @throws OCSBadRequestException
436
-	 * @throws OCSException
437
-	 * @throws OCSForbiddenException
438
-	 * @throws OCSNotFoundException
439
-	 * @throws InvalidPathException
440
-	 * @suppress PhanUndeclaredClassMethod
441
-	 */
442
-	public function createShare(
443
-		string $path = null,
444
-		int $permissions = null,
445
-		int $shareType = -1,
446
-		string $shareWith = null,
447
-		string $publicUpload = 'false',
448
-		string $password = '',
449
-		string $sendPasswordByTalk = null,
450
-		string $expireDate = '',
451
-		string $label = ''
452
-	): DataResponse {
453
-		$share = $this->shareManager->newShare();
454
-
455
-		if ($permissions === null) {
456
-			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
457
-		}
458
-
459
-		// Verify path
460
-		if ($path === null) {
461
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
462
-		}
463
-
464
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
465
-		try {
466
-			$path = $userFolder->get($path);
467
-		} catch (NotFoundException $e) {
468
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
469
-		}
470
-
471
-		$share->setNode($path);
472
-
473
-		try {
474
-			$this->lock($share->getNode());
475
-		} catch (LockedException $e) {
476
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
477
-		}
478
-
479
-		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
480
-			throw new OCSNotFoundException($this->l->t('invalid permissions'));
481
-		}
482
-
483
-		// Shares always require read permissions
484
-		$permissions |= Constants::PERMISSION_READ;
485
-
486
-		if ($path instanceof \OCP\Files\File) {
487
-			// Single file shares should never have delete or create permissions
488
-			$permissions &= ~Constants::PERMISSION_DELETE;
489
-			$permissions &= ~Constants::PERMISSION_CREATE;
490
-		}
491
-
492
-		/**
493
-		 * Hack for https://github.com/owncloud/core/issues/22587
494
-		 * We check the permissions via webdav. But the permissions of the mount point
495
-		 * do not equal the share permissions. Here we fix that for federated mounts.
496
-		 */
497
-		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
498
-			$permissions &= ~($permissions & ~$path->getPermissions());
499
-		}
500
-
501
-		if ($shareType === IShare::TYPE_USER) {
502
-			// Valid user is required to share
503
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
504
-				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
505
-			}
506
-			$share->setSharedWith($shareWith);
507
-			$share->setPermissions($permissions);
508
-		} elseif ($shareType === IShare::TYPE_GROUP) {
509
-			if (!$this->shareManager->allowGroupSharing()) {
510
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
511
-			}
512
-
513
-			// Valid group is required to share
514
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
515
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
516
-			}
517
-			$share->setSharedWith($shareWith);
518
-			$share->setPermissions($permissions);
519
-		} elseif ($shareType === IShare::TYPE_LINK
520
-			|| $shareType === IShare::TYPE_EMAIL) {
521
-
522
-			// Can we even share links?
523
-			if (!$this->shareManager->shareApiAllowLinks()) {
524
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
525
-			}
526
-
527
-			if ($publicUpload === 'true') {
528
-				// Check if public upload is allowed
529
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
530
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
531
-				}
532
-
533
-				// Public upload can only be set for folders
534
-				if ($path instanceof \OCP\Files\File) {
535
-					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
536
-				}
537
-
538
-				$permissions = Constants::PERMISSION_READ |
539
-					Constants::PERMISSION_CREATE |
540
-					Constants::PERMISSION_UPDATE |
541
-					Constants::PERMISSION_DELETE;
542
-			} else {
543
-				$permissions = Constants::PERMISSION_READ;
544
-			}
545
-
546
-			// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
547
-			if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
548
-				$permissions |= Constants::PERMISSION_SHARE;
549
-			}
550
-
551
-			$share->setPermissions($permissions);
552
-
553
-			// Set password
554
-			if ($password !== '') {
555
-				$share->setPassword($password);
556
-			}
557
-
558
-			// Only share by mail have a recipient
559
-			if (is_string($shareWith) && $shareType === IShare::TYPE_EMAIL) {
560
-				$share->setSharedWith($shareWith);
561
-			}
562
-
563
-			// If we have a label, use it
564
-			if (!empty($label)) {
565
-				$share->setLabel($label);
566
-			}
567
-
568
-			if ($sendPasswordByTalk === 'true') {
569
-				if (!$this->appManager->isEnabledForUser('spreed')) {
570
-					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
571
-				}
572
-
573
-				$share->setSendPasswordByTalk(true);
574
-			}
575
-
576
-			//Expire date
577
-			if ($expireDate !== '') {
578
-				try {
579
-					$expireDate = $this->parseDate($expireDate);
580
-					$share->setExpirationDate($expireDate);
581
-				} catch (\Exception $e) {
582
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
583
-				}
584
-			}
585
-		} elseif ($shareType === IShare::TYPE_REMOTE) {
586
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
587
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
588
-			}
589
-
590
-			$share->setSharedWith($shareWith);
591
-			$share->setPermissions($permissions);
592
-		} elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
593
-			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
594
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
595
-			}
596
-
597
-			$share->setSharedWith($shareWith);
598
-			$share->setPermissions($permissions);
599
-		} elseif ($shareType === IShare::TYPE_CIRCLE) {
600
-			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
601
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
602
-			}
603
-
604
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
605
-
606
-			// Valid circle is required to share
607
-			if ($circle === null) {
608
-				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
609
-			}
610
-			$share->setSharedWith($shareWith);
611
-			$share->setPermissions($permissions);
612
-		} elseif ($shareType === IShare::TYPE_ROOM) {
613
-			try {
614
-				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
615
-			} catch (QueryException $e) {
616
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
617
-			}
618
-		} elseif ($shareType === IShare::TYPE_DECK) {
619
-			try {
620
-				$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
621
-			} catch (QueryException $e) {
622
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
623
-			}
624
-		} else {
625
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
626
-		}
627
-
628
-		$share->setShareType($shareType);
629
-		$share->setSharedBy($this->currentUser);
630
-
631
-		try {
632
-			$share = $this->shareManager->createShare($share);
633
-		} catch (GenericShareException $e) {
634
-			\OC::$server->getLogger()->logException($e);
635
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
636
-			throw new OCSException($e->getHint(), $code);
637
-		} catch (\Exception $e) {
638
-			\OC::$server->getLogger()->logException($e);
639
-			throw new OCSForbiddenException($e->getMessage(), $e);
640
-		}
641
-
642
-		$output = $this->formatShare($share);
643
-
644
-		return new DataResponse($output);
645
-	}
646
-
647
-	/**
648
-	 * @param null|Node $node
649
-	 * @param boolean $includeTags
650
-	 *
651
-	 * @return array
652
-	 */
653
-	private function getSharedWithMe($node, bool $includeTags): array {
654
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
655
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
656
-		$circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
657
-		$roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
658
-		$deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
659
-
660
-		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
661
-
662
-		$filteredShares = array_filter($shares, function (IShare $share) {
663
-			return $share->getShareOwner() !== $this->currentUser;
664
-		});
665
-
666
-		$formatted = [];
667
-		foreach ($filteredShares as $share) {
668
-			if ($this->canAccessShare($share)) {
669
-				try {
670
-					$formatted[] = $this->formatShare($share);
671
-				} catch (NotFoundException $e) {
672
-					// Ignore this share
673
-				}
674
-			}
675
-		}
676
-
677
-		if ($includeTags) {
678
-			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
679
-		}
680
-
681
-		return $formatted;
682
-	}
683
-
684
-	/**
685
-	 * @param \OCP\Files\Node $folder
686
-	 *
687
-	 * @return array
688
-	 * @throws OCSBadRequestException
689
-	 * @throws NotFoundException
690
-	 */
691
-	private function getSharesInDir(Node $folder): array {
692
-		if (!($folder instanceof \OCP\Files\Folder)) {
693
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
694
-		}
695
-
696
-		$nodes = $folder->getDirectoryListing();
697
-
698
-		/** @var \OCP\Share\IShare[] $shares */
699
-		$shares = array_reduce($nodes, function ($carry, $node) {
700
-			$carry = array_merge($carry, $this->getAllShares($node, true));
701
-			return $carry;
702
-		}, []);
703
-
704
-		// filter out duplicate shares
705
-		$known = [];
706
-
707
-
708
-		$formatted = $miniFormatted = [];
709
-		$resharingRight = false;
710
-		$known = [];
711
-		foreach ($shares as $share) {
712
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
713
-				continue;
714
-			}
715
-
716
-			try {
717
-				$format = $this->formatShare($share);
718
-
719
-				$known[] = $share->getId();
720
-				$formatted[] = $format;
721
-				if ($share->getSharedBy() === $this->currentUser) {
722
-					$miniFormatted[] = $format;
723
-				}
724
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
725
-					$resharingRight = true;
726
-				}
727
-			} catch (\Exception $e) {
728
-				//Ignore this share
729
-			}
730
-		}
731
-
732
-		if (!$resharingRight) {
733
-			$formatted = $miniFormatted;
734
-		}
735
-
736
-		return $formatted;
737
-	}
738
-
739
-	/**
740
-	 * The getShares function.
741
-	 *
742
-	 * @NoAdminRequired
743
-	 *
744
-	 * @param string $shared_with_me
745
-	 * @param string $reshares
746
-	 * @param string $subfiles
747
-	 * @param string $path
748
-	 *
749
-	 * - Get shares by the current user
750
-	 * - Get shares by the current user and reshares (?reshares=true)
751
-	 * - Get shares with the current user (?shared_with_me=true)
752
-	 * - Get shares for a specific path (?path=...)
753
-	 * - Get all shares in a folder (?subfiles=true&path=..)
754
-	 *
755
-	 * @param string $include_tags
756
-	 *
757
-	 * @return DataResponse
758
-	 * @throws NotFoundException
759
-	 * @throws OCSBadRequestException
760
-	 * @throws OCSNotFoundException
761
-	 */
762
-	public function getShares(
763
-		string $shared_with_me = 'false',
764
-		string $reshares = 'false',
765
-		string $subfiles = 'false',
766
-		string $path = '',
767
-		string $include_tags = 'false'
768
-	): DataResponse {
769
-		$node = null;
770
-		if ($path !== '') {
771
-			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
772
-			try {
773
-				$node = $userFolder->get($path);
774
-				$this->lock($node);
775
-			} catch (NotFoundException $e) {
776
-				throw new OCSNotFoundException(
777
-					$this->l->t('Wrong path, file/folder doesn\'t exist')
778
-				);
779
-			} catch (LockedException $e) {
780
-				throw new OCSNotFoundException($this->l->t('Could not lock node'));
781
-			}
782
-		}
783
-
784
-		$shares = $this->getFormattedShares(
785
-			$this->currentUser,
786
-			$node,
787
-			($shared_with_me === 'true'),
788
-			($reshares === 'true'),
789
-			($subfiles === 'true'),
790
-			($include_tags === 'true')
791
-		);
792
-
793
-		return new DataResponse($shares);
794
-	}
795
-
796
-
797
-	/**
798
-	 * @param string $viewer
799
-	 * @param Node $node
800
-	 * @param bool $sharedWithMe
801
-	 * @param bool $reShares
802
-	 * @param bool $subFiles
803
-	 * @param bool $includeTags
804
-	 *
805
-	 * @return array
806
-	 * @throws NotFoundException
807
-	 * @throws OCSBadRequestException
808
-	 */
809
-	private function getFormattedShares(
810
-		string $viewer,
811
-		$node = null,
812
-		bool $sharedWithMe = false,
813
-		bool $reShares = false,
814
-		bool $subFiles = false,
815
-		bool $includeTags = false
816
-	): array {
817
-		if ($sharedWithMe) {
818
-			return $this->getSharedWithMe($node, $includeTags);
819
-		}
820
-
821
-		if ($subFiles) {
822
-			return $this->getSharesInDir($node);
823
-		}
824
-
825
-		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
826
-
827
-		$known = $formatted = $miniFormatted = [];
828
-		$resharingRight = false;
829
-		foreach ($shares as $share) {
830
-			try {
831
-				$share->getNode();
832
-			} catch (NotFoundException $e) {
833
-				/*
87
+    /** @var IManager */
88
+    private $shareManager;
89
+    /** @var IGroupManager */
90
+    private $groupManager;
91
+    /** @var IUserManager */
92
+    private $userManager;
93
+    /** @var IRootFolder */
94
+    private $rootFolder;
95
+    /** @var IURLGenerator */
96
+    private $urlGenerator;
97
+    /** @var string */
98
+    private $currentUser;
99
+    /** @var IL10N */
100
+    private $l;
101
+    /** @var \OCP\Files\Node */
102
+    private $lockedNode;
103
+    /** @var IConfig */
104
+    private $config;
105
+    /** @var IAppManager */
106
+    private $appManager;
107
+    /** @var IServerContainer */
108
+    private $serverContainer;
109
+    /** @var IUserStatusManager */
110
+    private $userStatusManager;
111
+    /** @var IPreview */
112
+    private $previewManager;
113
+
114
+    /**
115
+     * Share20OCS constructor.
116
+     *
117
+     * @param string $appName
118
+     * @param IRequest $request
119
+     * @param IManager $shareManager
120
+     * @param IGroupManager $groupManager
121
+     * @param IUserManager $userManager
122
+     * @param IRootFolder $rootFolder
123
+     * @param IURLGenerator $urlGenerator
124
+     * @param string $userId
125
+     * @param IL10N $l10n
126
+     * @param IConfig $config
127
+     * @param IAppManager $appManager
128
+     * @param IServerContainer $serverContainer
129
+     * @param IUserStatusManager $userStatusManager
130
+     */
131
+    public function __construct(
132
+        string $appName,
133
+        IRequest $request,
134
+        IManager $shareManager,
135
+        IGroupManager $groupManager,
136
+        IUserManager $userManager,
137
+        IRootFolder $rootFolder,
138
+        IURLGenerator $urlGenerator,
139
+        string $userId = null,
140
+        IL10N $l10n,
141
+        IConfig $config,
142
+        IAppManager $appManager,
143
+        IServerContainer $serverContainer,
144
+        IUserStatusManager $userStatusManager,
145
+        IPreview $previewManager
146
+    ) {
147
+        parent::__construct($appName, $request);
148
+
149
+        $this->shareManager = $shareManager;
150
+        $this->userManager = $userManager;
151
+        $this->groupManager = $groupManager;
152
+        $this->request = $request;
153
+        $this->rootFolder = $rootFolder;
154
+        $this->urlGenerator = $urlGenerator;
155
+        $this->currentUser = $userId;
156
+        $this->l = $l10n;
157
+        $this->config = $config;
158
+        $this->appManager = $appManager;
159
+        $this->serverContainer = $serverContainer;
160
+        $this->userStatusManager = $userStatusManager;
161
+        $this->previewManager = $previewManager;
162
+    }
163
+
164
+    /**
165
+     * Convert an IShare to an array for OCS output
166
+     *
167
+     * @param \OCP\Share\IShare $share
168
+     * @param Node|null $recipientNode
169
+     * @return array
170
+     * @throws NotFoundException In case the node can't be resolved.
171
+     *
172
+     * @suppress PhanUndeclaredClassMethod
173
+     */
174
+    protected function formatShare(IShare $share, Node $recipientNode = null): array {
175
+        $sharedBy = $this->userManager->get($share->getSharedBy());
176
+        $shareOwner = $this->userManager->get($share->getShareOwner());
177
+
178
+        $result = [
179
+            'id' => $share->getId(),
180
+            'share_type' => $share->getShareType(),
181
+            'uid_owner' => $share->getSharedBy(),
182
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
183
+            // recipient permissions
184
+            'permissions' => $share->getPermissions(),
185
+            // current user permissions on this share
186
+            'can_edit' => $this->canEditShare($share),
187
+            'can_delete' => $this->canDeleteShare($share),
188
+            'stime' => $share->getShareTime()->getTimestamp(),
189
+            'parent' => null,
190
+            'expiration' => null,
191
+            'token' => null,
192
+            'uid_file_owner' => $share->getShareOwner(),
193
+            'note' => $share->getNote(),
194
+            'label' => $share->getLabel(),
195
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
196
+        ];
197
+
198
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
199
+        if ($recipientNode) {
200
+            $node = $recipientNode;
201
+        } else {
202
+            $nodes = $userFolder->getById($share->getNodeId());
203
+            if (empty($nodes)) {
204
+                // fallback to guessing the path
205
+                $node = $userFolder->get($share->getTarget());
206
+                if ($node === null || $share->getTarget() === '') {
207
+                    throw new NotFoundException();
208
+                }
209
+            } else {
210
+                $node = reset($nodes);
211
+            }
212
+        }
213
+
214
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
215
+        if ($node instanceof Folder) {
216
+            $result['item_type'] = 'folder';
217
+        } else {
218
+            $result['item_type'] = 'file';
219
+        }
220
+
221
+        $result['mimetype'] = $node->getMimetype();
222
+        $result['has_preview'] = $this->previewManager->isAvailable($node);
223
+        $result['storage_id'] = $node->getStorage()->getId();
224
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
225
+        $result['item_source'] = $node->getId();
226
+        $result['file_source'] = $node->getId();
227
+        $result['file_parent'] = $node->getParent()->getId();
228
+        $result['file_target'] = $share->getTarget();
229
+
230
+        $expiration = $share->getExpirationDate();
231
+        if ($expiration !== null) {
232
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
233
+        }
234
+
235
+        if ($share->getShareType() === IShare::TYPE_USER) {
236
+            $sharedWith = $this->userManager->get($share->getSharedWith());
237
+            $result['share_with'] = $share->getSharedWith();
238
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
239
+            $result['share_with_displayname_unique'] = $sharedWith !== null ? (
240
+                    $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
241
+            ) : $share->getSharedWith();
242
+            $result['status'] = [];
243
+
244
+            $userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
245
+            $userStatus = array_shift($userStatuses);
246
+            if ($userStatus) {
247
+                $result['status'] = [
248
+                    'status' => $userStatus->getStatus(),
249
+                    'message' => $userStatus->getMessage(),
250
+                    'icon' => $userStatus->getIcon(),
251
+                    'clearAt' => $userStatus->getClearAt()
252
+                        ? (int)$userStatus->getClearAt()->format('U')
253
+                        : null,
254
+                ];
255
+            }
256
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
257
+            $group = $this->groupManager->get($share->getSharedWith());
258
+            $result['share_with'] = $share->getSharedWith();
259
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
260
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
261
+
262
+            // "share_with" and "share_with_displayname" for passwords of link
263
+            // shares was deprecated in Nextcloud 15, use "password" instead.
264
+            $result['share_with'] = $share->getPassword();
265
+            $result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
266
+
267
+            $result['password'] = $share->getPassword();
268
+
269
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
270
+
271
+            $result['token'] = $share->getToken();
272
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
273
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
274
+            $result['share_with'] = $share->getSharedWith();
275
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
276
+            $result['token'] = $share->getToken();
277
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
278
+            $result['share_with'] = $share->getSharedWith();
279
+            $result['password'] = $share->getPassword();
280
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
281
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
282
+            $result['token'] = $share->getToken();
283
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
284
+            // getSharedWith() returns either "name (type, owner)" or
285
+            // "name (type, owner) [id]", depending on the Circles app version.
286
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
287
+
288
+            $result['share_with_displayname'] = $share->getSharedWithDisplayName();
289
+            if (empty($result['share_with_displayname'])) {
290
+                $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
291
+                $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
292
+            }
293
+
294
+            $result['share_with_avatar'] = $share->getSharedWithAvatar();
295
+
296
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
297
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
298
+            if (is_bool($shareWithLength)) {
299
+                $shareWithLength = -1;
300
+            }
301
+            $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
302
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
303
+            $result['share_with'] = $share->getSharedWith();
304
+            $result['share_with_displayname'] = '';
305
+
306
+            try {
307
+                $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
308
+            } catch (QueryException $e) {
309
+            }
310
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
311
+            $result['share_with'] = $share->getSharedWith();
312
+            $result['share_with_displayname'] = '';
313
+
314
+            try {
315
+                $result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
316
+            } catch (QueryException $e) {
317
+            }
318
+        }
319
+
320
+
321
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
322
+        $result['hide_download'] = $share->getHideDownload() ? 1 : 0;
323
+
324
+        return $result;
325
+    }
326
+
327
+    /**
328
+     * Check if one of the users address books knows the exact property, if
329
+     * yes we return the full name.
330
+     *
331
+     * @param string $query
332
+     * @param string $property
333
+     * @return string
334
+     */
335
+    private function getDisplayNameFromAddressBook(string $query, string $property): string {
336
+        // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
337
+        $result = \OC::$server->getContactsManager()->search($query, [$property]);
338
+        foreach ($result as $r) {
339
+            foreach ($r[$property] as $value) {
340
+                if ($value === $query && $r['FN']) {
341
+                    return $r['FN'];
342
+                }
343
+            }
344
+        }
345
+
346
+        return $query;
347
+    }
348
+
349
+    /**
350
+     * Get a specific share by id
351
+     *
352
+     * @NoAdminRequired
353
+     *
354
+     * @param string $id
355
+     * @return DataResponse
356
+     * @throws OCSNotFoundException
357
+     */
358
+    public function getShare(string $id): DataResponse {
359
+        try {
360
+            $share = $this->getShareById($id);
361
+        } catch (ShareNotFound $e) {
362
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
363
+        }
364
+
365
+        try {
366
+            if ($this->canAccessShare($share)) {
367
+                $share = $this->formatShare($share);
368
+                return new DataResponse([$share]);
369
+            }
370
+        } catch (NotFoundException $e) {
371
+            // Fall trough
372
+        }
373
+
374
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
375
+    }
376
+
377
+    /**
378
+     * Delete a share
379
+     *
380
+     * @NoAdminRequired
381
+     *
382
+     * @param string $id
383
+     * @return DataResponse
384
+     * @throws OCSNotFoundException
385
+     */
386
+    public function deleteShare(string $id): DataResponse {
387
+        try {
388
+            $share = $this->getShareById($id);
389
+        } catch (ShareNotFound $e) {
390
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
391
+        }
392
+
393
+        try {
394
+            $this->lock($share->getNode());
395
+        } catch (LockedException $e) {
396
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
397
+        }
398
+
399
+        if (!$this->canAccessShare($share)) {
400
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
401
+        }
402
+
403
+        // if it's a group share or a room share
404
+        // we don't delete the share, but only the
405
+        // mount point. Allowing it to be restored
406
+        // from the deleted shares
407
+        if ($this->canDeleteShareFromSelf($share)) {
408
+            $this->shareManager->deleteFromSelf($share, $this->currentUser);
409
+        } else {
410
+            if (!$this->canDeleteShare($share)) {
411
+                throw new OCSForbiddenException($this->l->t('Could not delete share'));
412
+            }
413
+
414
+            $this->shareManager->deleteShare($share);
415
+        }
416
+
417
+        return new DataResponse();
418
+    }
419
+
420
+    /**
421
+     * @NoAdminRequired
422
+     *
423
+     * @param string $path
424
+     * @param int $permissions
425
+     * @param int $shareType
426
+     * @param string $shareWith
427
+     * @param string $publicUpload
428
+     * @param string $password
429
+     * @param string $sendPasswordByTalk
430
+     * @param string $expireDate
431
+     * @param string $label
432
+     *
433
+     * @return DataResponse
434
+     * @throws NotFoundException
435
+     * @throws OCSBadRequestException
436
+     * @throws OCSException
437
+     * @throws OCSForbiddenException
438
+     * @throws OCSNotFoundException
439
+     * @throws InvalidPathException
440
+     * @suppress PhanUndeclaredClassMethod
441
+     */
442
+    public function createShare(
443
+        string $path = null,
444
+        int $permissions = null,
445
+        int $shareType = -1,
446
+        string $shareWith = null,
447
+        string $publicUpload = 'false',
448
+        string $password = '',
449
+        string $sendPasswordByTalk = null,
450
+        string $expireDate = '',
451
+        string $label = ''
452
+    ): DataResponse {
453
+        $share = $this->shareManager->newShare();
454
+
455
+        if ($permissions === null) {
456
+            $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
457
+        }
458
+
459
+        // Verify path
460
+        if ($path === null) {
461
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
462
+        }
463
+
464
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
465
+        try {
466
+            $path = $userFolder->get($path);
467
+        } catch (NotFoundException $e) {
468
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
469
+        }
470
+
471
+        $share->setNode($path);
472
+
473
+        try {
474
+            $this->lock($share->getNode());
475
+        } catch (LockedException $e) {
476
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
477
+        }
478
+
479
+        if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
480
+            throw new OCSNotFoundException($this->l->t('invalid permissions'));
481
+        }
482
+
483
+        // Shares always require read permissions
484
+        $permissions |= Constants::PERMISSION_READ;
485
+
486
+        if ($path instanceof \OCP\Files\File) {
487
+            // Single file shares should never have delete or create permissions
488
+            $permissions &= ~Constants::PERMISSION_DELETE;
489
+            $permissions &= ~Constants::PERMISSION_CREATE;
490
+        }
491
+
492
+        /**
493
+         * Hack for https://github.com/owncloud/core/issues/22587
494
+         * We check the permissions via webdav. But the permissions of the mount point
495
+         * do not equal the share permissions. Here we fix that for federated mounts.
496
+         */
497
+        if ($path->getStorage()->instanceOfStorage(Storage::class)) {
498
+            $permissions &= ~($permissions & ~$path->getPermissions());
499
+        }
500
+
501
+        if ($shareType === IShare::TYPE_USER) {
502
+            // Valid user is required to share
503
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
504
+                throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
505
+            }
506
+            $share->setSharedWith($shareWith);
507
+            $share->setPermissions($permissions);
508
+        } elseif ($shareType === IShare::TYPE_GROUP) {
509
+            if (!$this->shareManager->allowGroupSharing()) {
510
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
511
+            }
512
+
513
+            // Valid group is required to share
514
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
515
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
516
+            }
517
+            $share->setSharedWith($shareWith);
518
+            $share->setPermissions($permissions);
519
+        } elseif ($shareType === IShare::TYPE_LINK
520
+            || $shareType === IShare::TYPE_EMAIL) {
521
+
522
+            // Can we even share links?
523
+            if (!$this->shareManager->shareApiAllowLinks()) {
524
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
525
+            }
526
+
527
+            if ($publicUpload === 'true') {
528
+                // Check if public upload is allowed
529
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
530
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
531
+                }
532
+
533
+                // Public upload can only be set for folders
534
+                if ($path instanceof \OCP\Files\File) {
535
+                    throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
536
+                }
537
+
538
+                $permissions = Constants::PERMISSION_READ |
539
+                    Constants::PERMISSION_CREATE |
540
+                    Constants::PERMISSION_UPDATE |
541
+                    Constants::PERMISSION_DELETE;
542
+            } else {
543
+                $permissions = Constants::PERMISSION_READ;
544
+            }
545
+
546
+            // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
547
+            if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
548
+                $permissions |= Constants::PERMISSION_SHARE;
549
+            }
550
+
551
+            $share->setPermissions($permissions);
552
+
553
+            // Set password
554
+            if ($password !== '') {
555
+                $share->setPassword($password);
556
+            }
557
+
558
+            // Only share by mail have a recipient
559
+            if (is_string($shareWith) && $shareType === IShare::TYPE_EMAIL) {
560
+                $share->setSharedWith($shareWith);
561
+            }
562
+
563
+            // If we have a label, use it
564
+            if (!empty($label)) {
565
+                $share->setLabel($label);
566
+            }
567
+
568
+            if ($sendPasswordByTalk === 'true') {
569
+                if (!$this->appManager->isEnabledForUser('spreed')) {
570
+                    throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
571
+                }
572
+
573
+                $share->setSendPasswordByTalk(true);
574
+            }
575
+
576
+            //Expire date
577
+            if ($expireDate !== '') {
578
+                try {
579
+                    $expireDate = $this->parseDate($expireDate);
580
+                    $share->setExpirationDate($expireDate);
581
+                } catch (\Exception $e) {
582
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
583
+                }
584
+            }
585
+        } elseif ($shareType === IShare::TYPE_REMOTE) {
586
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
587
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
588
+            }
589
+
590
+            $share->setSharedWith($shareWith);
591
+            $share->setPermissions($permissions);
592
+        } elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
593
+            if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
594
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
595
+            }
596
+
597
+            $share->setSharedWith($shareWith);
598
+            $share->setPermissions($permissions);
599
+        } elseif ($shareType === IShare::TYPE_CIRCLE) {
600
+            if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
601
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
602
+            }
603
+
604
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
605
+
606
+            // Valid circle is required to share
607
+            if ($circle === null) {
608
+                throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
609
+            }
610
+            $share->setSharedWith($shareWith);
611
+            $share->setPermissions($permissions);
612
+        } elseif ($shareType === IShare::TYPE_ROOM) {
613
+            try {
614
+                $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
615
+            } catch (QueryException $e) {
616
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
617
+            }
618
+        } elseif ($shareType === IShare::TYPE_DECK) {
619
+            try {
620
+                $this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
621
+            } catch (QueryException $e) {
622
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
623
+            }
624
+        } else {
625
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
626
+        }
627
+
628
+        $share->setShareType($shareType);
629
+        $share->setSharedBy($this->currentUser);
630
+
631
+        try {
632
+            $share = $this->shareManager->createShare($share);
633
+        } catch (GenericShareException $e) {
634
+            \OC::$server->getLogger()->logException($e);
635
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
636
+            throw new OCSException($e->getHint(), $code);
637
+        } catch (\Exception $e) {
638
+            \OC::$server->getLogger()->logException($e);
639
+            throw new OCSForbiddenException($e->getMessage(), $e);
640
+        }
641
+
642
+        $output = $this->formatShare($share);
643
+
644
+        return new DataResponse($output);
645
+    }
646
+
647
+    /**
648
+     * @param null|Node $node
649
+     * @param boolean $includeTags
650
+     *
651
+     * @return array
652
+     */
653
+    private function getSharedWithMe($node, bool $includeTags): array {
654
+        $userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
655
+        $groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
656
+        $circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
657
+        $roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
658
+        $deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
659
+
660
+        $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
661
+
662
+        $filteredShares = array_filter($shares, function (IShare $share) {
663
+            return $share->getShareOwner() !== $this->currentUser;
664
+        });
665
+
666
+        $formatted = [];
667
+        foreach ($filteredShares as $share) {
668
+            if ($this->canAccessShare($share)) {
669
+                try {
670
+                    $formatted[] = $this->formatShare($share);
671
+                } catch (NotFoundException $e) {
672
+                    // Ignore this share
673
+                }
674
+            }
675
+        }
676
+
677
+        if ($includeTags) {
678
+            $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
679
+        }
680
+
681
+        return $formatted;
682
+    }
683
+
684
+    /**
685
+     * @param \OCP\Files\Node $folder
686
+     *
687
+     * @return array
688
+     * @throws OCSBadRequestException
689
+     * @throws NotFoundException
690
+     */
691
+    private function getSharesInDir(Node $folder): array {
692
+        if (!($folder instanceof \OCP\Files\Folder)) {
693
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
694
+        }
695
+
696
+        $nodes = $folder->getDirectoryListing();
697
+
698
+        /** @var \OCP\Share\IShare[] $shares */
699
+        $shares = array_reduce($nodes, function ($carry, $node) {
700
+            $carry = array_merge($carry, $this->getAllShares($node, true));
701
+            return $carry;
702
+        }, []);
703
+
704
+        // filter out duplicate shares
705
+        $known = [];
706
+
707
+
708
+        $formatted = $miniFormatted = [];
709
+        $resharingRight = false;
710
+        $known = [];
711
+        foreach ($shares as $share) {
712
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
713
+                continue;
714
+            }
715
+
716
+            try {
717
+                $format = $this->formatShare($share);
718
+
719
+                $known[] = $share->getId();
720
+                $formatted[] = $format;
721
+                if ($share->getSharedBy() === $this->currentUser) {
722
+                    $miniFormatted[] = $format;
723
+                }
724
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
725
+                    $resharingRight = true;
726
+                }
727
+            } catch (\Exception $e) {
728
+                //Ignore this share
729
+            }
730
+        }
731
+
732
+        if (!$resharingRight) {
733
+            $formatted = $miniFormatted;
734
+        }
735
+
736
+        return $formatted;
737
+    }
738
+
739
+    /**
740
+     * The getShares function.
741
+     *
742
+     * @NoAdminRequired
743
+     *
744
+     * @param string $shared_with_me
745
+     * @param string $reshares
746
+     * @param string $subfiles
747
+     * @param string $path
748
+     *
749
+     * - Get shares by the current user
750
+     * - Get shares by the current user and reshares (?reshares=true)
751
+     * - Get shares with the current user (?shared_with_me=true)
752
+     * - Get shares for a specific path (?path=...)
753
+     * - Get all shares in a folder (?subfiles=true&path=..)
754
+     *
755
+     * @param string $include_tags
756
+     *
757
+     * @return DataResponse
758
+     * @throws NotFoundException
759
+     * @throws OCSBadRequestException
760
+     * @throws OCSNotFoundException
761
+     */
762
+    public function getShares(
763
+        string $shared_with_me = 'false',
764
+        string $reshares = 'false',
765
+        string $subfiles = 'false',
766
+        string $path = '',
767
+        string $include_tags = 'false'
768
+    ): DataResponse {
769
+        $node = null;
770
+        if ($path !== '') {
771
+            $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
772
+            try {
773
+                $node = $userFolder->get($path);
774
+                $this->lock($node);
775
+            } catch (NotFoundException $e) {
776
+                throw new OCSNotFoundException(
777
+                    $this->l->t('Wrong path, file/folder doesn\'t exist')
778
+                );
779
+            } catch (LockedException $e) {
780
+                throw new OCSNotFoundException($this->l->t('Could not lock node'));
781
+            }
782
+        }
783
+
784
+        $shares = $this->getFormattedShares(
785
+            $this->currentUser,
786
+            $node,
787
+            ($shared_with_me === 'true'),
788
+            ($reshares === 'true'),
789
+            ($subfiles === 'true'),
790
+            ($include_tags === 'true')
791
+        );
792
+
793
+        return new DataResponse($shares);
794
+    }
795
+
796
+
797
+    /**
798
+     * @param string $viewer
799
+     * @param Node $node
800
+     * @param bool $sharedWithMe
801
+     * @param bool $reShares
802
+     * @param bool $subFiles
803
+     * @param bool $includeTags
804
+     *
805
+     * @return array
806
+     * @throws NotFoundException
807
+     * @throws OCSBadRequestException
808
+     */
809
+    private function getFormattedShares(
810
+        string $viewer,
811
+        $node = null,
812
+        bool $sharedWithMe = false,
813
+        bool $reShares = false,
814
+        bool $subFiles = false,
815
+        bool $includeTags = false
816
+    ): array {
817
+        if ($sharedWithMe) {
818
+            return $this->getSharedWithMe($node, $includeTags);
819
+        }
820
+
821
+        if ($subFiles) {
822
+            return $this->getSharesInDir($node);
823
+        }
824
+
825
+        $shares = $this->getSharesFromNode($viewer, $node, $reShares);
826
+
827
+        $known = $formatted = $miniFormatted = [];
828
+        $resharingRight = false;
829
+        foreach ($shares as $share) {
830
+            try {
831
+                $share->getNode();
832
+            } catch (NotFoundException $e) {
833
+                /*
834 834
 				 * Ignore shares where we can't get the node
835 835
 				 * For example deleted shares
836 836
 				 */
837
-				continue;
838
-			}
839
-
840
-			if (in_array($share->getId(), $known)
841
-				|| ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
842
-				continue;
843
-			}
844
-
845
-			$known[] = $share->getId();
846
-			try {
847
-				/** @var IShare $share */
848
-				$format = $this->formatShare($share, $node);
849
-				$formatted[] = $format;
850
-
851
-				// let's also build a list of shares created
852
-				// by the current user only, in case
853
-				// there is no resharing rights
854
-				if ($share->getSharedBy() === $this->currentUser) {
855
-					$miniFormatted[] = $format;
856
-				}
857
-
858
-				// check if one of those share is shared with me
859
-				// and if I have resharing rights on it
860
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
861
-					$resharingRight = true;
862
-				}
863
-			} catch (InvalidPathException | NotFoundException $e) {
864
-			}
865
-		}
866
-
867
-		if (!$resharingRight) {
868
-			$formatted = $miniFormatted;
869
-		}
870
-
871
-		if ($includeTags) {
872
-			$formatted =
873
-				Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
874
-		}
875
-
876
-		return $formatted;
877
-	}
878
-
879
-
880
-	/**
881
-	 * The getInheritedShares function.
882
-	 * returns all shares relative to a file, including parent folders shares rights.
883
-	 *
884
-	 * @NoAdminRequired
885
-	 *
886
-	 * @param string $path
887
-	 *
888
-	 * - Get shares by the current user
889
-	 * - Get shares by the current user and reshares (?reshares=true)
890
-	 * - Get shares with the current user (?shared_with_me=true)
891
-	 * - Get shares for a specific path (?path=...)
892
-	 * - Get all shares in a folder (?subfiles=true&path=..)
893
-	 *
894
-	 * @return DataResponse
895
-	 * @throws InvalidPathException
896
-	 * @throws NotFoundException
897
-	 * @throws OCSNotFoundException
898
-	 * @throws OCSBadRequestException
899
-	 * @throws SharingRightsException
900
-	 */
901
-	public function getInheritedShares(string $path): DataResponse {
902
-
903
-		// get Node from (string) path.
904
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
905
-		try {
906
-			$node = $userFolder->get($path);
907
-			$this->lock($node);
908
-		} catch (\OCP\Files\NotFoundException $e) {
909
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
910
-		} catch (LockedException $e) {
911
-			throw new OCSNotFoundException($this->l->t('Could not lock path'));
912
-		}
913
-
914
-		if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
915
-			throw new SharingRightsException('no sharing rights on this item');
916
-		}
917
-
918
-		// The current top parent we have access to
919
-		$parent = $node;
920
-
921
-		// initiate real owner.
922
-		$owner = $node->getOwner()
923
-					  ->getUID();
924
-		if (!$this->userManager->userExists($owner)) {
925
-			return new DataResponse([]);
926
-		}
927
-
928
-		// get node based on the owner, fix owner in case of external storage
929
-		$userFolder = $this->rootFolder->getUserFolder($owner);
930
-		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
931
-			$owner = $node->getOwner()
932
-						  ->getUID();
933
-			$userFolder = $this->rootFolder->getUserFolder($owner);
934
-			$nodes = $userFolder->getById($node->getId());
935
-			$node = array_shift($nodes);
936
-		}
937
-		$basePath = $userFolder->getPath();
938
-
939
-		// generate node list for each parent folders
940
-		/** @var Node[] $nodes */
941
-		$nodes = [];
942
-		while ($node->getPath() !== $basePath) {
943
-			$node = $node->getParent();
944
-			$nodes[] = $node;
945
-		}
946
-
947
-		// The user that is requesting this list
948
-		$currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
949
-
950
-		// for each nodes, retrieve shares.
951
-		$shares = [];
952
-
953
-		foreach ($nodes as $node) {
954
-			$getShares = $this->getFormattedShares($owner, $node, false, true);
955
-
956
-			$currentUserNodes = $currentUserFolder->getById($node->getId());
957
-			if (!empty($currentUserNodes)) {
958
-				$parent = array_pop($currentUserNodes);
959
-			}
960
-
961
-			$subPath = $currentUserFolder->getRelativePath($parent->getPath());
962
-			foreach ($getShares as &$share) {
963
-				$share['via_fileid'] = $parent->getId();
964
-				$share['via_path'] = $subPath;
965
-			}
966
-			$this->mergeFormattedShares($shares, $getShares);
967
-		}
968
-
969
-		return new DataResponse(array_values($shares));
970
-	}
971
-
972
-
973
-	/**
974
-	 * @NoAdminRequired
975
-	 *
976
-	 * @param string $id
977
-	 * @param int $permissions
978
-	 * @param string $password
979
-	 * @param string $sendPasswordByTalk
980
-	 * @param string $publicUpload
981
-	 * @param string $expireDate
982
-	 * @param string $note
983
-	 * @param string $label
984
-	 * @param string $hideDownload
985
-	 * @return DataResponse
986
-	 * @throws LockedException
987
-	 * @throws NotFoundException
988
-	 * @throws OCSBadRequestException
989
-	 * @throws OCSForbiddenException
990
-	 * @throws OCSNotFoundException
991
-	 */
992
-	public function updateShare(
993
-		string $id,
994
-		int $permissions = null,
995
-		string $password = null,
996
-		string $sendPasswordByTalk = null,
997
-		string $publicUpload = null,
998
-		string $expireDate = null,
999
-		string $note = null,
1000
-		string $label = null,
1001
-		string $hideDownload = null
1002
-	): DataResponse {
1003
-		try {
1004
-			$share = $this->getShareById($id);
1005
-		} catch (ShareNotFound $e) {
1006
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1007
-		}
1008
-
1009
-		$this->lock($share->getNode());
1010
-
1011
-		if (!$this->canAccessShare($share, false)) {
1012
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1013
-		}
1014
-
1015
-		if (!$this->canEditShare($share)) {
1016
-			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1017
-		}
1018
-
1019
-		if (
1020
-			$permissions === null &&
1021
-			$password === null &&
1022
-			$sendPasswordByTalk === null &&
1023
-			$publicUpload === null &&
1024
-			$expireDate === null &&
1025
-			$note === null &&
1026
-			$label === null &&
1027
-			$hideDownload === null
1028
-		) {
1029
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1030
-		}
1031
-
1032
-		if ($note !== null) {
1033
-			$share->setNote($note);
1034
-		}
1035
-
1036
-		/**
1037
-		 * expirationdate, password and publicUpload only make sense for link shares
1038
-		 */
1039
-		if ($share->getShareType() === IShare::TYPE_LINK
1040
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1041
-
1042
-			/**
1043
-			 * We do not allow editing link shares that the current user
1044
-			 * doesn't own. This is confusing and lead to errors when
1045
-			 * someone else edit a password or expiration date without
1046
-			 * the share owner knowing about it.
1047
-			 * We only allow deletion
1048
-			 */
1049
-
1050
-			if ($share->getSharedBy() !== $this->currentUser) {
1051
-				throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1052
-			}
1053
-
1054
-			// Update hide download state
1055
-			if ($hideDownload === 'true') {
1056
-				$share->setHideDownload(true);
1057
-			} elseif ($hideDownload === 'false') {
1058
-				$share->setHideDownload(false);
1059
-			}
1060
-
1061
-			$newPermissions = null;
1062
-			if ($publicUpload === 'true') {
1063
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1064
-			} elseif ($publicUpload === 'false') {
1065
-				$newPermissions = Constants::PERMISSION_READ;
1066
-			}
1067
-
1068
-			if ($permissions !== null) {
1069
-				$newPermissions = $permissions;
1070
-				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1071
-			}
1072
-
1073
-			if ($newPermissions !== null &&
1074
-				!in_array($newPermissions, [
1075
-					Constants::PERMISSION_READ,
1076
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1077
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1078
-					Constants::PERMISSION_CREATE, // hidden file list
1079
-					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1080
-				], true)
1081
-			) {
1082
-				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1083
-			}
1084
-
1085
-			if (
1086
-				// legacy
1087
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1088
-				// correct
1089
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1090
-			) {
1091
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1092
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1093
-				}
1094
-
1095
-				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1096
-					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1097
-				}
1098
-
1099
-				// normalize to correct public upload permissions
1100
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1101
-			}
1102
-
1103
-			if ($newPermissions !== null) {
1104
-				// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1105
-				if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1106
-					$newPermissions |= Constants::PERMISSION_SHARE;
1107
-				}
1108
-
1109
-				$share->setPermissions($newPermissions);
1110
-				$permissions = $newPermissions;
1111
-			}
1112
-
1113
-			if ($expireDate === '') {
1114
-				$share->setExpirationDate(null);
1115
-			} elseif ($expireDate !== null) {
1116
-				try {
1117
-					$expireDate = $this->parseDate($expireDate);
1118
-				} catch (\Exception $e) {
1119
-					throw new OCSBadRequestException($e->getMessage(), $e);
1120
-				}
1121
-				$share->setExpirationDate($expireDate);
1122
-			}
1123
-
1124
-			if ($password === '') {
1125
-				$share->setPassword(null);
1126
-			} elseif ($password !== null) {
1127
-				$share->setPassword($password);
1128
-			}
1129
-
1130
-			if ($label !== null) {
1131
-				if (strlen($label) > 255) {
1132
-					throw new OCSBadRequestException("Maxmimum label length is 255");
1133
-				}
1134
-				$share->setLabel($label);
1135
-			}
1136
-
1137
-			if ($sendPasswordByTalk === 'true') {
1138
-				if (!$this->appManager->isEnabledForUser('spreed')) {
1139
-					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1140
-				}
1141
-
1142
-				$share->setSendPasswordByTalk(true);
1143
-			} elseif ($sendPasswordByTalk !== null) {
1144
-				$share->setSendPasswordByTalk(false);
1145
-			}
1146
-		}
1147
-
1148
-		// NOT A LINK SHARE
1149
-		else {
1150
-			if ($permissions !== null) {
1151
-				$share->setPermissions($permissions);
1152
-			}
1153
-
1154
-			if ($expireDate === '') {
1155
-				$share->setExpirationDate(null);
1156
-			} elseif ($expireDate !== null) {
1157
-				try {
1158
-					$expireDate = $this->parseDate($expireDate);
1159
-				} catch (\Exception $e) {
1160
-					throw new OCSBadRequestException($e->getMessage(), $e);
1161
-				}
1162
-				$share->setExpirationDate($expireDate);
1163
-			}
1164
-		}
1165
-
1166
-		try {
1167
-			$share = $this->shareManager->updateShare($share);
1168
-		} catch (GenericShareException $e) {
1169
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1170
-			throw new OCSException($e->getHint(), $code);
1171
-		} catch (\Exception $e) {
1172
-			throw new OCSBadRequestException($e->getMessage(), $e);
1173
-		}
1174
-
1175
-		return new DataResponse($this->formatShare($share));
1176
-	}
1177
-
1178
-	/**
1179
-	 * @NoAdminRequired
1180
-	 */
1181
-	public function pendingShares(): DataResponse {
1182
-		$pendingShares = [];
1183
-
1184
-		$shareTypes = [
1185
-			IShare::TYPE_USER,
1186
-			IShare::TYPE_GROUP
1187
-		];
1188
-
1189
-		foreach ($shareTypes as $shareType) {
1190
-			$shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1191
-
1192
-			foreach ($shares as $share) {
1193
-				if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1194
-					$pendingShares[] = $share;
1195
-				}
1196
-			}
1197
-		}
1198
-
1199
-		$result = array_filter(array_map(function (IShare $share) {
1200
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1201
-			$nodes = $userFolder->getById($share->getNodeId());
1202
-			if (empty($nodes)) {
1203
-				// fallback to guessing the path
1204
-				$node = $userFolder->get($share->getTarget());
1205
-				if ($node === null || $share->getTarget() === '') {
1206
-					return null;
1207
-				}
1208
-			} else {
1209
-				$node = $nodes[0];
1210
-			}
1211
-
1212
-			try {
1213
-				$formattedShare = $this->formatShare($share, $node);
1214
-				$formattedShare['status'] = $share->getStatus();
1215
-				$formattedShare['path'] = $share->getNode()->getName();
1216
-				$formattedShare['permissions'] = 0;
1217
-				return $formattedShare;
1218
-			} catch (NotFoundException $e) {
1219
-				return null;
1220
-			}
1221
-		}, $pendingShares), function ($entry) {
1222
-			return $entry !== null;
1223
-		});
1224
-
1225
-		return new DataResponse($result);
1226
-	}
1227
-
1228
-	/**
1229
-	 * @NoAdminRequired
1230
-	 *
1231
-	 * @param string $id
1232
-	 * @return DataResponse
1233
-	 * @throws OCSNotFoundException
1234
-	 * @throws OCSException
1235
-	 * @throws OCSBadRequestException
1236
-	 */
1237
-	public function acceptShare(string $id): DataResponse {
1238
-		try {
1239
-			$share = $this->getShareById($id);
1240
-		} catch (ShareNotFound $e) {
1241
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1242
-		}
1243
-
1244
-		if (!$this->canAccessShare($share)) {
1245
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1246
-		}
1247
-
1248
-		try {
1249
-			$this->shareManager->acceptShare($share, $this->currentUser);
1250
-		} catch (GenericShareException $e) {
1251
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1252
-			throw new OCSException($e->getHint(), $code);
1253
-		} catch (\Exception $e) {
1254
-			throw new OCSBadRequestException($e->getMessage(), $e);
1255
-		}
1256
-
1257
-		return new DataResponse();
1258
-	}
1259
-
1260
-	/**
1261
-	 * Does the user have read permission on the share
1262
-	 *
1263
-	 * @param \OCP\Share\IShare $share the share to check
1264
-	 * @param boolean $checkGroups check groups as well?
1265
-	 * @return boolean
1266
-	 * @throws NotFoundException
1267
-	 *
1268
-	 * @suppress PhanUndeclaredClassMethod
1269
-	 */
1270
-	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1271
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1272
-		if ($share->getPermissions() === 0) {
1273
-			return false;
1274
-		}
1275
-
1276
-		// Owner of the file and the sharer of the file can always get share
1277
-		if ($share->getShareOwner() === $this->currentUser
1278
-			|| $share->getSharedBy() === $this->currentUser) {
1279
-			return true;
1280
-		}
1281
-
1282
-		// If the share is shared with you, you can access it!
1283
-		if ($share->getShareType() === IShare::TYPE_USER
1284
-			&& $share->getSharedWith() === $this->currentUser) {
1285
-			return true;
1286
-		}
1287
-
1288
-		// Have reshare rights on the shared file/folder ?
1289
-		// Does the currentUser have access to the shared file?
1290
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1291
-		$files = $userFolder->getById($share->getNodeId());
1292
-		if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1293
-			return true;
1294
-		}
1295
-
1296
-		// If in the recipient group, you can see the share
1297
-		if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1298
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1299
-			$user = $this->userManager->get($this->currentUser);
1300
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1301
-				return true;
1302
-			}
1303
-		}
1304
-
1305
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1306
-			// TODO: have a sanity check like above?
1307
-			return true;
1308
-		}
1309
-
1310
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1311
-			try {
1312
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1313
-			} catch (QueryException $e) {
1314
-				return false;
1315
-			}
1316
-		}
1317
-
1318
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1319
-			try {
1320
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1321
-			} catch (QueryException $e) {
1322
-				return false;
1323
-			}
1324
-		}
1325
-
1326
-		return false;
1327
-	}
1328
-
1329
-	/**
1330
-	 * Does the user have edit permission on the share
1331
-	 *
1332
-	 * @param \OCP\Share\IShare $share the share to check
1333
-	 * @return boolean
1334
-	 */
1335
-	protected function canEditShare(\OCP\Share\IShare $share): bool {
1336
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1337
-		if ($share->getPermissions() === 0) {
1338
-			return false;
1339
-		}
1340
-
1341
-		// The owner of the file and the creator of the share
1342
-		// can always edit the share
1343
-		if ($share->getShareOwner() === $this->currentUser ||
1344
-			$share->getSharedBy() === $this->currentUser
1345
-		) {
1346
-			return true;
1347
-		}
1348
-
1349
-		//! we do NOT support some kind of `admin` in groups.
1350
-		//! You cannot edit shares shared to a group you're
1351
-		//! a member of if you're not the share owner or the file owner!
1352
-
1353
-		return false;
1354
-	}
1355
-
1356
-	/**
1357
-	 * Does the user have delete permission on the share
1358
-	 *
1359
-	 * @param \OCP\Share\IShare $share the share to check
1360
-	 * @return boolean
1361
-	 */
1362
-	protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1363
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1364
-		if ($share->getPermissions() === 0) {
1365
-			return false;
1366
-		}
1367
-
1368
-		// if the user is the recipient, i can unshare
1369
-		// the share with self
1370
-		if ($share->getShareType() === IShare::TYPE_USER &&
1371
-			$share->getSharedWith() === $this->currentUser
1372
-		) {
1373
-			return true;
1374
-		}
1375
-
1376
-		// The owner of the file and the creator of the share
1377
-		// can always delete the share
1378
-		if ($share->getShareOwner() === $this->currentUser ||
1379
-			$share->getSharedBy() === $this->currentUser
1380
-		) {
1381
-			return true;
1382
-		}
1383
-
1384
-		return false;
1385
-	}
1386
-
1387
-	/**
1388
-	 * Does the user have delete permission on the share
1389
-	 * This differs from the canDeleteShare function as it only
1390
-	 * remove the share for the current user. It does NOT
1391
-	 * completely delete the share but only the mount point.
1392
-	 * It can then be restored from the deleted shares section.
1393
-	 *
1394
-	 * @param \OCP\Share\IShare $share the share to check
1395
-	 * @return boolean
1396
-	 *
1397
-	 * @suppress PhanUndeclaredClassMethod
1398
-	 */
1399
-	protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1400
-		if ($share->getShareType() !== IShare::TYPE_GROUP &&
1401
-			$share->getShareType() !== IShare::TYPE_ROOM &&
1402
-			$share->getShareType() !== IShare::TYPE_DECK
1403
-		) {
1404
-			return false;
1405
-		}
1406
-
1407
-		if ($share->getShareOwner() === $this->currentUser ||
1408
-			$share->getSharedBy() === $this->currentUser
1409
-		) {
1410
-			// Delete the whole share, not just for self
1411
-			return false;
1412
-		}
1413
-
1414
-		// If in the recipient group, you can delete the share from self
1415
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1416
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1417
-			$user = $this->userManager->get($this->currentUser);
1418
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1419
-				return true;
1420
-			}
1421
-		}
1422
-
1423
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1424
-			try {
1425
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1426
-			} catch (QueryException $e) {
1427
-				return false;
1428
-			}
1429
-		}
1430
-
1431
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1432
-			try {
1433
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1434
-			} catch (QueryException $e) {
1435
-				return false;
1436
-			}
1437
-		}
1438
-
1439
-		return false;
1440
-	}
1441
-
1442
-	/**
1443
-	 * Make sure that the passed date is valid ISO 8601
1444
-	 * So YYYY-MM-DD
1445
-	 * If not throw an exception
1446
-	 *
1447
-	 * @param string $expireDate
1448
-	 *
1449
-	 * @throws \Exception
1450
-	 * @return \DateTime
1451
-	 */
1452
-	private function parseDate(string $expireDate): \DateTime {
1453
-		try {
1454
-			$date = new \DateTime($expireDate);
1455
-		} catch (\Exception $e) {
1456
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1457
-		}
1458
-
1459
-		$date->setTime(0, 0, 0);
1460
-
1461
-		return $date;
1462
-	}
1463
-
1464
-	/**
1465
-	 * Since we have multiple providers but the OCS Share API v1 does
1466
-	 * not support this we need to check all backends.
1467
-	 *
1468
-	 * @param string $id
1469
-	 * @return \OCP\Share\IShare
1470
-	 * @throws ShareNotFound
1471
-	 */
1472
-	private function getShareById(string $id): IShare {
1473
-		$share = null;
1474
-
1475
-		// First check if it is an internal share.
1476
-		try {
1477
-			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1478
-			return $share;
1479
-		} catch (ShareNotFound $e) {
1480
-			// Do nothing, just try the other share type
1481
-		}
1482
-
1483
-
1484
-		try {
1485
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1486
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1487
-				return $share;
1488
-			}
1489
-		} catch (ShareNotFound $e) {
1490
-			// Do nothing, just try the other share type
1491
-		}
1492
-
1493
-		try {
1494
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1495
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1496
-				return $share;
1497
-			}
1498
-		} catch (ShareNotFound $e) {
1499
-			// Do nothing, just try the other share type
1500
-		}
1501
-
1502
-		try {
1503
-			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1504
-			return $share;
1505
-		} catch (ShareNotFound $e) {
1506
-			// Do nothing, just try the other share type
1507
-		}
1508
-
1509
-		try {
1510
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1511
-				$share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1512
-				return $share;
1513
-			}
1514
-		} catch (ShareNotFound $e) {
1515
-			// Do nothing, just try the other share type
1516
-		}
1517
-
1518
-		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1519
-			throw new ShareNotFound();
1520
-		}
1521
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1522
-
1523
-		return $share;
1524
-	}
1525
-
1526
-	/**
1527
-	 * Lock a Node
1528
-	 *
1529
-	 * @param \OCP\Files\Node $node
1530
-	 * @throws LockedException
1531
-	 */
1532
-	private function lock(\OCP\Files\Node $node) {
1533
-		$node->lock(ILockingProvider::LOCK_SHARED);
1534
-		$this->lockedNode = $node;
1535
-	}
1536
-
1537
-	/**
1538
-	 * Cleanup the remaining locks
1539
-	 * @throws LockedException
1540
-	 */
1541
-	public function cleanup() {
1542
-		if ($this->lockedNode !== null) {
1543
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1544
-		}
1545
-	}
1546
-
1547
-	/**
1548
-	 * Returns the helper of ShareAPIController for room shares.
1549
-	 *
1550
-	 * If the Talk application is not enabled or the helper is not available
1551
-	 * a QueryException is thrown instead.
1552
-	 *
1553
-	 * @return \OCA\Talk\Share\Helper\ShareAPIController
1554
-	 * @throws QueryException
1555
-	 */
1556
-	private function getRoomShareHelper() {
1557
-		if (!$this->appManager->isEnabledForUser('spreed')) {
1558
-			throw new QueryException();
1559
-		}
1560
-
1561
-		return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1562
-	}
1563
-
1564
-	/**
1565
-	 * Returns the helper of ShareAPIHelper for deck shares.
1566
-	 *
1567
-	 * If the Deck application is not enabled or the helper is not available
1568
-	 * a QueryException is thrown instead.
1569
-	 *
1570
-	 * @return \OCA\Deck\Sharing\ShareAPIHelper
1571
-	 * @throws QueryException
1572
-	 */
1573
-	private function getDeckShareHelper() {
1574
-		if (!$this->appManager->isEnabledForUser('deck')) {
1575
-			throw new QueryException();
1576
-		}
1577
-
1578
-		return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1579
-	}
1580
-
1581
-	/**
1582
-	 * @param string $viewer
1583
-	 * @param Node $node
1584
-	 * @param bool $reShares
1585
-	 *
1586
-	 * @return IShare[]
1587
-	 */
1588
-	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1589
-		$providers = [
1590
-			IShare::TYPE_USER,
1591
-			IShare::TYPE_GROUP,
1592
-			IShare::TYPE_LINK,
1593
-			IShare::TYPE_EMAIL,
1594
-			IShare::TYPE_CIRCLE,
1595
-			IShare::TYPE_ROOM,
1596
-			IShare::TYPE_DECK
1597
-		];
1598
-
1599
-		// Should we assume that the (currentUser) viewer is the owner of the node !?
1600
-		$shares = [];
1601
-		foreach ($providers as $provider) {
1602
-			if (!$this->shareManager->shareProviderExists($provider)) {
1603
-				continue;
1604
-			}
1605
-
1606
-			$providerShares =
1607
-				$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1608
-			$shares = array_merge($shares, $providerShares);
1609
-		}
1610
-
1611
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1612
-			$federatedShares = $this->shareManager->getSharesBy(
1613
-				$this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1614
-			);
1615
-			$shares = array_merge($shares, $federatedShares);
1616
-		}
1617
-
1618
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1619
-			$federatedShares = $this->shareManager->getSharesBy(
1620
-				$this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1621
-			);
1622
-			$shares = array_merge($shares, $federatedShares);
1623
-		}
1624
-
1625
-		return $shares;
1626
-	}
1627
-
1628
-
1629
-	/**
1630
-	 * @param Node $node
1631
-	 *
1632
-	 * @throws SharingRightsException
1633
-	 */
1634
-	private function confirmSharingRights(Node $node): void {
1635
-		if (!$this->hasResharingRights($this->currentUser, $node)) {
1636
-			throw new SharingRightsException('no sharing rights on this item');
1637
-		}
1638
-	}
1639
-
1640
-
1641
-	/**
1642
-	 * @param string $viewer
1643
-	 * @param Node $node
1644
-	 *
1645
-	 * @return bool
1646
-	 */
1647
-	private function hasResharingRights($viewer, $node): bool {
1648
-		if ($viewer === $node->getOwner()->getUID()) {
1649
-			return true;
1650
-		}
1651
-
1652
-		foreach ([$node, $node->getParent()] as $node) {
1653
-			$shares = $this->getSharesFromNode($viewer, $node, true);
1654
-			foreach ($shares as $share) {
1655
-				try {
1656
-					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1657
-						return true;
1658
-					}
1659
-				} catch (InvalidPathException | NotFoundException $e) {
1660
-				}
1661
-			}
1662
-		}
1663
-
1664
-		return false;
1665
-	}
1666
-
1667
-
1668
-	/**
1669
-	 * Returns if we can find resharing rights in an IShare object for a specific user.
1670
-	 *
1671
-	 * @suppress PhanUndeclaredClassMethod
1672
-	 *
1673
-	 * @param string $userId
1674
-	 * @param IShare $share
1675
-	 * @param Node $node
1676
-	 *
1677
-	 * @return bool
1678
-	 * @throws NotFoundException
1679
-	 * @throws InvalidPathException
1680
-	 */
1681
-	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1682
-		if ($share->getShareOwner() === $userId) {
1683
-			return true;
1684
-		}
1685
-
1686
-		// we check that current user have parent resharing rights on the current file
1687
-		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1688
-			return true;
1689
-		}
1690
-
1691
-		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1692
-			return false;
1693
-		}
1694
-
1695
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1696
-			return true;
1697
-		}
1698
-
1699
-		if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1700
-			return true;
1701
-		}
1702
-
1703
-		if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1704
-			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1705
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1706
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1707
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1708
-			if ($shareWithLength === false) {
1709
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart);
1710
-			} else {
1711
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1712
-			}
1713
-			try {
1714
-				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1715
-				if ($member->getLevel() >= 4) {
1716
-					return true;
1717
-				}
1718
-				return false;
1719
-			} catch (QueryException $e) {
1720
-				return false;
1721
-			}
1722
-		}
1723
-
1724
-		return false;
1725
-	}
1726
-
1727
-	/**
1728
-	 * Get all the shares for the current user
1729
-	 *
1730
-	 * @param Node|null $path
1731
-	 * @param boolean $reshares
1732
-	 * @return IShare[]
1733
-	 */
1734
-	private function getAllShares(?Node $path = null, bool $reshares = false) {
1735
-		// Get all shares
1736
-		$userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1737
-		$groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1738
-		$linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1739
-
1740
-		// EMAIL SHARES
1741
-		$mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1742
-
1743
-		// CIRCLE SHARES
1744
-		$circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1745
-
1746
-		// TALK SHARES
1747
-		$roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1748
-
1749
-		$deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1750
-
1751
-		// FEDERATION
1752
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1753
-			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1754
-		} else {
1755
-			$federatedShares = [];
1756
-		}
1757
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1758
-			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1759
-		} else {
1760
-			$federatedGroupShares = [];
1761
-		}
1762
-
1763
-		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1764
-	}
1765
-
1766
-
1767
-	/**
1768
-	 * merging already formatted shares.
1769
-	 * We'll make an associative array to easily detect duplicate Ids.
1770
-	 * Keys _needs_ to be removed after all shares are retrieved and merged.
1771
-	 *
1772
-	 * @param array $shares
1773
-	 * @param array $newShares
1774
-	 */
1775
-	private function mergeFormattedShares(array &$shares, array $newShares) {
1776
-		foreach ($newShares as $newShare) {
1777
-			if (!array_key_exists($newShare['id'], $shares)) {
1778
-				$shares[$newShare['id']] = $newShare;
1779
-			}
1780
-		}
1781
-	}
837
+                continue;
838
+            }
839
+
840
+            if (in_array($share->getId(), $known)
841
+                || ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
842
+                continue;
843
+            }
844
+
845
+            $known[] = $share->getId();
846
+            try {
847
+                /** @var IShare $share */
848
+                $format = $this->formatShare($share, $node);
849
+                $formatted[] = $format;
850
+
851
+                // let's also build a list of shares created
852
+                // by the current user only, in case
853
+                // there is no resharing rights
854
+                if ($share->getSharedBy() === $this->currentUser) {
855
+                    $miniFormatted[] = $format;
856
+                }
857
+
858
+                // check if one of those share is shared with me
859
+                // and if I have resharing rights on it
860
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
861
+                    $resharingRight = true;
862
+                }
863
+            } catch (InvalidPathException | NotFoundException $e) {
864
+            }
865
+        }
866
+
867
+        if (!$resharingRight) {
868
+            $formatted = $miniFormatted;
869
+        }
870
+
871
+        if ($includeTags) {
872
+            $formatted =
873
+                Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
874
+        }
875
+
876
+        return $formatted;
877
+    }
878
+
879
+
880
+    /**
881
+     * The getInheritedShares function.
882
+     * returns all shares relative to a file, including parent folders shares rights.
883
+     *
884
+     * @NoAdminRequired
885
+     *
886
+     * @param string $path
887
+     *
888
+     * - Get shares by the current user
889
+     * - Get shares by the current user and reshares (?reshares=true)
890
+     * - Get shares with the current user (?shared_with_me=true)
891
+     * - Get shares for a specific path (?path=...)
892
+     * - Get all shares in a folder (?subfiles=true&path=..)
893
+     *
894
+     * @return DataResponse
895
+     * @throws InvalidPathException
896
+     * @throws NotFoundException
897
+     * @throws OCSNotFoundException
898
+     * @throws OCSBadRequestException
899
+     * @throws SharingRightsException
900
+     */
901
+    public function getInheritedShares(string $path): DataResponse {
902
+
903
+        // get Node from (string) path.
904
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
905
+        try {
906
+            $node = $userFolder->get($path);
907
+            $this->lock($node);
908
+        } catch (\OCP\Files\NotFoundException $e) {
909
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
910
+        } catch (LockedException $e) {
911
+            throw new OCSNotFoundException($this->l->t('Could not lock path'));
912
+        }
913
+
914
+        if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
915
+            throw new SharingRightsException('no sharing rights on this item');
916
+        }
917
+
918
+        // The current top parent we have access to
919
+        $parent = $node;
920
+
921
+        // initiate real owner.
922
+        $owner = $node->getOwner()
923
+                        ->getUID();
924
+        if (!$this->userManager->userExists($owner)) {
925
+            return new DataResponse([]);
926
+        }
927
+
928
+        // get node based on the owner, fix owner in case of external storage
929
+        $userFolder = $this->rootFolder->getUserFolder($owner);
930
+        if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
931
+            $owner = $node->getOwner()
932
+                            ->getUID();
933
+            $userFolder = $this->rootFolder->getUserFolder($owner);
934
+            $nodes = $userFolder->getById($node->getId());
935
+            $node = array_shift($nodes);
936
+        }
937
+        $basePath = $userFolder->getPath();
938
+
939
+        // generate node list for each parent folders
940
+        /** @var Node[] $nodes */
941
+        $nodes = [];
942
+        while ($node->getPath() !== $basePath) {
943
+            $node = $node->getParent();
944
+            $nodes[] = $node;
945
+        }
946
+
947
+        // The user that is requesting this list
948
+        $currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
949
+
950
+        // for each nodes, retrieve shares.
951
+        $shares = [];
952
+
953
+        foreach ($nodes as $node) {
954
+            $getShares = $this->getFormattedShares($owner, $node, false, true);
955
+
956
+            $currentUserNodes = $currentUserFolder->getById($node->getId());
957
+            if (!empty($currentUserNodes)) {
958
+                $parent = array_pop($currentUserNodes);
959
+            }
960
+
961
+            $subPath = $currentUserFolder->getRelativePath($parent->getPath());
962
+            foreach ($getShares as &$share) {
963
+                $share['via_fileid'] = $parent->getId();
964
+                $share['via_path'] = $subPath;
965
+            }
966
+            $this->mergeFormattedShares($shares, $getShares);
967
+        }
968
+
969
+        return new DataResponse(array_values($shares));
970
+    }
971
+
972
+
973
+    /**
974
+     * @NoAdminRequired
975
+     *
976
+     * @param string $id
977
+     * @param int $permissions
978
+     * @param string $password
979
+     * @param string $sendPasswordByTalk
980
+     * @param string $publicUpload
981
+     * @param string $expireDate
982
+     * @param string $note
983
+     * @param string $label
984
+     * @param string $hideDownload
985
+     * @return DataResponse
986
+     * @throws LockedException
987
+     * @throws NotFoundException
988
+     * @throws OCSBadRequestException
989
+     * @throws OCSForbiddenException
990
+     * @throws OCSNotFoundException
991
+     */
992
+    public function updateShare(
993
+        string $id,
994
+        int $permissions = null,
995
+        string $password = null,
996
+        string $sendPasswordByTalk = null,
997
+        string $publicUpload = null,
998
+        string $expireDate = null,
999
+        string $note = null,
1000
+        string $label = null,
1001
+        string $hideDownload = null
1002
+    ): DataResponse {
1003
+        try {
1004
+            $share = $this->getShareById($id);
1005
+        } catch (ShareNotFound $e) {
1006
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1007
+        }
1008
+
1009
+        $this->lock($share->getNode());
1010
+
1011
+        if (!$this->canAccessShare($share, false)) {
1012
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1013
+        }
1014
+
1015
+        if (!$this->canEditShare($share)) {
1016
+            throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1017
+        }
1018
+
1019
+        if (
1020
+            $permissions === null &&
1021
+            $password === null &&
1022
+            $sendPasswordByTalk === null &&
1023
+            $publicUpload === null &&
1024
+            $expireDate === null &&
1025
+            $note === null &&
1026
+            $label === null &&
1027
+            $hideDownload === null
1028
+        ) {
1029
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1030
+        }
1031
+
1032
+        if ($note !== null) {
1033
+            $share->setNote($note);
1034
+        }
1035
+
1036
+        /**
1037
+         * expirationdate, password and publicUpload only make sense for link shares
1038
+         */
1039
+        if ($share->getShareType() === IShare::TYPE_LINK
1040
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1041
+
1042
+            /**
1043
+             * We do not allow editing link shares that the current user
1044
+             * doesn't own. This is confusing and lead to errors when
1045
+             * someone else edit a password or expiration date without
1046
+             * the share owner knowing about it.
1047
+             * We only allow deletion
1048
+             */
1049
+
1050
+            if ($share->getSharedBy() !== $this->currentUser) {
1051
+                throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1052
+            }
1053
+
1054
+            // Update hide download state
1055
+            if ($hideDownload === 'true') {
1056
+                $share->setHideDownload(true);
1057
+            } elseif ($hideDownload === 'false') {
1058
+                $share->setHideDownload(false);
1059
+            }
1060
+
1061
+            $newPermissions = null;
1062
+            if ($publicUpload === 'true') {
1063
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1064
+            } elseif ($publicUpload === 'false') {
1065
+                $newPermissions = Constants::PERMISSION_READ;
1066
+            }
1067
+
1068
+            if ($permissions !== null) {
1069
+                $newPermissions = $permissions;
1070
+                $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1071
+            }
1072
+
1073
+            if ($newPermissions !== null &&
1074
+                !in_array($newPermissions, [
1075
+                    Constants::PERMISSION_READ,
1076
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1077
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1078
+                    Constants::PERMISSION_CREATE, // hidden file list
1079
+                    Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1080
+                ], true)
1081
+            ) {
1082
+                throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1083
+            }
1084
+
1085
+            if (
1086
+                // legacy
1087
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1088
+                // correct
1089
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1090
+            ) {
1091
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1092
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1093
+                }
1094
+
1095
+                if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1096
+                    throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1097
+                }
1098
+
1099
+                // normalize to correct public upload permissions
1100
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1101
+            }
1102
+
1103
+            if ($newPermissions !== null) {
1104
+                // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1105
+                if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1106
+                    $newPermissions |= Constants::PERMISSION_SHARE;
1107
+                }
1108
+
1109
+                $share->setPermissions($newPermissions);
1110
+                $permissions = $newPermissions;
1111
+            }
1112
+
1113
+            if ($expireDate === '') {
1114
+                $share->setExpirationDate(null);
1115
+            } elseif ($expireDate !== null) {
1116
+                try {
1117
+                    $expireDate = $this->parseDate($expireDate);
1118
+                } catch (\Exception $e) {
1119
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1120
+                }
1121
+                $share->setExpirationDate($expireDate);
1122
+            }
1123
+
1124
+            if ($password === '') {
1125
+                $share->setPassword(null);
1126
+            } elseif ($password !== null) {
1127
+                $share->setPassword($password);
1128
+            }
1129
+
1130
+            if ($label !== null) {
1131
+                if (strlen($label) > 255) {
1132
+                    throw new OCSBadRequestException("Maxmimum label length is 255");
1133
+                }
1134
+                $share->setLabel($label);
1135
+            }
1136
+
1137
+            if ($sendPasswordByTalk === 'true') {
1138
+                if (!$this->appManager->isEnabledForUser('spreed')) {
1139
+                    throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1140
+                }
1141
+
1142
+                $share->setSendPasswordByTalk(true);
1143
+            } elseif ($sendPasswordByTalk !== null) {
1144
+                $share->setSendPasswordByTalk(false);
1145
+            }
1146
+        }
1147
+
1148
+        // NOT A LINK SHARE
1149
+        else {
1150
+            if ($permissions !== null) {
1151
+                $share->setPermissions($permissions);
1152
+            }
1153
+
1154
+            if ($expireDate === '') {
1155
+                $share->setExpirationDate(null);
1156
+            } elseif ($expireDate !== null) {
1157
+                try {
1158
+                    $expireDate = $this->parseDate($expireDate);
1159
+                } catch (\Exception $e) {
1160
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1161
+                }
1162
+                $share->setExpirationDate($expireDate);
1163
+            }
1164
+        }
1165
+
1166
+        try {
1167
+            $share = $this->shareManager->updateShare($share);
1168
+        } catch (GenericShareException $e) {
1169
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1170
+            throw new OCSException($e->getHint(), $code);
1171
+        } catch (\Exception $e) {
1172
+            throw new OCSBadRequestException($e->getMessage(), $e);
1173
+        }
1174
+
1175
+        return new DataResponse($this->formatShare($share));
1176
+    }
1177
+
1178
+    /**
1179
+     * @NoAdminRequired
1180
+     */
1181
+    public function pendingShares(): DataResponse {
1182
+        $pendingShares = [];
1183
+
1184
+        $shareTypes = [
1185
+            IShare::TYPE_USER,
1186
+            IShare::TYPE_GROUP
1187
+        ];
1188
+
1189
+        foreach ($shareTypes as $shareType) {
1190
+            $shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1191
+
1192
+            foreach ($shares as $share) {
1193
+                if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1194
+                    $pendingShares[] = $share;
1195
+                }
1196
+            }
1197
+        }
1198
+
1199
+        $result = array_filter(array_map(function (IShare $share) {
1200
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1201
+            $nodes = $userFolder->getById($share->getNodeId());
1202
+            if (empty($nodes)) {
1203
+                // fallback to guessing the path
1204
+                $node = $userFolder->get($share->getTarget());
1205
+                if ($node === null || $share->getTarget() === '') {
1206
+                    return null;
1207
+                }
1208
+            } else {
1209
+                $node = $nodes[0];
1210
+            }
1211
+
1212
+            try {
1213
+                $formattedShare = $this->formatShare($share, $node);
1214
+                $formattedShare['status'] = $share->getStatus();
1215
+                $formattedShare['path'] = $share->getNode()->getName();
1216
+                $formattedShare['permissions'] = 0;
1217
+                return $formattedShare;
1218
+            } catch (NotFoundException $e) {
1219
+                return null;
1220
+            }
1221
+        }, $pendingShares), function ($entry) {
1222
+            return $entry !== null;
1223
+        });
1224
+
1225
+        return new DataResponse($result);
1226
+    }
1227
+
1228
+    /**
1229
+     * @NoAdminRequired
1230
+     *
1231
+     * @param string $id
1232
+     * @return DataResponse
1233
+     * @throws OCSNotFoundException
1234
+     * @throws OCSException
1235
+     * @throws OCSBadRequestException
1236
+     */
1237
+    public function acceptShare(string $id): DataResponse {
1238
+        try {
1239
+            $share = $this->getShareById($id);
1240
+        } catch (ShareNotFound $e) {
1241
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1242
+        }
1243
+
1244
+        if (!$this->canAccessShare($share)) {
1245
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1246
+        }
1247
+
1248
+        try {
1249
+            $this->shareManager->acceptShare($share, $this->currentUser);
1250
+        } catch (GenericShareException $e) {
1251
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1252
+            throw new OCSException($e->getHint(), $code);
1253
+        } catch (\Exception $e) {
1254
+            throw new OCSBadRequestException($e->getMessage(), $e);
1255
+        }
1256
+
1257
+        return new DataResponse();
1258
+    }
1259
+
1260
+    /**
1261
+     * Does the user have read permission on the share
1262
+     *
1263
+     * @param \OCP\Share\IShare $share the share to check
1264
+     * @param boolean $checkGroups check groups as well?
1265
+     * @return boolean
1266
+     * @throws NotFoundException
1267
+     *
1268
+     * @suppress PhanUndeclaredClassMethod
1269
+     */
1270
+    protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1271
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1272
+        if ($share->getPermissions() === 0) {
1273
+            return false;
1274
+        }
1275
+
1276
+        // Owner of the file and the sharer of the file can always get share
1277
+        if ($share->getShareOwner() === $this->currentUser
1278
+            || $share->getSharedBy() === $this->currentUser) {
1279
+            return true;
1280
+        }
1281
+
1282
+        // If the share is shared with you, you can access it!
1283
+        if ($share->getShareType() === IShare::TYPE_USER
1284
+            && $share->getSharedWith() === $this->currentUser) {
1285
+            return true;
1286
+        }
1287
+
1288
+        // Have reshare rights on the shared file/folder ?
1289
+        // Does the currentUser have access to the shared file?
1290
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1291
+        $files = $userFolder->getById($share->getNodeId());
1292
+        if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1293
+            return true;
1294
+        }
1295
+
1296
+        // If in the recipient group, you can see the share
1297
+        if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1298
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1299
+            $user = $this->userManager->get($this->currentUser);
1300
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1301
+                return true;
1302
+            }
1303
+        }
1304
+
1305
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1306
+            // TODO: have a sanity check like above?
1307
+            return true;
1308
+        }
1309
+
1310
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1311
+            try {
1312
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1313
+            } catch (QueryException $e) {
1314
+                return false;
1315
+            }
1316
+        }
1317
+
1318
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1319
+            try {
1320
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1321
+            } catch (QueryException $e) {
1322
+                return false;
1323
+            }
1324
+        }
1325
+
1326
+        return false;
1327
+    }
1328
+
1329
+    /**
1330
+     * Does the user have edit permission on the share
1331
+     *
1332
+     * @param \OCP\Share\IShare $share the share to check
1333
+     * @return boolean
1334
+     */
1335
+    protected function canEditShare(\OCP\Share\IShare $share): bool {
1336
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1337
+        if ($share->getPermissions() === 0) {
1338
+            return false;
1339
+        }
1340
+
1341
+        // The owner of the file and the creator of the share
1342
+        // can always edit the share
1343
+        if ($share->getShareOwner() === $this->currentUser ||
1344
+            $share->getSharedBy() === $this->currentUser
1345
+        ) {
1346
+            return true;
1347
+        }
1348
+
1349
+        //! we do NOT support some kind of `admin` in groups.
1350
+        //! You cannot edit shares shared to a group you're
1351
+        //! a member of if you're not the share owner or the file owner!
1352
+
1353
+        return false;
1354
+    }
1355
+
1356
+    /**
1357
+     * Does the user have delete permission on the share
1358
+     *
1359
+     * @param \OCP\Share\IShare $share the share to check
1360
+     * @return boolean
1361
+     */
1362
+    protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1363
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1364
+        if ($share->getPermissions() === 0) {
1365
+            return false;
1366
+        }
1367
+
1368
+        // if the user is the recipient, i can unshare
1369
+        // the share with self
1370
+        if ($share->getShareType() === IShare::TYPE_USER &&
1371
+            $share->getSharedWith() === $this->currentUser
1372
+        ) {
1373
+            return true;
1374
+        }
1375
+
1376
+        // The owner of the file and the creator of the share
1377
+        // can always delete the share
1378
+        if ($share->getShareOwner() === $this->currentUser ||
1379
+            $share->getSharedBy() === $this->currentUser
1380
+        ) {
1381
+            return true;
1382
+        }
1383
+
1384
+        return false;
1385
+    }
1386
+
1387
+    /**
1388
+     * Does the user have delete permission on the share
1389
+     * This differs from the canDeleteShare function as it only
1390
+     * remove the share for the current user. It does NOT
1391
+     * completely delete the share but only the mount point.
1392
+     * It can then be restored from the deleted shares section.
1393
+     *
1394
+     * @param \OCP\Share\IShare $share the share to check
1395
+     * @return boolean
1396
+     *
1397
+     * @suppress PhanUndeclaredClassMethod
1398
+     */
1399
+    protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1400
+        if ($share->getShareType() !== IShare::TYPE_GROUP &&
1401
+            $share->getShareType() !== IShare::TYPE_ROOM &&
1402
+            $share->getShareType() !== IShare::TYPE_DECK
1403
+        ) {
1404
+            return false;
1405
+        }
1406
+
1407
+        if ($share->getShareOwner() === $this->currentUser ||
1408
+            $share->getSharedBy() === $this->currentUser
1409
+        ) {
1410
+            // Delete the whole share, not just for self
1411
+            return false;
1412
+        }
1413
+
1414
+        // If in the recipient group, you can delete the share from self
1415
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1416
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1417
+            $user = $this->userManager->get($this->currentUser);
1418
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1419
+                return true;
1420
+            }
1421
+        }
1422
+
1423
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1424
+            try {
1425
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1426
+            } catch (QueryException $e) {
1427
+                return false;
1428
+            }
1429
+        }
1430
+
1431
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1432
+            try {
1433
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1434
+            } catch (QueryException $e) {
1435
+                return false;
1436
+            }
1437
+        }
1438
+
1439
+        return false;
1440
+    }
1441
+
1442
+    /**
1443
+     * Make sure that the passed date is valid ISO 8601
1444
+     * So YYYY-MM-DD
1445
+     * If not throw an exception
1446
+     *
1447
+     * @param string $expireDate
1448
+     *
1449
+     * @throws \Exception
1450
+     * @return \DateTime
1451
+     */
1452
+    private function parseDate(string $expireDate): \DateTime {
1453
+        try {
1454
+            $date = new \DateTime($expireDate);
1455
+        } catch (\Exception $e) {
1456
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1457
+        }
1458
+
1459
+        $date->setTime(0, 0, 0);
1460
+
1461
+        return $date;
1462
+    }
1463
+
1464
+    /**
1465
+     * Since we have multiple providers but the OCS Share API v1 does
1466
+     * not support this we need to check all backends.
1467
+     *
1468
+     * @param string $id
1469
+     * @return \OCP\Share\IShare
1470
+     * @throws ShareNotFound
1471
+     */
1472
+    private function getShareById(string $id): IShare {
1473
+        $share = null;
1474
+
1475
+        // First check if it is an internal share.
1476
+        try {
1477
+            $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1478
+            return $share;
1479
+        } catch (ShareNotFound $e) {
1480
+            // Do nothing, just try the other share type
1481
+        }
1482
+
1483
+
1484
+        try {
1485
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1486
+                $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1487
+                return $share;
1488
+            }
1489
+        } catch (ShareNotFound $e) {
1490
+            // Do nothing, just try the other share type
1491
+        }
1492
+
1493
+        try {
1494
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1495
+                $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1496
+                return $share;
1497
+            }
1498
+        } catch (ShareNotFound $e) {
1499
+            // Do nothing, just try the other share type
1500
+        }
1501
+
1502
+        try {
1503
+            $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1504
+            return $share;
1505
+        } catch (ShareNotFound $e) {
1506
+            // Do nothing, just try the other share type
1507
+        }
1508
+
1509
+        try {
1510
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1511
+                $share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1512
+                return $share;
1513
+            }
1514
+        } catch (ShareNotFound $e) {
1515
+            // Do nothing, just try the other share type
1516
+        }
1517
+
1518
+        if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1519
+            throw new ShareNotFound();
1520
+        }
1521
+        $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1522
+
1523
+        return $share;
1524
+    }
1525
+
1526
+    /**
1527
+     * Lock a Node
1528
+     *
1529
+     * @param \OCP\Files\Node $node
1530
+     * @throws LockedException
1531
+     */
1532
+    private function lock(\OCP\Files\Node $node) {
1533
+        $node->lock(ILockingProvider::LOCK_SHARED);
1534
+        $this->lockedNode = $node;
1535
+    }
1536
+
1537
+    /**
1538
+     * Cleanup the remaining locks
1539
+     * @throws LockedException
1540
+     */
1541
+    public function cleanup() {
1542
+        if ($this->lockedNode !== null) {
1543
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1544
+        }
1545
+    }
1546
+
1547
+    /**
1548
+     * Returns the helper of ShareAPIController for room shares.
1549
+     *
1550
+     * If the Talk application is not enabled or the helper is not available
1551
+     * a QueryException is thrown instead.
1552
+     *
1553
+     * @return \OCA\Talk\Share\Helper\ShareAPIController
1554
+     * @throws QueryException
1555
+     */
1556
+    private function getRoomShareHelper() {
1557
+        if (!$this->appManager->isEnabledForUser('spreed')) {
1558
+            throw new QueryException();
1559
+        }
1560
+
1561
+        return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1562
+    }
1563
+
1564
+    /**
1565
+     * Returns the helper of ShareAPIHelper for deck shares.
1566
+     *
1567
+     * If the Deck application is not enabled or the helper is not available
1568
+     * a QueryException is thrown instead.
1569
+     *
1570
+     * @return \OCA\Deck\Sharing\ShareAPIHelper
1571
+     * @throws QueryException
1572
+     */
1573
+    private function getDeckShareHelper() {
1574
+        if (!$this->appManager->isEnabledForUser('deck')) {
1575
+            throw new QueryException();
1576
+        }
1577
+
1578
+        return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1579
+    }
1580
+
1581
+    /**
1582
+     * @param string $viewer
1583
+     * @param Node $node
1584
+     * @param bool $reShares
1585
+     *
1586
+     * @return IShare[]
1587
+     */
1588
+    private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1589
+        $providers = [
1590
+            IShare::TYPE_USER,
1591
+            IShare::TYPE_GROUP,
1592
+            IShare::TYPE_LINK,
1593
+            IShare::TYPE_EMAIL,
1594
+            IShare::TYPE_CIRCLE,
1595
+            IShare::TYPE_ROOM,
1596
+            IShare::TYPE_DECK
1597
+        ];
1598
+
1599
+        // Should we assume that the (currentUser) viewer is the owner of the node !?
1600
+        $shares = [];
1601
+        foreach ($providers as $provider) {
1602
+            if (!$this->shareManager->shareProviderExists($provider)) {
1603
+                continue;
1604
+            }
1605
+
1606
+            $providerShares =
1607
+                $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1608
+            $shares = array_merge($shares, $providerShares);
1609
+        }
1610
+
1611
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1612
+            $federatedShares = $this->shareManager->getSharesBy(
1613
+                $this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1614
+            );
1615
+            $shares = array_merge($shares, $federatedShares);
1616
+        }
1617
+
1618
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1619
+            $federatedShares = $this->shareManager->getSharesBy(
1620
+                $this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1621
+            );
1622
+            $shares = array_merge($shares, $federatedShares);
1623
+        }
1624
+
1625
+        return $shares;
1626
+    }
1627
+
1628
+
1629
+    /**
1630
+     * @param Node $node
1631
+     *
1632
+     * @throws SharingRightsException
1633
+     */
1634
+    private function confirmSharingRights(Node $node): void {
1635
+        if (!$this->hasResharingRights($this->currentUser, $node)) {
1636
+            throw new SharingRightsException('no sharing rights on this item');
1637
+        }
1638
+    }
1639
+
1640
+
1641
+    /**
1642
+     * @param string $viewer
1643
+     * @param Node $node
1644
+     *
1645
+     * @return bool
1646
+     */
1647
+    private function hasResharingRights($viewer, $node): bool {
1648
+        if ($viewer === $node->getOwner()->getUID()) {
1649
+            return true;
1650
+        }
1651
+
1652
+        foreach ([$node, $node->getParent()] as $node) {
1653
+            $shares = $this->getSharesFromNode($viewer, $node, true);
1654
+            foreach ($shares as $share) {
1655
+                try {
1656
+                    if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1657
+                        return true;
1658
+                    }
1659
+                } catch (InvalidPathException | NotFoundException $e) {
1660
+                }
1661
+            }
1662
+        }
1663
+
1664
+        return false;
1665
+    }
1666
+
1667
+
1668
+    /**
1669
+     * Returns if we can find resharing rights in an IShare object for a specific user.
1670
+     *
1671
+     * @suppress PhanUndeclaredClassMethod
1672
+     *
1673
+     * @param string $userId
1674
+     * @param IShare $share
1675
+     * @param Node $node
1676
+     *
1677
+     * @return bool
1678
+     * @throws NotFoundException
1679
+     * @throws InvalidPathException
1680
+     */
1681
+    private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1682
+        if ($share->getShareOwner() === $userId) {
1683
+            return true;
1684
+        }
1685
+
1686
+        // we check that current user have parent resharing rights on the current file
1687
+        if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1688
+            return true;
1689
+        }
1690
+
1691
+        if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1692
+            return false;
1693
+        }
1694
+
1695
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1696
+            return true;
1697
+        }
1698
+
1699
+        if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1700
+            return true;
1701
+        }
1702
+
1703
+        if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1704
+            && class_exists('\OCA\Circles\Api\v1\Circles')) {
1705
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1706
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1707
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1708
+            if ($shareWithLength === false) {
1709
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart);
1710
+            } else {
1711
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1712
+            }
1713
+            try {
1714
+                $member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1715
+                if ($member->getLevel() >= 4) {
1716
+                    return true;
1717
+                }
1718
+                return false;
1719
+            } catch (QueryException $e) {
1720
+                return false;
1721
+            }
1722
+        }
1723
+
1724
+        return false;
1725
+    }
1726
+
1727
+    /**
1728
+     * Get all the shares for the current user
1729
+     *
1730
+     * @param Node|null $path
1731
+     * @param boolean $reshares
1732
+     * @return IShare[]
1733
+     */
1734
+    private function getAllShares(?Node $path = null, bool $reshares = false) {
1735
+        // Get all shares
1736
+        $userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1737
+        $groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1738
+        $linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1739
+
1740
+        // EMAIL SHARES
1741
+        $mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1742
+
1743
+        // CIRCLE SHARES
1744
+        $circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1745
+
1746
+        // TALK SHARES
1747
+        $roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1748
+
1749
+        $deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1750
+
1751
+        // FEDERATION
1752
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1753
+            $federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1754
+        } else {
1755
+            $federatedShares = [];
1756
+        }
1757
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1758
+            $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1759
+        } else {
1760
+            $federatedGroupShares = [];
1761
+        }
1762
+
1763
+        return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1764
+    }
1765
+
1766
+
1767
+    /**
1768
+     * merging already formatted shares.
1769
+     * We'll make an associative array to easily detect duplicate Ids.
1770
+     * Keys _needs_ to be removed after all shares are retrieved and merged.
1771
+     *
1772
+     * @param array $shares
1773
+     * @param array $newShares
1774
+     */
1775
+    private function mergeFormattedShares(array &$shares, array $newShares) {
1776
+        foreach ($newShares as $newShare) {
1777
+            if (!array_key_exists($newShare['id'], $shares)) {
1778
+                $shares[$newShare['id']] = $newShare;
1779
+            }
1780
+        }
1781
+    }
1782 1782
 }
Please login to merge, or discard this patch.
lib/public/Share/IShare.php 1 patch
Indentation   +533 added lines, -533 removed lines patch added patch discarded remove patch
@@ -43,537 +43,537 @@
 block discarded – undo
43 43
  */
44 44
 interface IShare {
45 45
 
46
-	/**
47
-	 * @since 17.0.0
48
-	 */
49
-	public const TYPE_USER = 0;
50
-
51
-	/**
52
-	 * @since 17.0.0
53
-	 */
54
-	public const TYPE_GROUP = 1;
55
-
56
-	/**
57
-	 * @internal
58
-	 * @since 18.0.0
59
-	 */
60
-	public const TYPE_USERGROUP = 2;
61
-
62
-	/**
63
-	 * @since 17.0.0
64
-	 */
65
-	public const TYPE_LINK = 3;
66
-
67
-	/**
68
-	 * @since 17.0.0
69
-	 */
70
-	public const TYPE_EMAIL = 4;
71
-
72
-	/**
73
-	 * ToDo Check if it is still in use otherwise remove it
74
-	 * @since 17.0.0
75
-	 */
76
-	// public const TYPE_CONTACT = 5;
77
-
78
-	/**
79
-	 * @since 17.0.0
80
-	 */
81
-	public const TYPE_REMOTE = 6;
82
-
83
-	/**
84
-	 * @since 17.0.0
85
-	 */
86
-	public const TYPE_CIRCLE = 7;
87
-
88
-	/**
89
-	 * @since 17.0.0
90
-	 */
91
-	public const TYPE_GUEST = 8;
92
-
93
-	/**
94
-	 * @since 17.0.0
95
-	 */
96
-	public const TYPE_REMOTE_GROUP = 9;
97
-
98
-	/**
99
-	 * @since 17.0.0
100
-	 */
101
-	public const TYPE_ROOM = 10;
102
-
103
-	/**
104
-	 * Internal type used by RoomShareProvider
105
-	 * @since 17.0.0
106
-	 */
107
-	// const TYPE_USERROOM = 11;
108
-
109
-	/**
110
-	 * @since 21.0.0
111
-	 */
112
-	public const TYPE_DECK = 12;
113
-
114
-	/**
115
-	 * @internal
116
-	 * @since 21.0.0
117
-	 */
118
-	public const TYPE_DECK_USER = 13;
119
-
120
-	/**
121
-	 * @since 18.0.0
122
-	 */
123
-	public const STATUS_PENDING = 0;
124
-
125
-	/**
126
-	 * @since 18.0.0
127
-	 */
128
-	public const STATUS_ACCEPTED = 1;
129
-
130
-	/**
131
-	 * @since 18.0.0
132
-	 */
133
-	public const STATUS_REJECTED = 2;
134
-
135
-	/**
136
-	 * Set the internal id of the share
137
-	 * It is only allowed to set the internal id of a share once.
138
-	 * Attempts to override the internal id will result in an IllegalIDChangeException
139
-	 *
140
-	 * @param string $id
141
-	 * @return \OCP\Share\IShare
142
-	 * @throws IllegalIDChangeException
143
-	 * @throws \InvalidArgumentException
144
-	 * @since 9.1.0
145
-	 */
146
-	public function setId($id);
147
-
148
-	/**
149
-	 * Get the internal id of the share.
150
-	 *
151
-	 * @return string
152
-	 * @since 9.0.0
153
-	 */
154
-	public function getId();
155
-
156
-	/**
157
-	 * Get the full share id. This is the <providerid>:<internalid>.
158
-	 * The full id is unique in the system.
159
-	 *
160
-	 * @return string
161
-	 * @since 9.0.0
162
-	 * @throws \UnexpectedValueException If the fullId could not be constructed
163
-	 */
164
-	public function getFullId();
165
-
166
-	/**
167
-	 * Set the provider id of the share
168
-	 * It is only allowed to set the provider id of a share once.
169
-	 * Attempts to override the provider id will result in an IllegalIDChangeException
170
-	 *
171
-	 * @param string $id
172
-	 * @return \OCP\Share\IShare
173
-	 * @throws IllegalIDChangeException
174
-	 * @throws \InvalidArgumentException
175
-	 * @since 9.1.0
176
-	 */
177
-	public function setProviderId($id);
178
-
179
-	/**
180
-	 * Set the node of the file/folder that is shared
181
-	 *
182
-	 * @param Node $node
183
-	 * @return \OCP\Share\IShare The modified object
184
-	 * @since 9.0.0
185
-	 */
186
-	public function setNode(Node $node);
187
-
188
-	/**
189
-	 * Get the node of the file/folder that is shared
190
-	 *
191
-	 * @return File|Folder
192
-	 * @since 9.0.0
193
-	 * @throws NotFoundException
194
-	 */
195
-	public function getNode();
196
-
197
-	/**
198
-	 * Set file id for lazy evaluation of the node
199
-	 * @param int $fileId
200
-	 * @return \OCP\Share\IShare The modified object
201
-	 * @since 9.0.0
202
-	 */
203
-	public function setNodeId($fileId);
204
-
205
-	/**
206
-	 * Get the fileid of the node of this share
207
-	 * @return int
208
-	 * @since 9.0.0
209
-	 * @throws NotFoundException
210
-	 */
211
-	public function getNodeId();
212
-
213
-	/**
214
-	 * Set the type of node (file/folder)
215
-	 *
216
-	 * @param string $type
217
-	 * @return \OCP\Share\IShare The modified object
218
-	 * @since 9.0.0
219
-	 */
220
-	public function setNodeType($type);
221
-
222
-	/**
223
-	 * Get the type of node (file/folder)
224
-	 *
225
-	 * @return string
226
-	 * @since 9.0.0
227
-	 * @throws NotFoundException
228
-	 */
229
-	public function getNodeType();
230
-
231
-	/**
232
-	 * Set the shareType
233
-	 *
234
-	 * @param int $shareType
235
-	 * @return \OCP\Share\IShare The modified object
236
-	 * @since 9.0.0
237
-	 */
238
-	public function setShareType($shareType);
239
-
240
-	/**
241
-	 * Get the shareType
242
-	 *
243
-	 * @return int
244
-	 * @since 9.0.0
245
-	 */
246
-	public function getShareType();
247
-
248
-	/**
249
-	 * Set the receiver of this share.
250
-	 *
251
-	 * @param string $sharedWith
252
-	 * @return \OCP\Share\IShare The modified object
253
-	 * @since 9.0.0
254
-	 */
255
-	public function setSharedWith($sharedWith);
256
-
257
-	/**
258
-	 * Get the receiver of this share.
259
-	 *
260
-	 * @return string
261
-	 * @since 9.0.0
262
-	 */
263
-	public function getSharedWith();
264
-
265
-	/**
266
-	 * Set the display name of the receiver of this share.
267
-	 *
268
-	 * @param string $displayName
269
-	 * @return \OCP\Share\IShare The modified object
270
-	 * @since 14.0.0
271
-	 */
272
-	public function setSharedWithDisplayName($displayName);
273
-
274
-	/**
275
-	 * Get the display name of the receiver of this share.
276
-	 *
277
-	 * @return string
278
-	 * @since 14.0.0
279
-	 */
280
-	public function getSharedWithDisplayName();
281
-
282
-	/**
283
-	 * Set the avatar of the receiver of this share.
284
-	 *
285
-	 * @param string $src
286
-	 * @return \OCP\Share\IShare The modified object
287
-	 * @since 14.0.0
288
-	 */
289
-	public function setSharedWithAvatar($src);
290
-
291
-	/**
292
-	 * Get the avatar of the receiver of this share.
293
-	 *
294
-	 * @return string
295
-	 * @since 14.0.0
296
-	 */
297
-	public function getSharedWithAvatar();
298
-
299
-	/**
300
-	 * Set the permissions.
301
-	 * See \OCP\Constants::PERMISSION_*
302
-	 *
303
-	 * @param int $permissions
304
-	 * @return \OCP\Share\IShare The modified object
305
-	 * @since 9.0.0
306
-	 */
307
-	public function setPermissions($permissions);
308
-
309
-	/**
310
-	 * Get the share permissions
311
-	 * See \OCP\Constants::PERMISSION_*
312
-	 *
313
-	 * @return int
314
-	 * @since 9.0.0
315
-	 */
316
-	public function getPermissions();
317
-
318
-	/**
319
-	 * Set the accepted status
320
-	 * See self::STATUS_*
321
-	 *
322
-	 * @param int $status
323
-	 * @return IShare The modified object
324
-	 * @since 18.0.0
325
-	 */
326
-	public function setStatus(int $status): IShare;
327
-
328
-	/**
329
-	 * Get the accepted status
330
-	 * See self::STATUS_*
331
-	 *
332
-	 * @return int
333
-	 * @since 18.0.0
334
-	 */
335
-	public function getStatus(): int;
336
-
337
-	/**
338
-	 * Attach a note to a share
339
-	 *
340
-	 * @param string $note
341
-	 * @return \OCP\Share\IShare The modified object
342
-	 * @since 14.0.0
343
-	 */
344
-	public function setNote($note);
345
-
346
-	/**
347
-	 * Get note attached to a share
348
-	 *
349
-	 * @return string
350
-	 * @since 14.0.0
351
-	 */
352
-	public function getNote();
353
-
354
-
355
-	/**
356
-	 * Set the expiration date
357
-	 *
358
-	 * @param null|\DateTime $expireDate
359
-	 * @return \OCP\Share\IShare The modified object
360
-	 * @since 9.0.0
361
-	 */
362
-	public function setExpirationDate($expireDate);
363
-
364
-	/**
365
-	 * Get the expiration date
366
-	 *
367
-	 * @return \DateTime
368
-	 * @since 9.0.0
369
-	 */
370
-	public function getExpirationDate();
371
-
372
-	/**
373
-	 * Is the share expired ?
374
-	 *
375
-	 * @return boolean
376
-	 * @since 18.0.0
377
-	 */
378
-	public function isExpired();
379
-
380
-	/**
381
-	 * set a label for a share, some shares, e.g. public links can have a label
382
-	 *
383
-	 * @param string $label
384
-	 * @return \OCP\Share\IShare The modified object
385
-	 * @since 15.0.0
386
-	 */
387
-	public function setLabel($label);
388
-
389
-	/**
390
-	 * get label for the share, some shares, e.g. public links can have a label
391
-	 *
392
-	 * @return string
393
-	 * @since 15.0.0
394
-	 */
395
-	public function getLabel();
396
-
397
-	/**
398
-	 * Set the sharer of the path.
399
-	 *
400
-	 * @param string $sharedBy
401
-	 * @return \OCP\Share\IShare The modified object
402
-	 * @since 9.0.0
403
-	 */
404
-	public function setSharedBy($sharedBy);
405
-
406
-	/**
407
-	 * Get share sharer
408
-	 *
409
-	 * @return string
410
-	 * @since 9.0.0
411
-	 */
412
-	public function getSharedBy();
413
-
414
-	/**
415
-	 * Set the original share owner (who owns the path that is shared)
416
-	 *
417
-	 * @param string $shareOwner
418
-	 * @return \OCP\Share\IShare The modified object
419
-	 * @since 9.0.0
420
-	 */
421
-	public function setShareOwner($shareOwner);
422
-
423
-	/**
424
-	 * Get the original share owner (who owns the path that is shared)
425
-	 *
426
-	 * @return string
427
-	 * @since 9.0.0
428
-	 */
429
-	public function getShareOwner();
430
-
431
-	/**
432
-	 * Set the password for this share.
433
-	 * When the share is passed to the share manager to be created
434
-	 * or updated the password will be hashed.
435
-	 *
436
-	 * @param string|null $password
437
-	 * @return \OCP\Share\IShare The modified object
438
-	 * @since 9.0.0
439
-	 */
440
-	public function setPassword($password);
441
-
442
-	/**
443
-	 * Get the password of this share.
444
-	 * If this share is obtained via a shareprovider the password is
445
-	 * hashed.
446
-	 *
447
-	 * @return string
448
-	 * @since 9.0.0
449
-	 */
450
-	public function getPassword();
451
-
452
-
453
-	/**
454
-	 * Set if the recipient can start a conversation with the owner to get the
455
-	 * password using Nextcloud Talk.
456
-	 *
457
-	 * @param bool $sendPasswordByTalk
458
-	 * @return \OCP\Share\IShare The modified object
459
-	 * @since 14.0.0
460
-	 */
461
-	public function setSendPasswordByTalk(bool $sendPasswordByTalk);
462
-
463
-	/**
464
-	 * Get if the recipient can start a conversation with the owner to get the
465
-	 * password using Nextcloud Talk.
466
-	 * The returned value does not take into account other factors, like Talk
467
-	 * being enabled for the owner of the share or not; it just cover whether
468
-	 * the option is enabled for the share itself or not.
469
-	 *
470
-	 * @return bool
471
-	 * @since 14.0.0
472
-	 */
473
-	public function getSendPasswordByTalk(): bool;
474
-
475
-	/**
476
-	 * Set the public link token.
477
-	 *
478
-	 * @param string $token
479
-	 * @return \OCP\Share\IShare The modified object
480
-	 * @since 9.0.0
481
-	 */
482
-	public function setToken($token);
483
-
484
-	/**
485
-	 * Get the public link token.
486
-	 *
487
-	 * @return string
488
-	 * @since 9.0.0
489
-	 */
490
-	public function getToken();
491
-
492
-	/**
493
-	 * Set the target path of this share relative to the recipients user folder.
494
-	 *
495
-	 * @param string $target
496
-	 * @return \OCP\Share\IShare The modified object
497
-	 * @since 9.0.0
498
-	 */
499
-	public function setTarget($target);
500
-
501
-	/**
502
-	 * Get the target path of this share relative to the recipients user folder.
503
-	 *
504
-	 * @return string
505
-	 * @since 9.0.0
506
-	 */
507
-	public function getTarget();
508
-
509
-	/**
510
-	 * Set the time this share was created
511
-	 *
512
-	 * @param \DateTime $shareTime
513
-	 * @return \OCP\Share\IShare The modified object
514
-	 * @since 9.0.0
515
-	 */
516
-	public function setShareTime(\DateTime $shareTime);
517
-
518
-	/**
519
-	 * Get the timestamp this share was created
520
-	 *
521
-	 * @return \DateTime
522
-	 * @since 9.0.0
523
-	 */
524
-	public function getShareTime();
525
-
526
-	/**
527
-	 * Set if the recipient is informed by mail about the share.
528
-	 *
529
-	 * @param bool $mailSend
530
-	 * @return \OCP\Share\IShare The modified object
531
-	 * @since 9.0.0
532
-	 */
533
-	public function setMailSend($mailSend);
534
-
535
-	/**
536
-	 * Get if the recipient informed by mail about the share.
537
-	 *
538
-	 * @return bool
539
-	 * @since 9.0.0
540
-	 */
541
-	public function getMailSend();
542
-
543
-	/**
544
-	 * Set the cache entry for the shared node
545
-	 *
546
-	 * @param ICacheEntry $entry
547
-	 * @since 11.0.0
548
-	 */
549
-	public function setNodeCacheEntry(ICacheEntry $entry);
550
-
551
-	/**
552
-	 * Get the cache entry for the shared node
553
-	 *
554
-	 * @return null|ICacheEntry
555
-	 * @since 11.0.0
556
-	 */
557
-	public function getNodeCacheEntry();
558
-
559
-	/**
560
-	 * Sets a shares hide download state
561
-	 * This is mainly for public shares. It will signal that the share page should
562
-	 * hide download buttons etc.
563
-	 *
564
-	 * @param bool $hide
565
-	 * @return IShare
566
-	 * @since 15.0.0
567
-	 */
568
-	public function setHideDownload(bool $hide): IShare;
569
-
570
-	/**
571
-	 * Gets a shares hide download state
572
-	 * This is mainly for public shares. It will signal that the share page should
573
-	 * hide download buttons etc.
574
-	 *
575
-	 * @return bool
576
-	 * @since 15.0.0
577
-	 */
578
-	public function getHideDownload(): bool;
46
+    /**
47
+     * @since 17.0.0
48
+     */
49
+    public const TYPE_USER = 0;
50
+
51
+    /**
52
+     * @since 17.0.0
53
+     */
54
+    public const TYPE_GROUP = 1;
55
+
56
+    /**
57
+     * @internal
58
+     * @since 18.0.0
59
+     */
60
+    public const TYPE_USERGROUP = 2;
61
+
62
+    /**
63
+     * @since 17.0.0
64
+     */
65
+    public const TYPE_LINK = 3;
66
+
67
+    /**
68
+     * @since 17.0.0
69
+     */
70
+    public const TYPE_EMAIL = 4;
71
+
72
+    /**
73
+     * ToDo Check if it is still in use otherwise remove it
74
+     * @since 17.0.0
75
+     */
76
+    // public const TYPE_CONTACT = 5;
77
+
78
+    /**
79
+     * @since 17.0.0
80
+     */
81
+    public const TYPE_REMOTE = 6;
82
+
83
+    /**
84
+     * @since 17.0.0
85
+     */
86
+    public const TYPE_CIRCLE = 7;
87
+
88
+    /**
89
+     * @since 17.0.0
90
+     */
91
+    public const TYPE_GUEST = 8;
92
+
93
+    /**
94
+     * @since 17.0.0
95
+     */
96
+    public const TYPE_REMOTE_GROUP = 9;
97
+
98
+    /**
99
+     * @since 17.0.0
100
+     */
101
+    public const TYPE_ROOM = 10;
102
+
103
+    /**
104
+     * Internal type used by RoomShareProvider
105
+     * @since 17.0.0
106
+     */
107
+    // const TYPE_USERROOM = 11;
108
+
109
+    /**
110
+     * @since 21.0.0
111
+     */
112
+    public const TYPE_DECK = 12;
113
+
114
+    /**
115
+     * @internal
116
+     * @since 21.0.0
117
+     */
118
+    public const TYPE_DECK_USER = 13;
119
+
120
+    /**
121
+     * @since 18.0.0
122
+     */
123
+    public const STATUS_PENDING = 0;
124
+
125
+    /**
126
+     * @since 18.0.0
127
+     */
128
+    public const STATUS_ACCEPTED = 1;
129
+
130
+    /**
131
+     * @since 18.0.0
132
+     */
133
+    public const STATUS_REJECTED = 2;
134
+
135
+    /**
136
+     * Set the internal id of the share
137
+     * It is only allowed to set the internal id of a share once.
138
+     * Attempts to override the internal id will result in an IllegalIDChangeException
139
+     *
140
+     * @param string $id
141
+     * @return \OCP\Share\IShare
142
+     * @throws IllegalIDChangeException
143
+     * @throws \InvalidArgumentException
144
+     * @since 9.1.0
145
+     */
146
+    public function setId($id);
147
+
148
+    /**
149
+     * Get the internal id of the share.
150
+     *
151
+     * @return string
152
+     * @since 9.0.0
153
+     */
154
+    public function getId();
155
+
156
+    /**
157
+     * Get the full share id. This is the <providerid>:<internalid>.
158
+     * The full id is unique in the system.
159
+     *
160
+     * @return string
161
+     * @since 9.0.0
162
+     * @throws \UnexpectedValueException If the fullId could not be constructed
163
+     */
164
+    public function getFullId();
165
+
166
+    /**
167
+     * Set the provider id of the share
168
+     * It is only allowed to set the provider id of a share once.
169
+     * Attempts to override the provider id will result in an IllegalIDChangeException
170
+     *
171
+     * @param string $id
172
+     * @return \OCP\Share\IShare
173
+     * @throws IllegalIDChangeException
174
+     * @throws \InvalidArgumentException
175
+     * @since 9.1.0
176
+     */
177
+    public function setProviderId($id);
178
+
179
+    /**
180
+     * Set the node of the file/folder that is shared
181
+     *
182
+     * @param Node $node
183
+     * @return \OCP\Share\IShare The modified object
184
+     * @since 9.0.0
185
+     */
186
+    public function setNode(Node $node);
187
+
188
+    /**
189
+     * Get the node of the file/folder that is shared
190
+     *
191
+     * @return File|Folder
192
+     * @since 9.0.0
193
+     * @throws NotFoundException
194
+     */
195
+    public function getNode();
196
+
197
+    /**
198
+     * Set file id for lazy evaluation of the node
199
+     * @param int $fileId
200
+     * @return \OCP\Share\IShare The modified object
201
+     * @since 9.0.0
202
+     */
203
+    public function setNodeId($fileId);
204
+
205
+    /**
206
+     * Get the fileid of the node of this share
207
+     * @return int
208
+     * @since 9.0.0
209
+     * @throws NotFoundException
210
+     */
211
+    public function getNodeId();
212
+
213
+    /**
214
+     * Set the type of node (file/folder)
215
+     *
216
+     * @param string $type
217
+     * @return \OCP\Share\IShare The modified object
218
+     * @since 9.0.0
219
+     */
220
+    public function setNodeType($type);
221
+
222
+    /**
223
+     * Get the type of node (file/folder)
224
+     *
225
+     * @return string
226
+     * @since 9.0.0
227
+     * @throws NotFoundException
228
+     */
229
+    public function getNodeType();
230
+
231
+    /**
232
+     * Set the shareType
233
+     *
234
+     * @param int $shareType
235
+     * @return \OCP\Share\IShare The modified object
236
+     * @since 9.0.0
237
+     */
238
+    public function setShareType($shareType);
239
+
240
+    /**
241
+     * Get the shareType
242
+     *
243
+     * @return int
244
+     * @since 9.0.0
245
+     */
246
+    public function getShareType();
247
+
248
+    /**
249
+     * Set the receiver of this share.
250
+     *
251
+     * @param string $sharedWith
252
+     * @return \OCP\Share\IShare The modified object
253
+     * @since 9.0.0
254
+     */
255
+    public function setSharedWith($sharedWith);
256
+
257
+    /**
258
+     * Get the receiver of this share.
259
+     *
260
+     * @return string
261
+     * @since 9.0.0
262
+     */
263
+    public function getSharedWith();
264
+
265
+    /**
266
+     * Set the display name of the receiver of this share.
267
+     *
268
+     * @param string $displayName
269
+     * @return \OCP\Share\IShare The modified object
270
+     * @since 14.0.0
271
+     */
272
+    public function setSharedWithDisplayName($displayName);
273
+
274
+    /**
275
+     * Get the display name of the receiver of this share.
276
+     *
277
+     * @return string
278
+     * @since 14.0.0
279
+     */
280
+    public function getSharedWithDisplayName();
281
+
282
+    /**
283
+     * Set the avatar of the receiver of this share.
284
+     *
285
+     * @param string $src
286
+     * @return \OCP\Share\IShare The modified object
287
+     * @since 14.0.0
288
+     */
289
+    public function setSharedWithAvatar($src);
290
+
291
+    /**
292
+     * Get the avatar of the receiver of this share.
293
+     *
294
+     * @return string
295
+     * @since 14.0.0
296
+     */
297
+    public function getSharedWithAvatar();
298
+
299
+    /**
300
+     * Set the permissions.
301
+     * See \OCP\Constants::PERMISSION_*
302
+     *
303
+     * @param int $permissions
304
+     * @return \OCP\Share\IShare The modified object
305
+     * @since 9.0.0
306
+     */
307
+    public function setPermissions($permissions);
308
+
309
+    /**
310
+     * Get the share permissions
311
+     * See \OCP\Constants::PERMISSION_*
312
+     *
313
+     * @return int
314
+     * @since 9.0.0
315
+     */
316
+    public function getPermissions();
317
+
318
+    /**
319
+     * Set the accepted status
320
+     * See self::STATUS_*
321
+     *
322
+     * @param int $status
323
+     * @return IShare The modified object
324
+     * @since 18.0.0
325
+     */
326
+    public function setStatus(int $status): IShare;
327
+
328
+    /**
329
+     * Get the accepted status
330
+     * See self::STATUS_*
331
+     *
332
+     * @return int
333
+     * @since 18.0.0
334
+     */
335
+    public function getStatus(): int;
336
+
337
+    /**
338
+     * Attach a note to a share
339
+     *
340
+     * @param string $note
341
+     * @return \OCP\Share\IShare The modified object
342
+     * @since 14.0.0
343
+     */
344
+    public function setNote($note);
345
+
346
+    /**
347
+     * Get note attached to a share
348
+     *
349
+     * @return string
350
+     * @since 14.0.0
351
+     */
352
+    public function getNote();
353
+
354
+
355
+    /**
356
+     * Set the expiration date
357
+     *
358
+     * @param null|\DateTime $expireDate
359
+     * @return \OCP\Share\IShare The modified object
360
+     * @since 9.0.0
361
+     */
362
+    public function setExpirationDate($expireDate);
363
+
364
+    /**
365
+     * Get the expiration date
366
+     *
367
+     * @return \DateTime
368
+     * @since 9.0.0
369
+     */
370
+    public function getExpirationDate();
371
+
372
+    /**
373
+     * Is the share expired ?
374
+     *
375
+     * @return boolean
376
+     * @since 18.0.0
377
+     */
378
+    public function isExpired();
379
+
380
+    /**
381
+     * set a label for a share, some shares, e.g. public links can have a label
382
+     *
383
+     * @param string $label
384
+     * @return \OCP\Share\IShare The modified object
385
+     * @since 15.0.0
386
+     */
387
+    public function setLabel($label);
388
+
389
+    /**
390
+     * get label for the share, some shares, e.g. public links can have a label
391
+     *
392
+     * @return string
393
+     * @since 15.0.0
394
+     */
395
+    public function getLabel();
396
+
397
+    /**
398
+     * Set the sharer of the path.
399
+     *
400
+     * @param string $sharedBy
401
+     * @return \OCP\Share\IShare The modified object
402
+     * @since 9.0.0
403
+     */
404
+    public function setSharedBy($sharedBy);
405
+
406
+    /**
407
+     * Get share sharer
408
+     *
409
+     * @return string
410
+     * @since 9.0.0
411
+     */
412
+    public function getSharedBy();
413
+
414
+    /**
415
+     * Set the original share owner (who owns the path that is shared)
416
+     *
417
+     * @param string $shareOwner
418
+     * @return \OCP\Share\IShare The modified object
419
+     * @since 9.0.0
420
+     */
421
+    public function setShareOwner($shareOwner);
422
+
423
+    /**
424
+     * Get the original share owner (who owns the path that is shared)
425
+     *
426
+     * @return string
427
+     * @since 9.0.0
428
+     */
429
+    public function getShareOwner();
430
+
431
+    /**
432
+     * Set the password for this share.
433
+     * When the share is passed to the share manager to be created
434
+     * or updated the password will be hashed.
435
+     *
436
+     * @param string|null $password
437
+     * @return \OCP\Share\IShare The modified object
438
+     * @since 9.0.0
439
+     */
440
+    public function setPassword($password);
441
+
442
+    /**
443
+     * Get the password of this share.
444
+     * If this share is obtained via a shareprovider the password is
445
+     * hashed.
446
+     *
447
+     * @return string
448
+     * @since 9.0.0
449
+     */
450
+    public function getPassword();
451
+
452
+
453
+    /**
454
+     * Set if the recipient can start a conversation with the owner to get the
455
+     * password using Nextcloud Talk.
456
+     *
457
+     * @param bool $sendPasswordByTalk
458
+     * @return \OCP\Share\IShare The modified object
459
+     * @since 14.0.0
460
+     */
461
+    public function setSendPasswordByTalk(bool $sendPasswordByTalk);
462
+
463
+    /**
464
+     * Get if the recipient can start a conversation with the owner to get the
465
+     * password using Nextcloud Talk.
466
+     * The returned value does not take into account other factors, like Talk
467
+     * being enabled for the owner of the share or not; it just cover whether
468
+     * the option is enabled for the share itself or not.
469
+     *
470
+     * @return bool
471
+     * @since 14.0.0
472
+     */
473
+    public function getSendPasswordByTalk(): bool;
474
+
475
+    /**
476
+     * Set the public link token.
477
+     *
478
+     * @param string $token
479
+     * @return \OCP\Share\IShare The modified object
480
+     * @since 9.0.0
481
+     */
482
+    public function setToken($token);
483
+
484
+    /**
485
+     * Get the public link token.
486
+     *
487
+     * @return string
488
+     * @since 9.0.0
489
+     */
490
+    public function getToken();
491
+
492
+    /**
493
+     * Set the target path of this share relative to the recipients user folder.
494
+     *
495
+     * @param string $target
496
+     * @return \OCP\Share\IShare The modified object
497
+     * @since 9.0.0
498
+     */
499
+    public function setTarget($target);
500
+
501
+    /**
502
+     * Get the target path of this share relative to the recipients user folder.
503
+     *
504
+     * @return string
505
+     * @since 9.0.0
506
+     */
507
+    public function getTarget();
508
+
509
+    /**
510
+     * Set the time this share was created
511
+     *
512
+     * @param \DateTime $shareTime
513
+     * @return \OCP\Share\IShare The modified object
514
+     * @since 9.0.0
515
+     */
516
+    public function setShareTime(\DateTime $shareTime);
517
+
518
+    /**
519
+     * Get the timestamp this share was created
520
+     *
521
+     * @return \DateTime
522
+     * @since 9.0.0
523
+     */
524
+    public function getShareTime();
525
+
526
+    /**
527
+     * Set if the recipient is informed by mail about the share.
528
+     *
529
+     * @param bool $mailSend
530
+     * @return \OCP\Share\IShare The modified object
531
+     * @since 9.0.0
532
+     */
533
+    public function setMailSend($mailSend);
534
+
535
+    /**
536
+     * Get if the recipient informed by mail about the share.
537
+     *
538
+     * @return bool
539
+     * @since 9.0.0
540
+     */
541
+    public function getMailSend();
542
+
543
+    /**
544
+     * Set the cache entry for the shared node
545
+     *
546
+     * @param ICacheEntry $entry
547
+     * @since 11.0.0
548
+     */
549
+    public function setNodeCacheEntry(ICacheEntry $entry);
550
+
551
+    /**
552
+     * Get the cache entry for the shared node
553
+     *
554
+     * @return null|ICacheEntry
555
+     * @since 11.0.0
556
+     */
557
+    public function getNodeCacheEntry();
558
+
559
+    /**
560
+     * Sets a shares hide download state
561
+     * This is mainly for public shares. It will signal that the share page should
562
+     * hide download buttons etc.
563
+     *
564
+     * @param bool $hide
565
+     * @return IShare
566
+     * @since 15.0.0
567
+     */
568
+    public function setHideDownload(bool $hide): IShare;
569
+
570
+    /**
571
+     * Gets a shares hide download state
572
+     * This is mainly for public shares. It will signal that the share page should
573
+     * hide download buttons etc.
574
+     *
575
+     * @return bool
576
+     * @since 15.0.0
577
+     */
578
+    public function getHideDownload(): bool;
579 579
 }
Please login to merge, or discard this patch.
lib/private/Share20/Manager.php 1 patch
Indentation   +1825 added lines, -1825 removed lines patch added patch discarded remove patch
@@ -78,1851 +78,1851 @@
 block discarded – undo
78 78
  */
79 79
 class Manager implements IManager {
80 80
 
81
-	/** @var IProviderFactory */
82
-	private $factory;
83
-	/** @var ILogger */
84
-	private $logger;
85
-	/** @var IConfig */
86
-	private $config;
87
-	/** @var ISecureRandom */
88
-	private $secureRandom;
89
-	/** @var IHasher */
90
-	private $hasher;
91
-	/** @var IMountManager */
92
-	private $mountManager;
93
-	/** @var IGroupManager */
94
-	private $groupManager;
95
-	/** @var IL10N */
96
-	private $l;
97
-	/** @var IFactory */
98
-	private $l10nFactory;
99
-	/** @var IUserManager */
100
-	private $userManager;
101
-	/** @var IRootFolder */
102
-	private $rootFolder;
103
-	/** @var CappedMemoryCache */
104
-	private $sharingDisabledForUsersCache;
105
-	/** @var EventDispatcherInterface */
106
-	private $legacyDispatcher;
107
-	/** @var LegacyHooks */
108
-	private $legacyHooks;
109
-	/** @var IMailer */
110
-	private $mailer;
111
-	/** @var IURLGenerator */
112
-	private $urlGenerator;
113
-	/** @var \OC_Defaults */
114
-	private $defaults;
115
-	/** @var IEventDispatcher */
116
-	private $dispatcher;
117
-
118
-
119
-	/**
120
-	 * Manager constructor.
121
-	 *
122
-	 * @param ILogger $logger
123
-	 * @param IConfig $config
124
-	 * @param ISecureRandom $secureRandom
125
-	 * @param IHasher $hasher
126
-	 * @param IMountManager $mountManager
127
-	 * @param IGroupManager $groupManager
128
-	 * @param IL10N $l
129
-	 * @param IFactory $l10nFactory
130
-	 * @param IProviderFactory $factory
131
-	 * @param IUserManager $userManager
132
-	 * @param IRootFolder $rootFolder
133
-	 * @param EventDispatcherInterface $eventDispatcher
134
-	 * @param IMailer $mailer
135
-	 * @param IURLGenerator $urlGenerator
136
-	 * @param \OC_Defaults $defaults
137
-	 */
138
-	public function __construct(
139
-			ILogger $logger,
140
-			IConfig $config,
141
-			ISecureRandom $secureRandom,
142
-			IHasher $hasher,
143
-			IMountManager $mountManager,
144
-			IGroupManager $groupManager,
145
-			IL10N $l,
146
-			IFactory $l10nFactory,
147
-			IProviderFactory $factory,
148
-			IUserManager $userManager,
149
-			IRootFolder $rootFolder,
150
-			EventDispatcherInterface $legacyDispatcher,
151
-			IMailer $mailer,
152
-			IURLGenerator $urlGenerator,
153
-			\OC_Defaults $defaults,
154
-			IEventDispatcher $dispatcher
155
-	) {
156
-		$this->logger = $logger;
157
-		$this->config = $config;
158
-		$this->secureRandom = $secureRandom;
159
-		$this->hasher = $hasher;
160
-		$this->mountManager = $mountManager;
161
-		$this->groupManager = $groupManager;
162
-		$this->l = $l;
163
-		$this->l10nFactory = $l10nFactory;
164
-		$this->factory = $factory;
165
-		$this->userManager = $userManager;
166
-		$this->rootFolder = $rootFolder;
167
-		$this->legacyDispatcher = $legacyDispatcher;
168
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
169
-		$this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
170
-		$this->mailer = $mailer;
171
-		$this->urlGenerator = $urlGenerator;
172
-		$this->defaults = $defaults;
173
-		$this->dispatcher = $dispatcher;
174
-	}
175
-
176
-	/**
177
-	 * Convert from a full share id to a tuple (providerId, shareId)
178
-	 *
179
-	 * @param string $id
180
-	 * @return string[]
181
-	 */
182
-	private function splitFullId($id) {
183
-		return explode(':', $id, 2);
184
-	}
185
-
186
-	/**
187
-	 * Verify if a password meets all requirements
188
-	 *
189
-	 * @param string $password
190
-	 * @throws \Exception
191
-	 */
192
-	protected function verifyPassword($password) {
193
-		if ($password === null) {
194
-			// No password is set, check if this is allowed.
195
-			if ($this->shareApiLinkEnforcePassword()) {
196
-				throw new \InvalidArgumentException('Passwords are enforced for link and mail shares');
197
-			}
198
-
199
-			return;
200
-		}
201
-
202
-		// Let others verify the password
203
-		try {
204
-			$this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
205
-		} catch (HintException $e) {
206
-			throw new \Exception($e->getHint());
207
-		}
208
-	}
209
-
210
-	/**
211
-	 * Check for generic requirements before creating a share
212
-	 *
213
-	 * @param IShare $share
214
-	 * @throws \InvalidArgumentException
215
-	 * @throws GenericShareException
216
-	 *
217
-	 * @suppress PhanUndeclaredClassMethod
218
-	 */
219
-	protected function generalCreateChecks(IShare $share) {
220
-		if ($share->getShareType() === IShare::TYPE_USER) {
221
-			// We expect a valid user as sharedWith for user shares
222
-			if (!$this->userManager->userExists($share->getSharedWith())) {
223
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
224
-			}
225
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
226
-			// We expect a valid group as sharedWith for group shares
227
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
228
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
229
-			}
230
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
231
-			// No check for TYPE_EMAIL here as we have a recipient for them
232
-			if ($share->getSharedWith() !== null) {
233
-				throw new \InvalidArgumentException('SharedWith should be empty');
234
-			}
235
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
236
-			if ($share->getSharedWith() === null) {
237
-				throw new \InvalidArgumentException('SharedWith should not be empty');
238
-			}
239
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
240
-			if ($share->getSharedWith() === null) {
241
-				throw new \InvalidArgumentException('SharedWith should not be empty');
242
-			}
243
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
244
-			if ($share->getSharedWith() === null) {
245
-				throw new \InvalidArgumentException('SharedWith should not be empty');
246
-			}
247
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
248
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
249
-			if ($circle === null) {
250
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
251
-			}
252
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
253
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
254
-		} else {
255
-			// We can't handle other types yet
256
-			throw new \InvalidArgumentException('unknown share type');
257
-		}
258
-
259
-		// Verify the initiator of the share is set
260
-		if ($share->getSharedBy() === null) {
261
-			throw new \InvalidArgumentException('SharedBy should be set');
262
-		}
263
-
264
-		// Cannot share with yourself
265
-		if ($share->getShareType() === IShare::TYPE_USER &&
266
-			$share->getSharedWith() === $share->getSharedBy()) {
267
-			throw new \InvalidArgumentException('Can’t share with yourself');
268
-		}
269
-
270
-		// The path should be set
271
-		if ($share->getNode() === null) {
272
-			throw new \InvalidArgumentException('Path should be set');
273
-		}
274
-
275
-		// And it should be a file or a folder
276
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
277
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
278
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
279
-		}
280
-
281
-		// And you can't share your rootfolder
282
-		if ($this->userManager->userExists($share->getSharedBy())) {
283
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
284
-		} else {
285
-			$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
286
-		}
287
-		if ($userFolder->getId() === $share->getNode()->getId()) {
288
-			throw new \InvalidArgumentException('You can’t share your root folder');
289
-		}
290
-
291
-		// Check if we actually have share permissions
292
-		if (!$share->getNode()->isShareable()) {
293
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
294
-			throw new GenericShareException($message_t, $message_t, 404);
295
-		}
296
-
297
-		// Permissions should be set
298
-		if ($share->getPermissions() === null) {
299
-			throw new \InvalidArgumentException('A share requires permissions');
300
-		}
301
-
302
-		$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
303
-		$permissions = 0;
304
-
305
-		if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
-			$userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
307
-				// We need to filter since there might be other mountpoints that contain the file
308
-				// e.g. if the user has access to the same external storage that the file is originating from
309
-				return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
310
-			});
311
-			$userMount = array_shift($userMounts);
312
-			if ($userMount === null) {
313
-				throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
314
-			}
315
-			$mount = $userMount->getMountPoint();
316
-			// When it's a reshare use the parent share permissions as maximum
317
-			$userMountPointId = $mount->getStorageRootId();
318
-			$userMountPoints = $userFolder->getById($userMountPointId);
319
-			$userMountPoint = array_shift($userMountPoints);
320
-
321
-			if ($userMountPoint === null) {
322
-				throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
323
-			}
324
-
325
-			/* Check if this is an incoming share */
326
-			$incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
327
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
328
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
329
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
330
-
331
-			/** @var IShare[] $incomingShares */
332
-			if (!empty($incomingShares)) {
333
-				foreach ($incomingShares as $incomingShare) {
334
-					$permissions |= $incomingShare->getPermissions();
335
-				}
336
-			}
337
-		} else {
338
-			/*
81
+    /** @var IProviderFactory */
82
+    private $factory;
83
+    /** @var ILogger */
84
+    private $logger;
85
+    /** @var IConfig */
86
+    private $config;
87
+    /** @var ISecureRandom */
88
+    private $secureRandom;
89
+    /** @var IHasher */
90
+    private $hasher;
91
+    /** @var IMountManager */
92
+    private $mountManager;
93
+    /** @var IGroupManager */
94
+    private $groupManager;
95
+    /** @var IL10N */
96
+    private $l;
97
+    /** @var IFactory */
98
+    private $l10nFactory;
99
+    /** @var IUserManager */
100
+    private $userManager;
101
+    /** @var IRootFolder */
102
+    private $rootFolder;
103
+    /** @var CappedMemoryCache */
104
+    private $sharingDisabledForUsersCache;
105
+    /** @var EventDispatcherInterface */
106
+    private $legacyDispatcher;
107
+    /** @var LegacyHooks */
108
+    private $legacyHooks;
109
+    /** @var IMailer */
110
+    private $mailer;
111
+    /** @var IURLGenerator */
112
+    private $urlGenerator;
113
+    /** @var \OC_Defaults */
114
+    private $defaults;
115
+    /** @var IEventDispatcher */
116
+    private $dispatcher;
117
+
118
+
119
+    /**
120
+     * Manager constructor.
121
+     *
122
+     * @param ILogger $logger
123
+     * @param IConfig $config
124
+     * @param ISecureRandom $secureRandom
125
+     * @param IHasher $hasher
126
+     * @param IMountManager $mountManager
127
+     * @param IGroupManager $groupManager
128
+     * @param IL10N $l
129
+     * @param IFactory $l10nFactory
130
+     * @param IProviderFactory $factory
131
+     * @param IUserManager $userManager
132
+     * @param IRootFolder $rootFolder
133
+     * @param EventDispatcherInterface $eventDispatcher
134
+     * @param IMailer $mailer
135
+     * @param IURLGenerator $urlGenerator
136
+     * @param \OC_Defaults $defaults
137
+     */
138
+    public function __construct(
139
+            ILogger $logger,
140
+            IConfig $config,
141
+            ISecureRandom $secureRandom,
142
+            IHasher $hasher,
143
+            IMountManager $mountManager,
144
+            IGroupManager $groupManager,
145
+            IL10N $l,
146
+            IFactory $l10nFactory,
147
+            IProviderFactory $factory,
148
+            IUserManager $userManager,
149
+            IRootFolder $rootFolder,
150
+            EventDispatcherInterface $legacyDispatcher,
151
+            IMailer $mailer,
152
+            IURLGenerator $urlGenerator,
153
+            \OC_Defaults $defaults,
154
+            IEventDispatcher $dispatcher
155
+    ) {
156
+        $this->logger = $logger;
157
+        $this->config = $config;
158
+        $this->secureRandom = $secureRandom;
159
+        $this->hasher = $hasher;
160
+        $this->mountManager = $mountManager;
161
+        $this->groupManager = $groupManager;
162
+        $this->l = $l;
163
+        $this->l10nFactory = $l10nFactory;
164
+        $this->factory = $factory;
165
+        $this->userManager = $userManager;
166
+        $this->rootFolder = $rootFolder;
167
+        $this->legacyDispatcher = $legacyDispatcher;
168
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
169
+        $this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
170
+        $this->mailer = $mailer;
171
+        $this->urlGenerator = $urlGenerator;
172
+        $this->defaults = $defaults;
173
+        $this->dispatcher = $dispatcher;
174
+    }
175
+
176
+    /**
177
+     * Convert from a full share id to a tuple (providerId, shareId)
178
+     *
179
+     * @param string $id
180
+     * @return string[]
181
+     */
182
+    private function splitFullId($id) {
183
+        return explode(':', $id, 2);
184
+    }
185
+
186
+    /**
187
+     * Verify if a password meets all requirements
188
+     *
189
+     * @param string $password
190
+     * @throws \Exception
191
+     */
192
+    protected function verifyPassword($password) {
193
+        if ($password === null) {
194
+            // No password is set, check if this is allowed.
195
+            if ($this->shareApiLinkEnforcePassword()) {
196
+                throw new \InvalidArgumentException('Passwords are enforced for link and mail shares');
197
+            }
198
+
199
+            return;
200
+        }
201
+
202
+        // Let others verify the password
203
+        try {
204
+            $this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
205
+        } catch (HintException $e) {
206
+            throw new \Exception($e->getHint());
207
+        }
208
+    }
209
+
210
+    /**
211
+     * Check for generic requirements before creating a share
212
+     *
213
+     * @param IShare $share
214
+     * @throws \InvalidArgumentException
215
+     * @throws GenericShareException
216
+     *
217
+     * @suppress PhanUndeclaredClassMethod
218
+     */
219
+    protected function generalCreateChecks(IShare $share) {
220
+        if ($share->getShareType() === IShare::TYPE_USER) {
221
+            // We expect a valid user as sharedWith for user shares
222
+            if (!$this->userManager->userExists($share->getSharedWith())) {
223
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
224
+            }
225
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
226
+            // We expect a valid group as sharedWith for group shares
227
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
228
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
229
+            }
230
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
231
+            // No check for TYPE_EMAIL here as we have a recipient for them
232
+            if ($share->getSharedWith() !== null) {
233
+                throw new \InvalidArgumentException('SharedWith should be empty');
234
+            }
235
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
236
+            if ($share->getSharedWith() === null) {
237
+                throw new \InvalidArgumentException('SharedWith should not be empty');
238
+            }
239
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
240
+            if ($share->getSharedWith() === null) {
241
+                throw new \InvalidArgumentException('SharedWith should not be empty');
242
+            }
243
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
244
+            if ($share->getSharedWith() === null) {
245
+                throw new \InvalidArgumentException('SharedWith should not be empty');
246
+            }
247
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
248
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
249
+            if ($circle === null) {
250
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
251
+            }
252
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
253
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
254
+        } else {
255
+            // We can't handle other types yet
256
+            throw new \InvalidArgumentException('unknown share type');
257
+        }
258
+
259
+        // Verify the initiator of the share is set
260
+        if ($share->getSharedBy() === null) {
261
+            throw new \InvalidArgumentException('SharedBy should be set');
262
+        }
263
+
264
+        // Cannot share with yourself
265
+        if ($share->getShareType() === IShare::TYPE_USER &&
266
+            $share->getSharedWith() === $share->getSharedBy()) {
267
+            throw new \InvalidArgumentException('Can’t share with yourself');
268
+        }
269
+
270
+        // The path should be set
271
+        if ($share->getNode() === null) {
272
+            throw new \InvalidArgumentException('Path should be set');
273
+        }
274
+
275
+        // And it should be a file or a folder
276
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
277
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
278
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
279
+        }
280
+
281
+        // And you can't share your rootfolder
282
+        if ($this->userManager->userExists($share->getSharedBy())) {
283
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
284
+        } else {
285
+            $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
286
+        }
287
+        if ($userFolder->getId() === $share->getNode()->getId()) {
288
+            throw new \InvalidArgumentException('You can’t share your root folder');
289
+        }
290
+
291
+        // Check if we actually have share permissions
292
+        if (!$share->getNode()->isShareable()) {
293
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
294
+            throw new GenericShareException($message_t, $message_t, 404);
295
+        }
296
+
297
+        // Permissions should be set
298
+        if ($share->getPermissions() === null) {
299
+            throw new \InvalidArgumentException('A share requires permissions');
300
+        }
301
+
302
+        $isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
303
+        $permissions = 0;
304
+
305
+        if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
+            $userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
307
+                // We need to filter since there might be other mountpoints that contain the file
308
+                // e.g. if the user has access to the same external storage that the file is originating from
309
+                return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
310
+            });
311
+            $userMount = array_shift($userMounts);
312
+            if ($userMount === null) {
313
+                throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
314
+            }
315
+            $mount = $userMount->getMountPoint();
316
+            // When it's a reshare use the parent share permissions as maximum
317
+            $userMountPointId = $mount->getStorageRootId();
318
+            $userMountPoints = $userFolder->getById($userMountPointId);
319
+            $userMountPoint = array_shift($userMountPoints);
320
+
321
+            if ($userMountPoint === null) {
322
+                throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
323
+            }
324
+
325
+            /* Check if this is an incoming share */
326
+            $incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
327
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
328
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
329
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
330
+
331
+            /** @var IShare[] $incomingShares */
332
+            if (!empty($incomingShares)) {
333
+                foreach ($incomingShares as $incomingShare) {
334
+                    $permissions |= $incomingShare->getPermissions();
335
+                }
336
+            }
337
+        } else {
338
+            /*
339 339
 			 * Quick fix for #23536
340 340
 			 * Non moveable mount points do not have update and delete permissions
341 341
 			 * while we 'most likely' do have that on the storage.
342 342
 			 */
343
-			$permissions = $share->getNode()->getPermissions();
344
-			if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
345
-				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
346
-			}
347
-		}
348
-
349
-		// Check that we do not share with more permissions than we have
350
-		if ($share->getPermissions() & ~$permissions) {
351
-			$path = $userFolder->getRelativePath($share->getNode()->getPath());
352
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
353
-			throw new GenericShareException($message_t, $message_t, 404);
354
-		}
355
-
356
-
357
-		// Check that read permissions are always set
358
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
359
-		$noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
360
-			|| $share->getShareType() === IShare::TYPE_EMAIL;
361
-		if (!$noReadPermissionRequired &&
362
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
363
-			throw new \InvalidArgumentException('Shares need at least read permissions');
364
-		}
365
-
366
-		if ($share->getNode() instanceof \OCP\Files\File) {
367
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
368
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
369
-				throw new GenericShareException($message_t);
370
-			}
371
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
372
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
373
-				throw new GenericShareException($message_t);
374
-			}
375
-		}
376
-	}
377
-
378
-	/**
379
-	 * Validate if the expiration date fits the system settings
380
-	 *
381
-	 * @param IShare $share The share to validate the expiration date of
382
-	 * @return IShare The modified share object
383
-	 * @throws GenericShareException
384
-	 * @throws \InvalidArgumentException
385
-	 * @throws \Exception
386
-	 */
387
-	protected function validateExpirationDateInternal(IShare $share) {
388
-		$expirationDate = $share->getExpirationDate();
389
-
390
-		if ($expirationDate !== null) {
391
-			//Make sure the expiration date is a date
392
-			$expirationDate->setTime(0, 0, 0);
393
-
394
-			$date = new \DateTime();
395
-			$date->setTime(0, 0, 0);
396
-			if ($date >= $expirationDate) {
397
-				$message = $this->l->t('Expiration date is in the past');
398
-				throw new GenericShareException($message, $message, 404);
399
-			}
400
-		}
401
-
402
-		// If expiredate is empty set a default one if there is a default
403
-		$fullId = null;
404
-		try {
405
-			$fullId = $share->getFullId();
406
-		} catch (\UnexpectedValueException $e) {
407
-			// This is a new share
408
-		}
409
-
410
-		if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
411
-			$expirationDate = new \DateTime();
412
-			$expirationDate->setTime(0,0,0);
413
-
414
-			$days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', (string)$this->shareApiInternalDefaultExpireDays());
415
-			if ($days > $this->shareApiInternalDefaultExpireDays()) {
416
-				$days = $this->shareApiInternalDefaultExpireDays();
417
-			}
418
-			$expirationDate->add(new \DateInterval('P'.$days.'D'));
419
-		}
420
-
421
-		// If we enforce the expiration date check that is does not exceed
422
-		if ($this->shareApiInternalDefaultExpireDateEnforced()) {
423
-			if ($expirationDate === null) {
424
-				throw new \InvalidArgumentException('Expiration date is enforced');
425
-			}
426
-
427
-			$date = new \DateTime();
428
-			$date->setTime(0, 0, 0);
429
-			$date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
430
-			if ($date < $expirationDate) {
431
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
432
-				throw new GenericShareException($message, $message, 404);
433
-			}
434
-		}
435
-
436
-		$accepted = true;
437
-		$message = '';
438
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
439
-			'expirationDate' => &$expirationDate,
440
-			'accepted' => &$accepted,
441
-			'message' => &$message,
442
-			'passwordSet' => $share->getPassword() !== null,
443
-		]);
444
-
445
-		if (!$accepted) {
446
-			throw new \Exception($message);
447
-		}
448
-
449
-		$share->setExpirationDate($expirationDate);
450
-
451
-		return $share;
452
-	}
453
-
454
-	/**
455
-	 * Validate if the expiration date fits the system settings
456
-	 *
457
-	 * @param IShare $share The share to validate the expiration date of
458
-	 * @return IShare The modified share object
459
-	 * @throws GenericShareException
460
-	 * @throws \InvalidArgumentException
461
-	 * @throws \Exception
462
-	 */
463
-	protected function validateExpirationDateLink(IShare $share) {
464
-		$expirationDate = $share->getExpirationDate();
465
-
466
-		if ($expirationDate !== null) {
467
-			//Make sure the expiration date is a date
468
-			$expirationDate->setTime(0, 0, 0);
469
-
470
-			$date = new \DateTime();
471
-			$date->setTime(0, 0, 0);
472
-			if ($date >= $expirationDate) {
473
-				$message = $this->l->t('Expiration date is in the past');
474
-				throw new GenericShareException($message, $message, 404);
475
-			}
476
-		}
477
-
478
-		// If expiredate is empty set a default one if there is a default
479
-		$fullId = null;
480
-		try {
481
-			$fullId = $share->getFullId();
482
-		} catch (\UnexpectedValueException $e) {
483
-			// This is a new share
484
-		}
485
-
486
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
487
-			$expirationDate = new \DateTime();
488
-			$expirationDate->setTime(0,0,0);
489
-
490
-			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
491
-			if ($days > $this->shareApiLinkDefaultExpireDays()) {
492
-				$days = $this->shareApiLinkDefaultExpireDays();
493
-			}
494
-			$expirationDate->add(new \DateInterval('P'.$days.'D'));
495
-		}
496
-
497
-		// If we enforce the expiration date check that is does not exceed
498
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
499
-			if ($expirationDate === null) {
500
-				throw new \InvalidArgumentException('Expiration date is enforced');
501
-			}
502
-
503
-			$date = new \DateTime();
504
-			$date->setTime(0, 0, 0);
505
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
506
-			if ($date < $expirationDate) {
507
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
508
-				throw new GenericShareException($message, $message, 404);
509
-			}
510
-		}
511
-
512
-		$accepted = true;
513
-		$message = '';
514
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
515
-			'expirationDate' => &$expirationDate,
516
-			'accepted' => &$accepted,
517
-			'message' => &$message,
518
-			'passwordSet' => $share->getPassword() !== null,
519
-		]);
520
-
521
-		if (!$accepted) {
522
-			throw new \Exception($message);
523
-		}
524
-
525
-		$share->setExpirationDate($expirationDate);
526
-
527
-		return $share;
528
-	}
529
-
530
-	/**
531
-	 * Check for pre share requirements for user shares
532
-	 *
533
-	 * @param IShare $share
534
-	 * @throws \Exception
535
-	 */
536
-	protected function userCreateChecks(IShare $share) {
537
-		// Check if we can share with group members only
538
-		if ($this->shareWithGroupMembersOnly()) {
539
-			$sharedBy = $this->userManager->get($share->getSharedBy());
540
-			$sharedWith = $this->userManager->get($share->getSharedWith());
541
-			// Verify we can share with this user
542
-			$groups = array_intersect(
543
-					$this->groupManager->getUserGroupIds($sharedBy),
544
-					$this->groupManager->getUserGroupIds($sharedWith)
545
-			);
546
-			if (empty($groups)) {
547
-				$message_t = $this->l->t('Sharing is only allowed with group members');
548
-				throw new \Exception($message_t);
549
-			}
550
-		}
551
-
552
-		/*
343
+            $permissions = $share->getNode()->getPermissions();
344
+            if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
345
+                $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
346
+            }
347
+        }
348
+
349
+        // Check that we do not share with more permissions than we have
350
+        if ($share->getPermissions() & ~$permissions) {
351
+            $path = $userFolder->getRelativePath($share->getNode()->getPath());
352
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
353
+            throw new GenericShareException($message_t, $message_t, 404);
354
+        }
355
+
356
+
357
+        // Check that read permissions are always set
358
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
359
+        $noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
360
+            || $share->getShareType() === IShare::TYPE_EMAIL;
361
+        if (!$noReadPermissionRequired &&
362
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
363
+            throw new \InvalidArgumentException('Shares need at least read permissions');
364
+        }
365
+
366
+        if ($share->getNode() instanceof \OCP\Files\File) {
367
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
368
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
369
+                throw new GenericShareException($message_t);
370
+            }
371
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
372
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
373
+                throw new GenericShareException($message_t);
374
+            }
375
+        }
376
+    }
377
+
378
+    /**
379
+     * Validate if the expiration date fits the system settings
380
+     *
381
+     * @param IShare $share The share to validate the expiration date of
382
+     * @return IShare The modified share object
383
+     * @throws GenericShareException
384
+     * @throws \InvalidArgumentException
385
+     * @throws \Exception
386
+     */
387
+    protected function validateExpirationDateInternal(IShare $share) {
388
+        $expirationDate = $share->getExpirationDate();
389
+
390
+        if ($expirationDate !== null) {
391
+            //Make sure the expiration date is a date
392
+            $expirationDate->setTime(0, 0, 0);
393
+
394
+            $date = new \DateTime();
395
+            $date->setTime(0, 0, 0);
396
+            if ($date >= $expirationDate) {
397
+                $message = $this->l->t('Expiration date is in the past');
398
+                throw new GenericShareException($message, $message, 404);
399
+            }
400
+        }
401
+
402
+        // If expiredate is empty set a default one if there is a default
403
+        $fullId = null;
404
+        try {
405
+            $fullId = $share->getFullId();
406
+        } catch (\UnexpectedValueException $e) {
407
+            // This is a new share
408
+        }
409
+
410
+        if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
411
+            $expirationDate = new \DateTime();
412
+            $expirationDate->setTime(0,0,0);
413
+
414
+            $days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', (string)$this->shareApiInternalDefaultExpireDays());
415
+            if ($days > $this->shareApiInternalDefaultExpireDays()) {
416
+                $days = $this->shareApiInternalDefaultExpireDays();
417
+            }
418
+            $expirationDate->add(new \DateInterval('P'.$days.'D'));
419
+        }
420
+
421
+        // If we enforce the expiration date check that is does not exceed
422
+        if ($this->shareApiInternalDefaultExpireDateEnforced()) {
423
+            if ($expirationDate === null) {
424
+                throw new \InvalidArgumentException('Expiration date is enforced');
425
+            }
426
+
427
+            $date = new \DateTime();
428
+            $date->setTime(0, 0, 0);
429
+            $date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
430
+            if ($date < $expirationDate) {
431
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
432
+                throw new GenericShareException($message, $message, 404);
433
+            }
434
+        }
435
+
436
+        $accepted = true;
437
+        $message = '';
438
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
439
+            'expirationDate' => &$expirationDate,
440
+            'accepted' => &$accepted,
441
+            'message' => &$message,
442
+            'passwordSet' => $share->getPassword() !== null,
443
+        ]);
444
+
445
+        if (!$accepted) {
446
+            throw new \Exception($message);
447
+        }
448
+
449
+        $share->setExpirationDate($expirationDate);
450
+
451
+        return $share;
452
+    }
453
+
454
+    /**
455
+     * Validate if the expiration date fits the system settings
456
+     *
457
+     * @param IShare $share The share to validate the expiration date of
458
+     * @return IShare The modified share object
459
+     * @throws GenericShareException
460
+     * @throws \InvalidArgumentException
461
+     * @throws \Exception
462
+     */
463
+    protected function validateExpirationDateLink(IShare $share) {
464
+        $expirationDate = $share->getExpirationDate();
465
+
466
+        if ($expirationDate !== null) {
467
+            //Make sure the expiration date is a date
468
+            $expirationDate->setTime(0, 0, 0);
469
+
470
+            $date = new \DateTime();
471
+            $date->setTime(0, 0, 0);
472
+            if ($date >= $expirationDate) {
473
+                $message = $this->l->t('Expiration date is in the past');
474
+                throw new GenericShareException($message, $message, 404);
475
+            }
476
+        }
477
+
478
+        // If expiredate is empty set a default one if there is a default
479
+        $fullId = null;
480
+        try {
481
+            $fullId = $share->getFullId();
482
+        } catch (\UnexpectedValueException $e) {
483
+            // This is a new share
484
+        }
485
+
486
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
487
+            $expirationDate = new \DateTime();
488
+            $expirationDate->setTime(0,0,0);
489
+
490
+            $days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
491
+            if ($days > $this->shareApiLinkDefaultExpireDays()) {
492
+                $days = $this->shareApiLinkDefaultExpireDays();
493
+            }
494
+            $expirationDate->add(new \DateInterval('P'.$days.'D'));
495
+        }
496
+
497
+        // If we enforce the expiration date check that is does not exceed
498
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
499
+            if ($expirationDate === null) {
500
+                throw new \InvalidArgumentException('Expiration date is enforced');
501
+            }
502
+
503
+            $date = new \DateTime();
504
+            $date->setTime(0, 0, 0);
505
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
506
+            if ($date < $expirationDate) {
507
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
508
+                throw new GenericShareException($message, $message, 404);
509
+            }
510
+        }
511
+
512
+        $accepted = true;
513
+        $message = '';
514
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
515
+            'expirationDate' => &$expirationDate,
516
+            'accepted' => &$accepted,
517
+            'message' => &$message,
518
+            'passwordSet' => $share->getPassword() !== null,
519
+        ]);
520
+
521
+        if (!$accepted) {
522
+            throw new \Exception($message);
523
+        }
524
+
525
+        $share->setExpirationDate($expirationDate);
526
+
527
+        return $share;
528
+    }
529
+
530
+    /**
531
+     * Check for pre share requirements for user shares
532
+     *
533
+     * @param IShare $share
534
+     * @throws \Exception
535
+     */
536
+    protected function userCreateChecks(IShare $share) {
537
+        // Check if we can share with group members only
538
+        if ($this->shareWithGroupMembersOnly()) {
539
+            $sharedBy = $this->userManager->get($share->getSharedBy());
540
+            $sharedWith = $this->userManager->get($share->getSharedWith());
541
+            // Verify we can share with this user
542
+            $groups = array_intersect(
543
+                    $this->groupManager->getUserGroupIds($sharedBy),
544
+                    $this->groupManager->getUserGroupIds($sharedWith)
545
+            );
546
+            if (empty($groups)) {
547
+                $message_t = $this->l->t('Sharing is only allowed with group members');
548
+                throw new \Exception($message_t);
549
+            }
550
+        }
551
+
552
+        /*
553 553
 		 * TODO: Could be costly, fix
554 554
 		 *
555 555
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
556 556
 		 */
557
-		$provider = $this->factory->getProviderForType(IShare::TYPE_USER);
558
-		$existingShares = $provider->getSharesByPath($share->getNode());
559
-		foreach ($existingShares as $existingShare) {
560
-			// Ignore if it is the same share
561
-			try {
562
-				if ($existingShare->getFullId() === $share->getFullId()) {
563
-					continue;
564
-				}
565
-			} catch (\UnexpectedValueException $e) {
566
-				//Shares are not identical
567
-			}
568
-
569
-			// Identical share already exists
570
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
571
-				$message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
572
-				throw new AlreadySharedException($message, $existingShare);
573
-			}
574
-
575
-			// The share is already shared with this user via a group share
576
-			if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
577
-				$group = $this->groupManager->get($existingShare->getSharedWith());
578
-				if (!is_null($group)) {
579
-					$user = $this->userManager->get($share->getSharedWith());
580
-
581
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
582
-						$message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
583
-						throw new AlreadySharedException($message, $existingShare);
584
-					}
585
-				}
586
-			}
587
-		}
588
-	}
589
-
590
-	/**
591
-	 * Check for pre share requirements for group shares
592
-	 *
593
-	 * @param IShare $share
594
-	 * @throws \Exception
595
-	 */
596
-	protected function groupCreateChecks(IShare $share) {
597
-		// Verify group shares are allowed
598
-		if (!$this->allowGroupSharing()) {
599
-			throw new \Exception('Group sharing is now allowed');
600
-		}
601
-
602
-		// Verify if the user can share with this group
603
-		if ($this->shareWithGroupMembersOnly()) {
604
-			$sharedBy = $this->userManager->get($share->getSharedBy());
605
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
606
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
607
-				throw new \Exception('Sharing is only allowed within your own groups');
608
-			}
609
-		}
610
-
611
-		/*
557
+        $provider = $this->factory->getProviderForType(IShare::TYPE_USER);
558
+        $existingShares = $provider->getSharesByPath($share->getNode());
559
+        foreach ($existingShares as $existingShare) {
560
+            // Ignore if it is the same share
561
+            try {
562
+                if ($existingShare->getFullId() === $share->getFullId()) {
563
+                    continue;
564
+                }
565
+            } catch (\UnexpectedValueException $e) {
566
+                //Shares are not identical
567
+            }
568
+
569
+            // Identical share already exists
570
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
571
+                $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
572
+                throw new AlreadySharedException($message, $existingShare);
573
+            }
574
+
575
+            // The share is already shared with this user via a group share
576
+            if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
577
+                $group = $this->groupManager->get($existingShare->getSharedWith());
578
+                if (!is_null($group)) {
579
+                    $user = $this->userManager->get($share->getSharedWith());
580
+
581
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
582
+                        $message = $this->l->t('Sharing %s failed, because this item is already shared with user %s', [$share->getNode()->getName(), $share->getSharedWithDisplayName()]);
583
+                        throw new AlreadySharedException($message, $existingShare);
584
+                    }
585
+                }
586
+            }
587
+        }
588
+    }
589
+
590
+    /**
591
+     * Check for pre share requirements for group shares
592
+     *
593
+     * @param IShare $share
594
+     * @throws \Exception
595
+     */
596
+    protected function groupCreateChecks(IShare $share) {
597
+        // Verify group shares are allowed
598
+        if (!$this->allowGroupSharing()) {
599
+            throw new \Exception('Group sharing is now allowed');
600
+        }
601
+
602
+        // Verify if the user can share with this group
603
+        if ($this->shareWithGroupMembersOnly()) {
604
+            $sharedBy = $this->userManager->get($share->getSharedBy());
605
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
606
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
607
+                throw new \Exception('Sharing is only allowed within your own groups');
608
+            }
609
+        }
610
+
611
+        /*
612 612
 		 * TODO: Could be costly, fix
613 613
 		 *
614 614
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
615 615
 		 */
616
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
617
-		$existingShares = $provider->getSharesByPath($share->getNode());
618
-		foreach ($existingShares as $existingShare) {
619
-			try {
620
-				if ($existingShare->getFullId() === $share->getFullId()) {
621
-					continue;
622
-				}
623
-			} catch (\UnexpectedValueException $e) {
624
-				//It is a new share so just continue
625
-			}
626
-
627
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
628
-				throw new AlreadySharedException('Path is already shared with this group', $existingShare);
629
-			}
630
-		}
631
-	}
632
-
633
-	/**
634
-	 * Check for pre share requirements for link shares
635
-	 *
636
-	 * @param IShare $share
637
-	 * @throws \Exception
638
-	 */
639
-	protected function linkCreateChecks(IShare $share) {
640
-		// Are link shares allowed?
641
-		if (!$this->shareApiAllowLinks()) {
642
-			throw new \Exception('Link sharing is not allowed');
643
-		}
644
-
645
-		// Check if public upload is allowed
646
-		if (!$this->shareApiLinkAllowPublicUpload() &&
647
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
648
-			throw new \InvalidArgumentException('Public upload is not allowed');
649
-		}
650
-	}
651
-
652
-	/**
653
-	 * To make sure we don't get invisible link shares we set the parent
654
-	 * of a link if it is a reshare. This is a quick word around
655
-	 * until we can properly display multiple link shares in the UI
656
-	 *
657
-	 * See: https://github.com/owncloud/core/issues/22295
658
-	 *
659
-	 * FIXME: Remove once multiple link shares can be properly displayed
660
-	 *
661
-	 * @param IShare $share
662
-	 */
663
-	protected function setLinkParent(IShare $share) {
664
-
665
-		// No sense in checking if the method is not there.
666
-		if (method_exists($share, 'setParent')) {
667
-			$storage = $share->getNode()->getStorage();
668
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
669
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
670
-				$share->setParent($storage->getShareId());
671
-			}
672
-		}
673
-	}
674
-
675
-	/**
676
-	 * @param File|Folder $path
677
-	 */
678
-	protected function pathCreateChecks($path) {
679
-		// Make sure that we do not share a path that contains a shared mountpoint
680
-		if ($path instanceof \OCP\Files\Folder) {
681
-			$mounts = $this->mountManager->findIn($path->getPath());
682
-			foreach ($mounts as $mount) {
683
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
684
-					throw new \InvalidArgumentException('Path contains files shared with you');
685
-				}
686
-			}
687
-		}
688
-	}
689
-
690
-	/**
691
-	 * Check if the user that is sharing can actually share
692
-	 *
693
-	 * @param IShare $share
694
-	 * @throws \Exception
695
-	 */
696
-	protected function canShare(IShare $share) {
697
-		if (!$this->shareApiEnabled()) {
698
-			throw new \Exception('Sharing is disabled');
699
-		}
700
-
701
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
702
-			throw new \Exception('Sharing is disabled for you');
703
-		}
704
-	}
705
-
706
-	/**
707
-	 * Share a path
708
-	 *
709
-	 * @param IShare $share
710
-	 * @return IShare The share object
711
-	 * @throws \Exception
712
-	 *
713
-	 * TODO: handle link share permissions or check them
714
-	 */
715
-	public function createShare(IShare $share) {
716
-		$this->canShare($share);
717
-
718
-		$this->generalCreateChecks($share);
719
-
720
-		// Verify if there are any issues with the path
721
-		$this->pathCreateChecks($share->getNode());
722
-
723
-		/*
616
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
617
+        $existingShares = $provider->getSharesByPath($share->getNode());
618
+        foreach ($existingShares as $existingShare) {
619
+            try {
620
+                if ($existingShare->getFullId() === $share->getFullId()) {
621
+                    continue;
622
+                }
623
+            } catch (\UnexpectedValueException $e) {
624
+                //It is a new share so just continue
625
+            }
626
+
627
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
628
+                throw new AlreadySharedException('Path is already shared with this group', $existingShare);
629
+            }
630
+        }
631
+    }
632
+
633
+    /**
634
+     * Check for pre share requirements for link shares
635
+     *
636
+     * @param IShare $share
637
+     * @throws \Exception
638
+     */
639
+    protected function linkCreateChecks(IShare $share) {
640
+        // Are link shares allowed?
641
+        if (!$this->shareApiAllowLinks()) {
642
+            throw new \Exception('Link sharing is not allowed');
643
+        }
644
+
645
+        // Check if public upload is allowed
646
+        if (!$this->shareApiLinkAllowPublicUpload() &&
647
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
648
+            throw new \InvalidArgumentException('Public upload is not allowed');
649
+        }
650
+    }
651
+
652
+    /**
653
+     * To make sure we don't get invisible link shares we set the parent
654
+     * of a link if it is a reshare. This is a quick word around
655
+     * until we can properly display multiple link shares in the UI
656
+     *
657
+     * See: https://github.com/owncloud/core/issues/22295
658
+     *
659
+     * FIXME: Remove once multiple link shares can be properly displayed
660
+     *
661
+     * @param IShare $share
662
+     */
663
+    protected function setLinkParent(IShare $share) {
664
+
665
+        // No sense in checking if the method is not there.
666
+        if (method_exists($share, 'setParent')) {
667
+            $storage = $share->getNode()->getStorage();
668
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
669
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
670
+                $share->setParent($storage->getShareId());
671
+            }
672
+        }
673
+    }
674
+
675
+    /**
676
+     * @param File|Folder $path
677
+     */
678
+    protected function pathCreateChecks($path) {
679
+        // Make sure that we do not share a path that contains a shared mountpoint
680
+        if ($path instanceof \OCP\Files\Folder) {
681
+            $mounts = $this->mountManager->findIn($path->getPath());
682
+            foreach ($mounts as $mount) {
683
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
684
+                    throw new \InvalidArgumentException('Path contains files shared with you');
685
+                }
686
+            }
687
+        }
688
+    }
689
+
690
+    /**
691
+     * Check if the user that is sharing can actually share
692
+     *
693
+     * @param IShare $share
694
+     * @throws \Exception
695
+     */
696
+    protected function canShare(IShare $share) {
697
+        if (!$this->shareApiEnabled()) {
698
+            throw new \Exception('Sharing is disabled');
699
+        }
700
+
701
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
702
+            throw new \Exception('Sharing is disabled for you');
703
+        }
704
+    }
705
+
706
+    /**
707
+     * Share a path
708
+     *
709
+     * @param IShare $share
710
+     * @return IShare The share object
711
+     * @throws \Exception
712
+     *
713
+     * TODO: handle link share permissions or check them
714
+     */
715
+    public function createShare(IShare $share) {
716
+        $this->canShare($share);
717
+
718
+        $this->generalCreateChecks($share);
719
+
720
+        // Verify if there are any issues with the path
721
+        $this->pathCreateChecks($share->getNode());
722
+
723
+        /*
724 724
 		 * On creation of a share the owner is always the owner of the path
725 725
 		 * Except for mounted federated shares.
726 726
 		 */
727
-		$storage = $share->getNode()->getStorage();
728
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
729
-			$parent = $share->getNode()->getParent();
730
-			while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
731
-				$parent = $parent->getParent();
732
-			}
733
-			$share->setShareOwner($parent->getOwner()->getUID());
734
-		} else {
735
-			if ($share->getNode()->getOwner()) {
736
-				$share->setShareOwner($share->getNode()->getOwner()->getUID());
737
-			} else {
738
-				$share->setShareOwner($share->getSharedBy());
739
-			}
740
-		}
741
-
742
-		try {
743
-			// Verify share type
744
-			if ($share->getShareType() === IShare::TYPE_USER) {
745
-				$this->userCreateChecks($share);
746
-
747
-				// Verify the expiration date
748
-				$share = $this->validateExpirationDateInternal($share);
749
-			} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
750
-				$this->groupCreateChecks($share);
751
-
752
-				// Verify the expiration date
753
-				$share = $this->validateExpirationDateInternal($share);
754
-			} elseif ($share->getShareType() === IShare::TYPE_LINK
755
-				|| $share->getShareType() === IShare::TYPE_EMAIL) {
756
-				$this->linkCreateChecks($share);
757
-				$this->setLinkParent($share);
758
-
759
-				// For now ignore a set token.
760
-				$share->setToken(
761
-					$this->secureRandom->generate(
762
-						\OC\Share\Constants::TOKEN_LENGTH,
763
-						\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
764
-					)
765
-				);
766
-
767
-				// Verify the expiration date
768
-				$share = $this->validateExpirationDateLink($share);
769
-
770
-				// Verify the password
771
-				$this->verifyPassword($share->getPassword());
772
-
773
-				// If a password is set. Hash it!
774
-				if ($share->getShareType() === IShare::TYPE_LINK
775
-					&& $share->getPassword() !== null) {
776
-					$share->setPassword($this->hasher->hash($share->getPassword()));
777
-				}
778
-			}
779
-
780
-			// Cannot share with the owner
781
-			if ($share->getShareType() === IShare::TYPE_USER &&
782
-				$share->getSharedWith() === $share->getShareOwner()) {
783
-				throw new \InvalidArgumentException('Can’t share with the share owner');
784
-			}
785
-
786
-			// Generate the target
787
-			$target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
788
-			$target = \OC\Files\Filesystem::normalizePath($target);
789
-			$share->setTarget($target);
790
-
791
-			// Pre share event
792
-			$event = new GenericEvent($share);
793
-			$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
794
-			if ($event->isPropagationStopped() && $event->hasArgument('error')) {
795
-				throw new \Exception($event->getArgument('error'));
796
-			}
797
-
798
-			$oldShare = $share;
799
-			$provider = $this->factory->getProviderForType($share->getShareType());
800
-			$share = $provider->create($share);
801
-
802
-			// Reuse the node we already have
803
-			$share->setNode($oldShare->getNode());
804
-
805
-			// Reset the target if it is null for the new share
806
-			if ($share->getTarget() === '') {
807
-				$share->setTarget($target);
808
-			}
809
-		} catch (AlreadySharedException $e) {
810
-			// if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
811
-			$share = $e->getExistingShare();
812
-		}
813
-
814
-		// Post share event
815
-		$event = new GenericEvent($share);
816
-		$this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
817
-
818
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
819
-
820
-		if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
821
-			&& $share->getShareType() === IShare::TYPE_USER) {
822
-			$mailSend = $share->getMailSend();
823
-			if ($mailSend === true) {
824
-				$user = $this->userManager->get($share->getSharedWith());
825
-				if ($user !== null) {
826
-					$emailAddress = $user->getEMailAddress();
827
-					if ($emailAddress !== null && $emailAddress !== '') {
828
-						$userLang = $this->l10nFactory->getUserLanguage($user);
829
-						$l = $this->l10nFactory->get('lib', $userLang);
830
-						$this->sendMailNotification(
831
-							$l,
832
-							$share->getNode()->getName(),
833
-							$this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
834
-							$share->getSharedBy(),
835
-							$emailAddress,
836
-							$share->getExpirationDate()
837
-						);
838
-						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
839
-					} else {
840
-						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
841
-					}
842
-				} else {
843
-					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
844
-				}
845
-			} else {
846
-				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
847
-			}
848
-		}
849
-
850
-		return $share;
851
-	}
852
-
853
-	/**
854
-	 * Send mail notifications
855
-	 *
856
-	 * This method will catch and log mail transmission errors
857
-	 *
858
-	 * @param IL10N $l Language of the recipient
859
-	 * @param string $filename file/folder name
860
-	 * @param string $link link to the file/folder
861
-	 * @param string $initiator user ID of share sender
862
-	 * @param string $shareWith email address of share receiver
863
-	 * @param \DateTime|null $expiration
864
-	 */
865
-	protected function sendMailNotification(IL10N $l,
866
-											$filename,
867
-											$link,
868
-											$initiator,
869
-											$shareWith,
870
-											\DateTime $expiration = null) {
871
-		$initiatorUser = $this->userManager->get($initiator);
872
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
873
-
874
-		$message = $this->mailer->createMessage();
875
-
876
-		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
877
-			'filename' => $filename,
878
-			'link' => $link,
879
-			'initiator' => $initiatorDisplayName,
880
-			'expiration' => $expiration,
881
-			'shareWith' => $shareWith,
882
-		]);
883
-
884
-		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
885
-		$emailTemplate->addHeader();
886
-		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
887
-		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
888
-
889
-		$emailTemplate->addBodyText(
890
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
891
-			$text
892
-		);
893
-		$emailTemplate->addBodyButton(
894
-			$l->t('Open »%s«', [$filename]),
895
-			$link
896
-		);
897
-
898
-		$message->setTo([$shareWith]);
899
-
900
-		// The "From" contains the sharers name
901
-		$instanceName = $this->defaults->getName();
902
-		$senderName = $l->t(
903
-			'%1$s via %2$s',
904
-			[
905
-				$initiatorDisplayName,
906
-				$instanceName
907
-			]
908
-		);
909
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
910
-
911
-		// The "Reply-To" is set to the sharer if an mail address is configured
912
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
913
-		$initiatorEmail = $initiatorUser->getEMailAddress();
914
-		if ($initiatorEmail !== null) {
915
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
916
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
917
-		} else {
918
-			$emailTemplate->addFooter('', $l->getLanguageCode());
919
-		}
920
-
921
-		$message->useTemplate($emailTemplate);
922
-		try {
923
-			$failedRecipients = $this->mailer->send($message);
924
-			if (!empty($failedRecipients)) {
925
-				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
926
-				return;
927
-			}
928
-		} catch (\Exception $e) {
929
-			$this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
930
-		}
931
-	}
932
-
933
-	/**
934
-	 * Update a share
935
-	 *
936
-	 * @param IShare $share
937
-	 * @return IShare The share object
938
-	 * @throws \InvalidArgumentException
939
-	 */
940
-	public function updateShare(IShare $share) {
941
-		$expirationDateUpdated = false;
942
-
943
-		$this->canShare($share);
944
-
945
-		try {
946
-			$originalShare = $this->getShareById($share->getFullId());
947
-		} catch (\UnexpectedValueException $e) {
948
-			throw new \InvalidArgumentException('Share does not have a full id');
949
-		}
950
-
951
-		// We can't change the share type!
952
-		if ($share->getShareType() !== $originalShare->getShareType()) {
953
-			throw new \InvalidArgumentException('Can’t change share type');
954
-		}
955
-
956
-		// We can only change the recipient on user shares
957
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
958
-			$share->getShareType() !== IShare::TYPE_USER) {
959
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
960
-		}
961
-
962
-		// Cannot share with the owner
963
-		if ($share->getShareType() === IShare::TYPE_USER &&
964
-			$share->getSharedWith() === $share->getShareOwner()) {
965
-			throw new \InvalidArgumentException('Can’t share with the share owner');
966
-		}
967
-
968
-		$this->generalCreateChecks($share);
969
-
970
-		if ($share->getShareType() === IShare::TYPE_USER) {
971
-			$this->userCreateChecks($share);
972
-
973
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
974
-				//Verify the expiration date
975
-				$this->validateExpirationDateInternal($share);
976
-				$expirationDateUpdated = true;
977
-			}
978
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
979
-			$this->groupCreateChecks($share);
980
-
981
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
982
-				//Verify the expiration date
983
-				$this->validateExpirationDateInternal($share);
984
-				$expirationDateUpdated = true;
985
-			}
986
-		} elseif ($share->getShareType() === IShare::TYPE_LINK
987
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
988
-			$this->linkCreateChecks($share);
989
-
990
-			// The new password is not set again if it is the same as the old
991
-			// one, unless when switching from sending by Talk to sending by
992
-			// mail.
993
-			$plainTextPassword = $share->getPassword();
994
-			$updatedPassword = $this->updateSharePasswordIfNeeded($share, $originalShare);
995
-
996
-			/**
997
-			 * Cannot enable the getSendPasswordByTalk if there is no password set
998
-			 */
999
-			if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
1000
-				throw new \InvalidArgumentException('Can’t enable sending the password by Talk with an empty password');
1001
-			}
727
+        $storage = $share->getNode()->getStorage();
728
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
729
+            $parent = $share->getNode()->getParent();
730
+            while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
731
+                $parent = $parent->getParent();
732
+            }
733
+            $share->setShareOwner($parent->getOwner()->getUID());
734
+        } else {
735
+            if ($share->getNode()->getOwner()) {
736
+                $share->setShareOwner($share->getNode()->getOwner()->getUID());
737
+            } else {
738
+                $share->setShareOwner($share->getSharedBy());
739
+            }
740
+        }
741
+
742
+        try {
743
+            // Verify share type
744
+            if ($share->getShareType() === IShare::TYPE_USER) {
745
+                $this->userCreateChecks($share);
746
+
747
+                // Verify the expiration date
748
+                $share = $this->validateExpirationDateInternal($share);
749
+            } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
750
+                $this->groupCreateChecks($share);
751
+
752
+                // Verify the expiration date
753
+                $share = $this->validateExpirationDateInternal($share);
754
+            } elseif ($share->getShareType() === IShare::TYPE_LINK
755
+                || $share->getShareType() === IShare::TYPE_EMAIL) {
756
+                $this->linkCreateChecks($share);
757
+                $this->setLinkParent($share);
758
+
759
+                // For now ignore a set token.
760
+                $share->setToken(
761
+                    $this->secureRandom->generate(
762
+                        \OC\Share\Constants::TOKEN_LENGTH,
763
+                        \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
764
+                    )
765
+                );
766
+
767
+                // Verify the expiration date
768
+                $share = $this->validateExpirationDateLink($share);
769
+
770
+                // Verify the password
771
+                $this->verifyPassword($share->getPassword());
772
+
773
+                // If a password is set. Hash it!
774
+                if ($share->getShareType() === IShare::TYPE_LINK
775
+                    && $share->getPassword() !== null) {
776
+                    $share->setPassword($this->hasher->hash($share->getPassword()));
777
+                }
778
+            }
779
+
780
+            // Cannot share with the owner
781
+            if ($share->getShareType() === IShare::TYPE_USER &&
782
+                $share->getSharedWith() === $share->getShareOwner()) {
783
+                throw new \InvalidArgumentException('Can’t share with the share owner');
784
+            }
785
+
786
+            // Generate the target
787
+            $target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
788
+            $target = \OC\Files\Filesystem::normalizePath($target);
789
+            $share->setTarget($target);
790
+
791
+            // Pre share event
792
+            $event = new GenericEvent($share);
793
+            $this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
794
+            if ($event->isPropagationStopped() && $event->hasArgument('error')) {
795
+                throw new \Exception($event->getArgument('error'));
796
+            }
797
+
798
+            $oldShare = $share;
799
+            $provider = $this->factory->getProviderForType($share->getShareType());
800
+            $share = $provider->create($share);
801
+
802
+            // Reuse the node we already have
803
+            $share->setNode($oldShare->getNode());
804
+
805
+            // Reset the target if it is null for the new share
806
+            if ($share->getTarget() === '') {
807
+                $share->setTarget($target);
808
+            }
809
+        } catch (AlreadySharedException $e) {
810
+            // if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
811
+            $share = $e->getExistingShare();
812
+        }
813
+
814
+        // Post share event
815
+        $event = new GenericEvent($share);
816
+        $this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
817
+
818
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
819
+
820
+        if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
821
+            && $share->getShareType() === IShare::TYPE_USER) {
822
+            $mailSend = $share->getMailSend();
823
+            if ($mailSend === true) {
824
+                $user = $this->userManager->get($share->getSharedWith());
825
+                if ($user !== null) {
826
+                    $emailAddress = $user->getEMailAddress();
827
+                    if ($emailAddress !== null && $emailAddress !== '') {
828
+                        $userLang = $this->l10nFactory->getUserLanguage($user);
829
+                        $l = $this->l10nFactory->get('lib', $userLang);
830
+                        $this->sendMailNotification(
831
+                            $l,
832
+                            $share->getNode()->getName(),
833
+                            $this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
834
+                            $share->getSharedBy(),
835
+                            $emailAddress,
836
+                            $share->getExpirationDate()
837
+                        );
838
+                        $this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
839
+                    } else {
840
+                        $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
841
+                    }
842
+                } else {
843
+                    $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
844
+                }
845
+            } else {
846
+                $this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
847
+            }
848
+        }
849
+
850
+        return $share;
851
+    }
852
+
853
+    /**
854
+     * Send mail notifications
855
+     *
856
+     * This method will catch and log mail transmission errors
857
+     *
858
+     * @param IL10N $l Language of the recipient
859
+     * @param string $filename file/folder name
860
+     * @param string $link link to the file/folder
861
+     * @param string $initiator user ID of share sender
862
+     * @param string $shareWith email address of share receiver
863
+     * @param \DateTime|null $expiration
864
+     */
865
+    protected function sendMailNotification(IL10N $l,
866
+                                            $filename,
867
+                                            $link,
868
+                                            $initiator,
869
+                                            $shareWith,
870
+                                            \DateTime $expiration = null) {
871
+        $initiatorUser = $this->userManager->get($initiator);
872
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
873
+
874
+        $message = $this->mailer->createMessage();
875
+
876
+        $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
877
+            'filename' => $filename,
878
+            'link' => $link,
879
+            'initiator' => $initiatorDisplayName,
880
+            'expiration' => $expiration,
881
+            'shareWith' => $shareWith,
882
+        ]);
883
+
884
+        $emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
885
+        $emailTemplate->addHeader();
886
+        $emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
887
+        $text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
888
+
889
+        $emailTemplate->addBodyText(
890
+            htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
891
+            $text
892
+        );
893
+        $emailTemplate->addBodyButton(
894
+            $l->t('Open »%s«', [$filename]),
895
+            $link
896
+        );
897
+
898
+        $message->setTo([$shareWith]);
899
+
900
+        // The "From" contains the sharers name
901
+        $instanceName = $this->defaults->getName();
902
+        $senderName = $l->t(
903
+            '%1$s via %2$s',
904
+            [
905
+                $initiatorDisplayName,
906
+                $instanceName
907
+            ]
908
+        );
909
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
910
+
911
+        // The "Reply-To" is set to the sharer if an mail address is configured
912
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
913
+        $initiatorEmail = $initiatorUser->getEMailAddress();
914
+        if ($initiatorEmail !== null) {
915
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
916
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
917
+        } else {
918
+            $emailTemplate->addFooter('', $l->getLanguageCode());
919
+        }
920
+
921
+        $message->useTemplate($emailTemplate);
922
+        try {
923
+            $failedRecipients = $this->mailer->send($message);
924
+            if (!empty($failedRecipients)) {
925
+                $this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
926
+                return;
927
+            }
928
+        } catch (\Exception $e) {
929
+            $this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
930
+        }
931
+    }
932
+
933
+    /**
934
+     * Update a share
935
+     *
936
+     * @param IShare $share
937
+     * @return IShare The share object
938
+     * @throws \InvalidArgumentException
939
+     */
940
+    public function updateShare(IShare $share) {
941
+        $expirationDateUpdated = false;
942
+
943
+        $this->canShare($share);
944
+
945
+        try {
946
+            $originalShare = $this->getShareById($share->getFullId());
947
+        } catch (\UnexpectedValueException $e) {
948
+            throw new \InvalidArgumentException('Share does not have a full id');
949
+        }
950
+
951
+        // We can't change the share type!
952
+        if ($share->getShareType() !== $originalShare->getShareType()) {
953
+            throw new \InvalidArgumentException('Can’t change share type');
954
+        }
955
+
956
+        // We can only change the recipient on user shares
957
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
958
+            $share->getShareType() !== IShare::TYPE_USER) {
959
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
960
+        }
961
+
962
+        // Cannot share with the owner
963
+        if ($share->getShareType() === IShare::TYPE_USER &&
964
+            $share->getSharedWith() === $share->getShareOwner()) {
965
+            throw new \InvalidArgumentException('Can’t share with the share owner');
966
+        }
967
+
968
+        $this->generalCreateChecks($share);
969
+
970
+        if ($share->getShareType() === IShare::TYPE_USER) {
971
+            $this->userCreateChecks($share);
972
+
973
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
974
+                //Verify the expiration date
975
+                $this->validateExpirationDateInternal($share);
976
+                $expirationDateUpdated = true;
977
+            }
978
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
979
+            $this->groupCreateChecks($share);
980
+
981
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
982
+                //Verify the expiration date
983
+                $this->validateExpirationDateInternal($share);
984
+                $expirationDateUpdated = true;
985
+            }
986
+        } elseif ($share->getShareType() === IShare::TYPE_LINK
987
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
988
+            $this->linkCreateChecks($share);
989
+
990
+            // The new password is not set again if it is the same as the old
991
+            // one, unless when switching from sending by Talk to sending by
992
+            // mail.
993
+            $plainTextPassword = $share->getPassword();
994
+            $updatedPassword = $this->updateSharePasswordIfNeeded($share, $originalShare);
995
+
996
+            /**
997
+             * Cannot enable the getSendPasswordByTalk if there is no password set
998
+             */
999
+            if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
1000
+                throw new \InvalidArgumentException('Can’t enable sending the password by Talk with an empty password');
1001
+            }
1002 1002
 	
1003
-			/**
1004
-			 * If we're in a mail share, we need to force a password change
1005
-			 * as either the user is not aware of the password or is already (received by mail)
1006
-			 * Thus the SendPasswordByTalk feature would not make sense
1007
-			 */
1008
-			if (!$updatedPassword && $share->getShareType() === IShare::TYPE_EMAIL) {
1009
-				if (!$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
1010
-					throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
1011
-				}
1012
-				if ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1013
-					throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
1014
-				}
1015
-			}
1016
-
1017
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1018
-				// Verify the expiration date
1019
-				$this->validateExpirationDateLink($share);
1020
-				$expirationDateUpdated = true;
1021
-			}
1022
-		}
1023
-
1024
-		$this->pathCreateChecks($share->getNode());
1025
-
1026
-		// Now update the share!
1027
-		$provider = $this->factory->getProviderForType($share->getShareType());
1028
-		if ($share->getShareType() === IShare::TYPE_EMAIL) {
1029
-			$share = $provider->update($share, $plainTextPassword);
1030
-		} else {
1031
-			$share = $provider->update($share);
1032
-		}
1033
-
1034
-		if ($expirationDateUpdated === true) {
1035
-			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1036
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1037
-				'itemSource' => $share->getNode()->getId(),
1038
-				'date' => $share->getExpirationDate(),
1039
-				'uidOwner' => $share->getSharedBy(),
1040
-			]);
1041
-		}
1042
-
1043
-		if ($share->getPassword() !== $originalShare->getPassword()) {
1044
-			\OC_Hook::emit(Share::class, 'post_update_password', [
1045
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1046
-				'itemSource' => $share->getNode()->getId(),
1047
-				'uidOwner' => $share->getSharedBy(),
1048
-				'token' => $share->getToken(),
1049
-				'disabled' => is_null($share->getPassword()),
1050
-			]);
1051
-		}
1052
-
1053
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
1054
-			if ($this->userManager->userExists($share->getShareOwner())) {
1055
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1056
-			} else {
1057
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1058
-			}
1059
-			\OC_Hook::emit(Share::class, 'post_update_permissions', [
1060
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1061
-				'itemSource' => $share->getNode()->getId(),
1062
-				'shareType' => $share->getShareType(),
1063
-				'shareWith' => $share->getSharedWith(),
1064
-				'uidOwner' => $share->getSharedBy(),
1065
-				'permissions' => $share->getPermissions(),
1066
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1067
-			]);
1068
-		}
1069
-
1070
-		return $share;
1071
-	}
1072
-
1073
-	/**
1074
-	 * Accept a share.
1075
-	 *
1076
-	 * @param IShare $share
1077
-	 * @param string $recipientId
1078
-	 * @return IShare The share object
1079
-	 * @throws \InvalidArgumentException
1080
-	 * @since 9.0.0
1081
-	 */
1082
-	public function acceptShare(IShare $share, string $recipientId): IShare {
1083
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1084
-		$provider = $this->factory->getProvider($providerId);
1085
-
1086
-		if (!method_exists($provider, 'acceptShare')) {
1087
-			// TODO FIX ME
1088
-			throw new \InvalidArgumentException('Share provider does not support accepting');
1089
-		}
1090
-		$provider->acceptShare($share, $recipientId);
1091
-		$event = new GenericEvent($share);
1092
-		$this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1093
-
1094
-		return $share;
1095
-	}
1096
-
1097
-	/**
1098
-	 * Updates the password of the given share if it is not the same as the
1099
-	 * password of the original share.
1100
-	 *
1101
-	 * @param IShare $share the share to update its password.
1102
-	 * @param IShare $originalShare the original share to compare its
1103
-	 *        password with.
1104
-	 * @return boolean whether the password was updated or not.
1105
-	 */
1106
-	private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1107
-		$passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1108
-									(($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1109
-									 ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1110
-									 ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1111
-										!$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1112
-
1113
-		// Password updated.
1114
-		if ($passwordsAreDifferent) {
1115
-			//Verify the password
1116
-			$this->verifyPassword($share->getPassword());
1117
-
1118
-			// If a password is set. Hash it!
1119
-			if (!empty($share->getPassword())) {
1120
-				$share->setPassword($this->hasher->hash($share->getPassword()));
1121
-
1122
-				return true;
1123
-			} else {
1124
-				// Empty string and null are seen as NOT password protected
1125
-				$share->setPassword(null);
1126
-				return true;
1127
-			}
1128
-		} else {
1129
-			// Reset the password to the original one, as it is either the same
1130
-			// as the "new" password or a hashed version of it.
1131
-			$share->setPassword($originalShare->getPassword());
1132
-		}
1133
-
1134
-		return false;
1135
-	}
1136
-
1137
-	/**
1138
-	 * Delete all the children of this share
1139
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1140
-	 *
1141
-	 * @param IShare $share
1142
-	 * @return IShare[] List of deleted shares
1143
-	 */
1144
-	protected function deleteChildren(IShare $share) {
1145
-		$deletedShares = [];
1146
-
1147
-		$provider = $this->factory->getProviderForType($share->getShareType());
1148
-
1149
-		foreach ($provider->getChildren($share) as $child) {
1150
-			$deletedChildren = $this->deleteChildren($child);
1151
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
1152
-
1153
-			$provider->delete($child);
1154
-			$this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
1155
-			$deletedShares[] = $child;
1156
-		}
1157
-
1158
-		return $deletedShares;
1159
-	}
1160
-
1161
-	/**
1162
-	 * Delete a share
1163
-	 *
1164
-	 * @param IShare $share
1165
-	 * @throws ShareNotFound
1166
-	 * @throws \InvalidArgumentException
1167
-	 */
1168
-	public function deleteShare(IShare $share) {
1169
-		try {
1170
-			$share->getFullId();
1171
-		} catch (\UnexpectedValueException $e) {
1172
-			throw new \InvalidArgumentException('Share does not have a full id');
1173
-		}
1174
-
1175
-		$event = new GenericEvent($share);
1176
-		$this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1177
-
1178
-		// Get all children and delete them as well
1179
-		$deletedShares = $this->deleteChildren($share);
1180
-
1181
-		// Do the actual delete
1182
-		$provider = $this->factory->getProviderForType($share->getShareType());
1183
-		$provider->delete($share);
1184
-
1185
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
1186
-
1187
-		// All the deleted shares caused by this delete
1188
-		$deletedShares[] = $share;
1189
-
1190
-		// Emit post hook
1191
-		$event->setArgument('deletedShares', $deletedShares);
1192
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1193
-	}
1194
-
1195
-
1196
-	/**
1197
-	 * Unshare a file as the recipient.
1198
-	 * This can be different from a regular delete for example when one of
1199
-	 * the users in a groups deletes that share. But the provider should
1200
-	 * handle this.
1201
-	 *
1202
-	 * @param IShare $share
1203
-	 * @param string $recipientId
1204
-	 */
1205
-	public function deleteFromSelf(IShare $share, $recipientId) {
1206
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1207
-		$provider = $this->factory->getProvider($providerId);
1208
-
1209
-		$provider->deleteFromSelf($share, $recipientId);
1210
-		$event = new GenericEvent($share);
1211
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1212
-	}
1213
-
1214
-	public function restoreShare(IShare $share, string $recipientId): IShare {
1215
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1216
-		$provider = $this->factory->getProvider($providerId);
1217
-
1218
-		return $provider->restore($share, $recipientId);
1219
-	}
1220
-
1221
-	/**
1222
-	 * @inheritdoc
1223
-	 */
1224
-	public function moveShare(IShare $share, $recipientId) {
1225
-		if ($share->getShareType() === IShare::TYPE_LINK
1226
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1227
-			throw new \InvalidArgumentException('Can’t change target of link share');
1228
-		}
1229
-
1230
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1231
-			throw new \InvalidArgumentException('Invalid recipient');
1232
-		}
1233
-
1234
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1235
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1236
-			if (is_null($sharedWith)) {
1237
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1238
-			}
1239
-			$recipient = $this->userManager->get($recipientId);
1240
-			if (!$sharedWith->inGroup($recipient)) {
1241
-				throw new \InvalidArgumentException('Invalid recipient');
1242
-			}
1243
-		}
1244
-
1245
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1246
-		$provider = $this->factory->getProvider($providerId);
1247
-
1248
-		return $provider->move($share, $recipientId);
1249
-	}
1250
-
1251
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1252
-		$providers = $this->factory->getAllProviders();
1253
-
1254
-		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1255
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1256
-			foreach ($newShares as $fid => $data) {
1257
-				if (!isset($shares[$fid])) {
1258
-					$shares[$fid] = [];
1259
-				}
1260
-
1261
-				$shares[$fid] = array_merge($shares[$fid], $data);
1262
-			}
1263
-			return $shares;
1264
-		}, []);
1265
-	}
1266
-
1267
-	/**
1268
-	 * @inheritdoc
1269
-	 */
1270
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1271
-		if ($path !== null &&
1272
-				!($path instanceof \OCP\Files\File) &&
1273
-				!($path instanceof \OCP\Files\Folder)) {
1274
-			throw new \InvalidArgumentException('invalid path');
1275
-		}
1276
-
1277
-		try {
1278
-			$provider = $this->factory->getProviderForType($shareType);
1279
-		} catch (ProviderException $e) {
1280
-			return [];
1281
-		}
1282
-
1283
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1284
-
1285
-		/*
1003
+            /**
1004
+             * If we're in a mail share, we need to force a password change
1005
+             * as either the user is not aware of the password or is already (received by mail)
1006
+             * Thus the SendPasswordByTalk feature would not make sense
1007
+             */
1008
+            if (!$updatedPassword && $share->getShareType() === IShare::TYPE_EMAIL) {
1009
+                if (!$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
1010
+                    throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
1011
+                }
1012
+                if ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1013
+                    throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
1014
+                }
1015
+            }
1016
+
1017
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
1018
+                // Verify the expiration date
1019
+                $this->validateExpirationDateLink($share);
1020
+                $expirationDateUpdated = true;
1021
+            }
1022
+        }
1023
+
1024
+        $this->pathCreateChecks($share->getNode());
1025
+
1026
+        // Now update the share!
1027
+        $provider = $this->factory->getProviderForType($share->getShareType());
1028
+        if ($share->getShareType() === IShare::TYPE_EMAIL) {
1029
+            $share = $provider->update($share, $plainTextPassword);
1030
+        } else {
1031
+            $share = $provider->update($share);
1032
+        }
1033
+
1034
+        if ($expirationDateUpdated === true) {
1035
+            \OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1036
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1037
+                'itemSource' => $share->getNode()->getId(),
1038
+                'date' => $share->getExpirationDate(),
1039
+                'uidOwner' => $share->getSharedBy(),
1040
+            ]);
1041
+        }
1042
+
1043
+        if ($share->getPassword() !== $originalShare->getPassword()) {
1044
+            \OC_Hook::emit(Share::class, 'post_update_password', [
1045
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1046
+                'itemSource' => $share->getNode()->getId(),
1047
+                'uidOwner' => $share->getSharedBy(),
1048
+                'token' => $share->getToken(),
1049
+                'disabled' => is_null($share->getPassword()),
1050
+            ]);
1051
+        }
1052
+
1053
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
1054
+            if ($this->userManager->userExists($share->getShareOwner())) {
1055
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1056
+            } else {
1057
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1058
+            }
1059
+            \OC_Hook::emit(Share::class, 'post_update_permissions', [
1060
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1061
+                'itemSource' => $share->getNode()->getId(),
1062
+                'shareType' => $share->getShareType(),
1063
+                'shareWith' => $share->getSharedWith(),
1064
+                'uidOwner' => $share->getSharedBy(),
1065
+                'permissions' => $share->getPermissions(),
1066
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1067
+            ]);
1068
+        }
1069
+
1070
+        return $share;
1071
+    }
1072
+
1073
+    /**
1074
+     * Accept a share.
1075
+     *
1076
+     * @param IShare $share
1077
+     * @param string $recipientId
1078
+     * @return IShare The share object
1079
+     * @throws \InvalidArgumentException
1080
+     * @since 9.0.0
1081
+     */
1082
+    public function acceptShare(IShare $share, string $recipientId): IShare {
1083
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1084
+        $provider = $this->factory->getProvider($providerId);
1085
+
1086
+        if (!method_exists($provider, 'acceptShare')) {
1087
+            // TODO FIX ME
1088
+            throw new \InvalidArgumentException('Share provider does not support accepting');
1089
+        }
1090
+        $provider->acceptShare($share, $recipientId);
1091
+        $event = new GenericEvent($share);
1092
+        $this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1093
+
1094
+        return $share;
1095
+    }
1096
+
1097
+    /**
1098
+     * Updates the password of the given share if it is not the same as the
1099
+     * password of the original share.
1100
+     *
1101
+     * @param IShare $share the share to update its password.
1102
+     * @param IShare $originalShare the original share to compare its
1103
+     *        password with.
1104
+     * @return boolean whether the password was updated or not.
1105
+     */
1106
+    private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1107
+        $passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1108
+                                    (($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1109
+                                     ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1110
+                                     ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1111
+                                        !$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1112
+
1113
+        // Password updated.
1114
+        if ($passwordsAreDifferent) {
1115
+            //Verify the password
1116
+            $this->verifyPassword($share->getPassword());
1117
+
1118
+            // If a password is set. Hash it!
1119
+            if (!empty($share->getPassword())) {
1120
+                $share->setPassword($this->hasher->hash($share->getPassword()));
1121
+
1122
+                return true;
1123
+            } else {
1124
+                // Empty string and null are seen as NOT password protected
1125
+                $share->setPassword(null);
1126
+                return true;
1127
+            }
1128
+        } else {
1129
+            // Reset the password to the original one, as it is either the same
1130
+            // as the "new" password or a hashed version of it.
1131
+            $share->setPassword($originalShare->getPassword());
1132
+        }
1133
+
1134
+        return false;
1135
+    }
1136
+
1137
+    /**
1138
+     * Delete all the children of this share
1139
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1140
+     *
1141
+     * @param IShare $share
1142
+     * @return IShare[] List of deleted shares
1143
+     */
1144
+    protected function deleteChildren(IShare $share) {
1145
+        $deletedShares = [];
1146
+
1147
+        $provider = $this->factory->getProviderForType($share->getShareType());
1148
+
1149
+        foreach ($provider->getChildren($share) as $child) {
1150
+            $deletedChildren = $this->deleteChildren($child);
1151
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
1152
+
1153
+            $provider->delete($child);
1154
+            $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($child));
1155
+            $deletedShares[] = $child;
1156
+        }
1157
+
1158
+        return $deletedShares;
1159
+    }
1160
+
1161
+    /**
1162
+     * Delete a share
1163
+     *
1164
+     * @param IShare $share
1165
+     * @throws ShareNotFound
1166
+     * @throws \InvalidArgumentException
1167
+     */
1168
+    public function deleteShare(IShare $share) {
1169
+        try {
1170
+            $share->getFullId();
1171
+        } catch (\UnexpectedValueException $e) {
1172
+            throw new \InvalidArgumentException('Share does not have a full id');
1173
+        }
1174
+
1175
+        $event = new GenericEvent($share);
1176
+        $this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1177
+
1178
+        // Get all children and delete them as well
1179
+        $deletedShares = $this->deleteChildren($share);
1180
+
1181
+        // Do the actual delete
1182
+        $provider = $this->factory->getProviderForType($share->getShareType());
1183
+        $provider->delete($share);
1184
+
1185
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareDeletedEvent($share));
1186
+
1187
+        // All the deleted shares caused by this delete
1188
+        $deletedShares[] = $share;
1189
+
1190
+        // Emit post hook
1191
+        $event->setArgument('deletedShares', $deletedShares);
1192
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1193
+    }
1194
+
1195
+
1196
+    /**
1197
+     * Unshare a file as the recipient.
1198
+     * This can be different from a regular delete for example when one of
1199
+     * the users in a groups deletes that share. But the provider should
1200
+     * handle this.
1201
+     *
1202
+     * @param IShare $share
1203
+     * @param string $recipientId
1204
+     */
1205
+    public function deleteFromSelf(IShare $share, $recipientId) {
1206
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1207
+        $provider = $this->factory->getProvider($providerId);
1208
+
1209
+        $provider->deleteFromSelf($share, $recipientId);
1210
+        $event = new GenericEvent($share);
1211
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1212
+    }
1213
+
1214
+    public function restoreShare(IShare $share, string $recipientId): IShare {
1215
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1216
+        $provider = $this->factory->getProvider($providerId);
1217
+
1218
+        return $provider->restore($share, $recipientId);
1219
+    }
1220
+
1221
+    /**
1222
+     * @inheritdoc
1223
+     */
1224
+    public function moveShare(IShare $share, $recipientId) {
1225
+        if ($share->getShareType() === IShare::TYPE_LINK
1226
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1227
+            throw new \InvalidArgumentException('Can’t change target of link share');
1228
+        }
1229
+
1230
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1231
+            throw new \InvalidArgumentException('Invalid recipient');
1232
+        }
1233
+
1234
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1235
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1236
+            if (is_null($sharedWith)) {
1237
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1238
+            }
1239
+            $recipient = $this->userManager->get($recipientId);
1240
+            if (!$sharedWith->inGroup($recipient)) {
1241
+                throw new \InvalidArgumentException('Invalid recipient');
1242
+            }
1243
+        }
1244
+
1245
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1246
+        $provider = $this->factory->getProvider($providerId);
1247
+
1248
+        return $provider->move($share, $recipientId);
1249
+    }
1250
+
1251
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1252
+        $providers = $this->factory->getAllProviders();
1253
+
1254
+        return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1255
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1256
+            foreach ($newShares as $fid => $data) {
1257
+                if (!isset($shares[$fid])) {
1258
+                    $shares[$fid] = [];
1259
+                }
1260
+
1261
+                $shares[$fid] = array_merge($shares[$fid], $data);
1262
+            }
1263
+            return $shares;
1264
+        }, []);
1265
+    }
1266
+
1267
+    /**
1268
+     * @inheritdoc
1269
+     */
1270
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1271
+        if ($path !== null &&
1272
+                !($path instanceof \OCP\Files\File) &&
1273
+                !($path instanceof \OCP\Files\Folder)) {
1274
+            throw new \InvalidArgumentException('invalid path');
1275
+        }
1276
+
1277
+        try {
1278
+            $provider = $this->factory->getProviderForType($shareType);
1279
+        } catch (ProviderException $e) {
1280
+            return [];
1281
+        }
1282
+
1283
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1284
+
1285
+        /*
1286 1286
 		 * Work around so we don't return expired shares but still follow
1287 1287
 		 * proper pagination.
1288 1288
 		 */
1289 1289
 
1290
-		$shares2 = [];
1291
-
1292
-		while (true) {
1293
-			$added = 0;
1294
-			foreach ($shares as $share) {
1295
-				try {
1296
-					$this->checkExpireDate($share);
1297
-				} catch (ShareNotFound $e) {
1298
-					//Ignore since this basically means the share is deleted
1299
-					continue;
1300
-				}
1301
-
1302
-				$added++;
1303
-				$shares2[] = $share;
1304
-
1305
-				if (count($shares2) === $limit) {
1306
-					break;
1307
-				}
1308
-			}
1309
-
1310
-			// If we did not fetch more shares than the limit then there are no more shares
1311
-			if (count($shares) < $limit) {
1312
-				break;
1313
-			}
1314
-
1315
-			if (count($shares2) === $limit) {
1316
-				break;
1317
-			}
1318
-
1319
-			// If there was no limit on the select we are done
1320
-			if ($limit === -1) {
1321
-				break;
1322
-			}
1323
-
1324
-			$offset += $added;
1325
-
1326
-			// Fetch again $limit shares
1327
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1328
-
1329
-			// No more shares means we are done
1330
-			if (empty($shares)) {
1331
-				break;
1332
-			}
1333
-		}
1334
-
1335
-		$shares = $shares2;
1336
-
1337
-		return $shares;
1338
-	}
1339
-
1340
-	/**
1341
-	 * @inheritdoc
1342
-	 */
1343
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1344
-		try {
1345
-			$provider = $this->factory->getProviderForType($shareType);
1346
-		} catch (ProviderException $e) {
1347
-			return [];
1348
-		}
1349
-
1350
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1351
-
1352
-		// remove all shares which are already expired
1353
-		foreach ($shares as $key => $share) {
1354
-			try {
1355
-				$this->checkExpireDate($share);
1356
-			} catch (ShareNotFound $e) {
1357
-				unset($shares[$key]);
1358
-			}
1359
-		}
1360
-
1361
-		return $shares;
1362
-	}
1363
-
1364
-	/**
1365
-	 * @inheritdoc
1366
-	 */
1367
-	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1368
-		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1369
-
1370
-		// Only get deleted shares
1371
-		$shares = array_filter($shares, function (IShare $share) {
1372
-			return $share->getPermissions() === 0;
1373
-		});
1374
-
1375
-		// Only get shares where the owner still exists
1376
-		$shares = array_filter($shares, function (IShare $share) {
1377
-			return $this->userManager->userExists($share->getShareOwner());
1378
-		});
1379
-
1380
-		return $shares;
1381
-	}
1382
-
1383
-	/**
1384
-	 * @inheritdoc
1385
-	 */
1386
-	public function getShareById($id, $recipient = null) {
1387
-		if ($id === null) {
1388
-			throw new ShareNotFound();
1389
-		}
1390
-
1391
-		[$providerId, $id] = $this->splitFullId($id);
1392
-
1393
-		try {
1394
-			$provider = $this->factory->getProvider($providerId);
1395
-		} catch (ProviderException $e) {
1396
-			throw new ShareNotFound();
1397
-		}
1398
-
1399
-		$share = $provider->getShareById($id, $recipient);
1400
-
1401
-		$this->checkExpireDate($share);
1402
-
1403
-		return $share;
1404
-	}
1405
-
1406
-	/**
1407
-	 * Get all the shares for a given path
1408
-	 *
1409
-	 * @param \OCP\Files\Node $path
1410
-	 * @param int $page
1411
-	 * @param int $perPage
1412
-	 *
1413
-	 * @return Share[]
1414
-	 */
1415
-	public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1416
-		return [];
1417
-	}
1418
-
1419
-	/**
1420
-	 * Get the share by token possible with password
1421
-	 *
1422
-	 * @param string $token
1423
-	 * @return IShare
1424
-	 *
1425
-	 * @throws ShareNotFound
1426
-	 */
1427
-	public function getShareByToken($token) {
1428
-		// tokens can't be valid local user names
1429
-		if ($this->userManager->userExists($token)) {
1430
-			throw new ShareNotFound();
1431
-		}
1432
-		$share = null;
1433
-		try {
1434
-			if ($this->shareApiAllowLinks()) {
1435
-				$provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1436
-				$share = $provider->getShareByToken($token);
1437
-			}
1438
-		} catch (ProviderException $e) {
1439
-		} catch (ShareNotFound $e) {
1440
-		}
1441
-
1442
-
1443
-		// If it is not a link share try to fetch a federated share by token
1444
-		if ($share === null) {
1445
-			try {
1446
-				$provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1447
-				$share = $provider->getShareByToken($token);
1448
-			} catch (ProviderException $e) {
1449
-			} catch (ShareNotFound $e) {
1450
-			}
1451
-		}
1452
-
1453
-		// If it is not a link share try to fetch a mail share by token
1454
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1455
-			try {
1456
-				$provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1457
-				$share = $provider->getShareByToken($token);
1458
-			} catch (ProviderException $e) {
1459
-			} catch (ShareNotFound $e) {
1460
-			}
1461
-		}
1462
-
1463
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1464
-			try {
1465
-				$provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1466
-				$share = $provider->getShareByToken($token);
1467
-			} catch (ProviderException $e) {
1468
-			} catch (ShareNotFound $e) {
1469
-			}
1470
-		}
1471
-
1472
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1473
-			try {
1474
-				$provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1475
-				$share = $provider->getShareByToken($token);
1476
-			} catch (ProviderException $e) {
1477
-			} catch (ShareNotFound $e) {
1478
-			}
1479
-		}
1480
-
1481
-		if ($share === null) {
1482
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1483
-		}
1484
-
1485
-		$this->checkExpireDate($share);
1486
-
1487
-		/*
1290
+        $shares2 = [];
1291
+
1292
+        while (true) {
1293
+            $added = 0;
1294
+            foreach ($shares as $share) {
1295
+                try {
1296
+                    $this->checkExpireDate($share);
1297
+                } catch (ShareNotFound $e) {
1298
+                    //Ignore since this basically means the share is deleted
1299
+                    continue;
1300
+                }
1301
+
1302
+                $added++;
1303
+                $shares2[] = $share;
1304
+
1305
+                if (count($shares2) === $limit) {
1306
+                    break;
1307
+                }
1308
+            }
1309
+
1310
+            // If we did not fetch more shares than the limit then there are no more shares
1311
+            if (count($shares) < $limit) {
1312
+                break;
1313
+            }
1314
+
1315
+            if (count($shares2) === $limit) {
1316
+                break;
1317
+            }
1318
+
1319
+            // If there was no limit on the select we are done
1320
+            if ($limit === -1) {
1321
+                break;
1322
+            }
1323
+
1324
+            $offset += $added;
1325
+
1326
+            // Fetch again $limit shares
1327
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1328
+
1329
+            // No more shares means we are done
1330
+            if (empty($shares)) {
1331
+                break;
1332
+            }
1333
+        }
1334
+
1335
+        $shares = $shares2;
1336
+
1337
+        return $shares;
1338
+    }
1339
+
1340
+    /**
1341
+     * @inheritdoc
1342
+     */
1343
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1344
+        try {
1345
+            $provider = $this->factory->getProviderForType($shareType);
1346
+        } catch (ProviderException $e) {
1347
+            return [];
1348
+        }
1349
+
1350
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1351
+
1352
+        // remove all shares which are already expired
1353
+        foreach ($shares as $key => $share) {
1354
+            try {
1355
+                $this->checkExpireDate($share);
1356
+            } catch (ShareNotFound $e) {
1357
+                unset($shares[$key]);
1358
+            }
1359
+        }
1360
+
1361
+        return $shares;
1362
+    }
1363
+
1364
+    /**
1365
+     * @inheritdoc
1366
+     */
1367
+    public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1368
+        $shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1369
+
1370
+        // Only get deleted shares
1371
+        $shares = array_filter($shares, function (IShare $share) {
1372
+            return $share->getPermissions() === 0;
1373
+        });
1374
+
1375
+        // Only get shares where the owner still exists
1376
+        $shares = array_filter($shares, function (IShare $share) {
1377
+            return $this->userManager->userExists($share->getShareOwner());
1378
+        });
1379
+
1380
+        return $shares;
1381
+    }
1382
+
1383
+    /**
1384
+     * @inheritdoc
1385
+     */
1386
+    public function getShareById($id, $recipient = null) {
1387
+        if ($id === null) {
1388
+            throw new ShareNotFound();
1389
+        }
1390
+
1391
+        [$providerId, $id] = $this->splitFullId($id);
1392
+
1393
+        try {
1394
+            $provider = $this->factory->getProvider($providerId);
1395
+        } catch (ProviderException $e) {
1396
+            throw new ShareNotFound();
1397
+        }
1398
+
1399
+        $share = $provider->getShareById($id, $recipient);
1400
+
1401
+        $this->checkExpireDate($share);
1402
+
1403
+        return $share;
1404
+    }
1405
+
1406
+    /**
1407
+     * Get all the shares for a given path
1408
+     *
1409
+     * @param \OCP\Files\Node $path
1410
+     * @param int $page
1411
+     * @param int $perPage
1412
+     *
1413
+     * @return Share[]
1414
+     */
1415
+    public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1416
+        return [];
1417
+    }
1418
+
1419
+    /**
1420
+     * Get the share by token possible with password
1421
+     *
1422
+     * @param string $token
1423
+     * @return IShare
1424
+     *
1425
+     * @throws ShareNotFound
1426
+     */
1427
+    public function getShareByToken($token) {
1428
+        // tokens can't be valid local user names
1429
+        if ($this->userManager->userExists($token)) {
1430
+            throw new ShareNotFound();
1431
+        }
1432
+        $share = null;
1433
+        try {
1434
+            if ($this->shareApiAllowLinks()) {
1435
+                $provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1436
+                $share = $provider->getShareByToken($token);
1437
+            }
1438
+        } catch (ProviderException $e) {
1439
+        } catch (ShareNotFound $e) {
1440
+        }
1441
+
1442
+
1443
+        // If it is not a link share try to fetch a federated share by token
1444
+        if ($share === null) {
1445
+            try {
1446
+                $provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1447
+                $share = $provider->getShareByToken($token);
1448
+            } catch (ProviderException $e) {
1449
+            } catch (ShareNotFound $e) {
1450
+            }
1451
+        }
1452
+
1453
+        // If it is not a link share try to fetch a mail share by token
1454
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1455
+            try {
1456
+                $provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1457
+                $share = $provider->getShareByToken($token);
1458
+            } catch (ProviderException $e) {
1459
+            } catch (ShareNotFound $e) {
1460
+            }
1461
+        }
1462
+
1463
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1464
+            try {
1465
+                $provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1466
+                $share = $provider->getShareByToken($token);
1467
+            } catch (ProviderException $e) {
1468
+            } catch (ShareNotFound $e) {
1469
+            }
1470
+        }
1471
+
1472
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1473
+            try {
1474
+                $provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1475
+                $share = $provider->getShareByToken($token);
1476
+            } catch (ProviderException $e) {
1477
+            } catch (ShareNotFound $e) {
1478
+            }
1479
+        }
1480
+
1481
+        if ($share === null) {
1482
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1483
+        }
1484
+
1485
+        $this->checkExpireDate($share);
1486
+
1487
+        /*
1488 1488
 		 * Reduce the permissions for link or email shares if public upload is not enabled
1489 1489
 		 */
1490
-		if (($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL)
1491
-			&& !$this->shareApiLinkAllowPublicUpload()) {
1492
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1493
-		}
1494
-
1495
-		return $share;
1496
-	}
1497
-
1498
-	protected function checkExpireDate($share) {
1499
-		if ($share->isExpired()) {
1500
-			$this->deleteShare($share);
1501
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1502
-		}
1503
-	}
1504
-
1505
-	/**
1506
-	 * Verify the password of a public share
1507
-	 *
1508
-	 * @param IShare $share
1509
-	 * @param string $password
1510
-	 * @return bool
1511
-	 */
1512
-	public function checkPassword(IShare $share, $password) {
1513
-		$passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1514
-							 || $share->getShareType() !== IShare::TYPE_EMAIL
1515
-							 || $share->getShareType() !== IShare::TYPE_CIRCLE;
1516
-		if (!$passwordProtected) {
1517
-			//TODO maybe exception?
1518
-			return false;
1519
-		}
1520
-
1521
-		if ($password === null || $share->getPassword() === null) {
1522
-			return false;
1523
-		}
1524
-
1525
-		$newHash = '';
1526
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1527
-			return false;
1528
-		}
1529
-
1530
-		if (!empty($newHash)) {
1531
-			$share->setPassword($newHash);
1532
-			$provider = $this->factory->getProviderForType($share->getShareType());
1533
-			$provider->update($share);
1534
-		}
1535
-
1536
-		return true;
1537
-	}
1538
-
1539
-	/**
1540
-	 * @inheritdoc
1541
-	 */
1542
-	public function userDeleted($uid) {
1543
-		$types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1544
-
1545
-		foreach ($types as $type) {
1546
-			try {
1547
-				$provider = $this->factory->getProviderForType($type);
1548
-			} catch (ProviderException $e) {
1549
-				continue;
1550
-			}
1551
-			$provider->userDeleted($uid, $type);
1552
-		}
1553
-	}
1554
-
1555
-	/**
1556
-	 * @inheritdoc
1557
-	 */
1558
-	public function groupDeleted($gid) {
1559
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1560
-		$provider->groupDeleted($gid);
1561
-
1562
-		$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1563
-		if ($excludedGroups === '') {
1564
-			return;
1565
-		}
1566
-
1567
-		$excludedGroups = json_decode($excludedGroups, true);
1568
-		if (json_last_error() !== JSON_ERROR_NONE) {
1569
-			return;
1570
-		}
1571
-
1572
-		$excludedGroups = array_diff($excludedGroups, [$gid]);
1573
-		$this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1574
-	}
1575
-
1576
-	/**
1577
-	 * @inheritdoc
1578
-	 */
1579
-	public function userDeletedFromGroup($uid, $gid) {
1580
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1581
-		$provider->userDeletedFromGroup($uid, $gid);
1582
-	}
1583
-
1584
-	/**
1585
-	 * Get access list to a path. This means
1586
-	 * all the users that can access a given path.
1587
-	 *
1588
-	 * Consider:
1589
-	 * -root
1590
-	 * |-folder1 (23)
1591
-	 *  |-folder2 (32)
1592
-	 *   |-fileA (42)
1593
-	 *
1594
-	 * fileA is shared with user1 and user1@server1
1595
-	 * folder2 is shared with group2 (user4 is a member of group2)
1596
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1597
-	 *
1598
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1599
-	 * [
1600
-	 *  users  => [
1601
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1602
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1603
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1604
-	 *  ],
1605
-	 *  remote => [
1606
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1607
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1608
-	 *  ],
1609
-	 *  public => bool
1610
-	 *  mail => bool
1611
-	 * ]
1612
-	 *
1613
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1614
-	 * [
1615
-	 *  users  => ['user1', 'user2', 'user4'],
1616
-	 *  remote => bool,
1617
-	 *  public => bool
1618
-	 *  mail => bool
1619
-	 * ]
1620
-	 *
1621
-	 * This is required for encryption/activity
1622
-	 *
1623
-	 * @param \OCP\Files\Node $path
1624
-	 * @param bool $recursive Should we check all parent folders as well
1625
-	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1626
-	 * @return array
1627
-	 */
1628
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1629
-		$owner = $path->getOwner();
1630
-
1631
-		if ($owner === null) {
1632
-			return [];
1633
-		}
1634
-
1635
-		$owner = $owner->getUID();
1636
-
1637
-		if ($currentAccess) {
1638
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1639
-		} else {
1640
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1641
-		}
1642
-		if (!$this->userManager->userExists($owner)) {
1643
-			return $al;
1644
-		}
1645
-
1646
-		//Get node for the owner and correct the owner in case of external storages
1647
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1648
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1649
-			$nodes = $userFolder->getById($path->getId());
1650
-			$path = array_shift($nodes);
1651
-			if ($path->getOwner() === null) {
1652
-				return [];
1653
-			}
1654
-			$owner = $path->getOwner()->getUID();
1655
-		}
1656
-
1657
-		$providers = $this->factory->getAllProviders();
1658
-
1659
-		/** @var Node[] $nodes */
1660
-		$nodes = [];
1661
-
1662
-
1663
-		if ($currentAccess) {
1664
-			$ownerPath = $path->getPath();
1665
-			$ownerPath = explode('/', $ownerPath, 4);
1666
-			if (count($ownerPath) < 4) {
1667
-				$ownerPath = '';
1668
-			} else {
1669
-				$ownerPath = $ownerPath[3];
1670
-			}
1671
-			$al['users'][$owner] = [
1672
-				'node_id' => $path->getId(),
1673
-				'node_path' => '/' . $ownerPath,
1674
-			];
1675
-		} else {
1676
-			$al['users'][] = $owner;
1677
-		}
1678
-
1679
-		// Collect all the shares
1680
-		while ($path->getPath() !== $userFolder->getPath()) {
1681
-			$nodes[] = $path;
1682
-			if (!$recursive) {
1683
-				break;
1684
-			}
1685
-			$path = $path->getParent();
1686
-		}
1687
-
1688
-		foreach ($providers as $provider) {
1689
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1690
-
1691
-			foreach ($tmp as $k => $v) {
1692
-				if (isset($al[$k])) {
1693
-					if (is_array($al[$k])) {
1694
-						if ($currentAccess) {
1695
-							$al[$k] += $v;
1696
-						} else {
1697
-							$al[$k] = array_merge($al[$k], $v);
1698
-							$al[$k] = array_unique($al[$k]);
1699
-							$al[$k] = array_values($al[$k]);
1700
-						}
1701
-					} else {
1702
-						$al[$k] = $al[$k] || $v;
1703
-					}
1704
-				} else {
1705
-					$al[$k] = $v;
1706
-				}
1707
-			}
1708
-		}
1709
-
1710
-		return $al;
1711
-	}
1712
-
1713
-	/**
1714
-	 * Create a new share
1715
-	 *
1716
-	 * @return IShare
1717
-	 */
1718
-	public function newShare() {
1719
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1720
-	}
1721
-
1722
-	/**
1723
-	 * Is the share API enabled
1724
-	 *
1725
-	 * @return bool
1726
-	 */
1727
-	public function shareApiEnabled() {
1728
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1729
-	}
1730
-
1731
-	/**
1732
-	 * Is public link sharing enabled
1733
-	 *
1734
-	 * @return bool
1735
-	 */
1736
-	public function shareApiAllowLinks() {
1737
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1738
-	}
1739
-
1740
-	/**
1741
-	 * Is password on public link requires
1742
-	 *
1743
-	 * @return bool
1744
-	 */
1745
-	public function shareApiLinkEnforcePassword() {
1746
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1747
-	}
1748
-
1749
-	/**
1750
-	 * Is default link expire date enabled
1751
-	 *
1752
-	 * @return bool
1753
-	 */
1754
-	public function shareApiLinkDefaultExpireDate() {
1755
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1756
-	}
1757
-
1758
-	/**
1759
-	 * Is default link expire date enforced
1760
-	 *`
1761
-	 * @return bool
1762
-	 */
1763
-	public function shareApiLinkDefaultExpireDateEnforced() {
1764
-		return $this->shareApiLinkDefaultExpireDate() &&
1765
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1766
-	}
1767
-
1768
-
1769
-	/**
1770
-	 * Number of default link expire days
1771
-	 * @return int
1772
-	 */
1773
-	public function shareApiLinkDefaultExpireDays() {
1774
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1775
-	}
1776
-
1777
-	/**
1778
-	 * Is default internal expire date enabled
1779
-	 *
1780
-	 * @return bool
1781
-	 */
1782
-	public function shareApiInternalDefaultExpireDate(): bool {
1783
-		return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1784
-	}
1785
-
1786
-	/**
1787
-	 * Is default expire date enforced
1788
-	 *`
1789
-	 * @return bool
1790
-	 */
1791
-	public function shareApiInternalDefaultExpireDateEnforced(): bool {
1792
-		return $this->shareApiInternalDefaultExpireDate() &&
1793
-			$this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1794
-	}
1795
-
1796
-
1797
-	/**
1798
-	 * Number of default expire days
1799
-	 * @return int
1800
-	 */
1801
-	public function shareApiInternalDefaultExpireDays(): int {
1802
-		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1803
-	}
1804
-
1805
-	/**
1806
-	 * Allow public upload on link shares
1807
-	 *
1808
-	 * @return bool
1809
-	 */
1810
-	public function shareApiLinkAllowPublicUpload() {
1811
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1812
-	}
1813
-
1814
-	/**
1815
-	 * check if user can only share with group members
1816
-	 * @return bool
1817
-	 */
1818
-	public function shareWithGroupMembersOnly() {
1819
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1820
-	}
1821
-
1822
-	/**
1823
-	 * Check if users can share with groups
1824
-	 * @return bool
1825
-	 */
1826
-	public function allowGroupSharing() {
1827
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1828
-	}
1829
-
1830
-	public function allowEnumeration(): bool {
1831
-		return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1832
-	}
1833
-
1834
-	public function limitEnumerationToGroups(): bool {
1835
-		return $this->allowEnumeration() &&
1836
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1837
-	}
1838
-
1839
-	public function limitEnumerationToPhone(): bool {
1840
-		return $this->allowEnumeration() &&
1841
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
1842
-	}
1843
-
1844
-	public function allowEnumerationFullMatch(): bool {
1845
-		return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
1846
-	}
1847
-
1848
-	/**
1849
-	 * Copied from \OC_Util::isSharingDisabledForUser
1850
-	 *
1851
-	 * TODO: Deprecate fuction from OC_Util
1852
-	 *
1853
-	 * @param string $userId
1854
-	 * @return bool
1855
-	 */
1856
-	public function sharingDisabledForUser($userId) {
1857
-		if ($userId === null) {
1858
-			return false;
1859
-		}
1860
-
1861
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1862
-			return $this->sharingDisabledForUsersCache[$userId];
1863
-		}
1864
-
1865
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1866
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1867
-			$excludedGroups = json_decode($groupsList);
1868
-			if (is_null($excludedGroups)) {
1869
-				$excludedGroups = explode(',', $groupsList);
1870
-				$newValue = json_encode($excludedGroups);
1871
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1872
-			}
1873
-			$user = $this->userManager->get($userId);
1874
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1875
-			if (!empty($usersGroups)) {
1876
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1877
-				// if the user is only in groups which are disabled for sharing then
1878
-				// sharing is also disabled for the user
1879
-				if (empty($remainingGroups)) {
1880
-					$this->sharingDisabledForUsersCache[$userId] = true;
1881
-					return true;
1882
-				}
1883
-			}
1884
-		}
1885
-
1886
-		$this->sharingDisabledForUsersCache[$userId] = false;
1887
-		return false;
1888
-	}
1889
-
1890
-	/**
1891
-	 * @inheritdoc
1892
-	 */
1893
-	public function outgoingServer2ServerSharesAllowed() {
1894
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1895
-	}
1896
-
1897
-	/**
1898
-	 * @inheritdoc
1899
-	 */
1900
-	public function outgoingServer2ServerGroupSharesAllowed() {
1901
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1902
-	}
1903
-
1904
-	/**
1905
-	 * @inheritdoc
1906
-	 */
1907
-	public function shareProviderExists($shareType) {
1908
-		try {
1909
-			$this->factory->getProviderForType($shareType);
1910
-		} catch (ProviderException $e) {
1911
-			return false;
1912
-		}
1913
-
1914
-		return true;
1915
-	}
1916
-
1917
-	public function registerShareProvider(string $shareProviderClass): void {
1918
-		$this->factory->registerProvider($shareProviderClass);
1919
-	}
1920
-
1921
-	public function getAllShares(): iterable {
1922
-		$providers = $this->factory->getAllProviders();
1923
-
1924
-		foreach ($providers as $provider) {
1925
-			yield from $provider->getAllShares();
1926
-		}
1927
-	}
1490
+        if (($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL)
1491
+            && !$this->shareApiLinkAllowPublicUpload()) {
1492
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1493
+        }
1494
+
1495
+        return $share;
1496
+    }
1497
+
1498
+    protected function checkExpireDate($share) {
1499
+        if ($share->isExpired()) {
1500
+            $this->deleteShare($share);
1501
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1502
+        }
1503
+    }
1504
+
1505
+    /**
1506
+     * Verify the password of a public share
1507
+     *
1508
+     * @param IShare $share
1509
+     * @param string $password
1510
+     * @return bool
1511
+     */
1512
+    public function checkPassword(IShare $share, $password) {
1513
+        $passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1514
+                             || $share->getShareType() !== IShare::TYPE_EMAIL
1515
+                             || $share->getShareType() !== IShare::TYPE_CIRCLE;
1516
+        if (!$passwordProtected) {
1517
+            //TODO maybe exception?
1518
+            return false;
1519
+        }
1520
+
1521
+        if ($password === null || $share->getPassword() === null) {
1522
+            return false;
1523
+        }
1524
+
1525
+        $newHash = '';
1526
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1527
+            return false;
1528
+        }
1529
+
1530
+        if (!empty($newHash)) {
1531
+            $share->setPassword($newHash);
1532
+            $provider = $this->factory->getProviderForType($share->getShareType());
1533
+            $provider->update($share);
1534
+        }
1535
+
1536
+        return true;
1537
+    }
1538
+
1539
+    /**
1540
+     * @inheritdoc
1541
+     */
1542
+    public function userDeleted($uid) {
1543
+        $types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1544
+
1545
+        foreach ($types as $type) {
1546
+            try {
1547
+                $provider = $this->factory->getProviderForType($type);
1548
+            } catch (ProviderException $e) {
1549
+                continue;
1550
+            }
1551
+            $provider->userDeleted($uid, $type);
1552
+        }
1553
+    }
1554
+
1555
+    /**
1556
+     * @inheritdoc
1557
+     */
1558
+    public function groupDeleted($gid) {
1559
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1560
+        $provider->groupDeleted($gid);
1561
+
1562
+        $excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1563
+        if ($excludedGroups === '') {
1564
+            return;
1565
+        }
1566
+
1567
+        $excludedGroups = json_decode($excludedGroups, true);
1568
+        if (json_last_error() !== JSON_ERROR_NONE) {
1569
+            return;
1570
+        }
1571
+
1572
+        $excludedGroups = array_diff($excludedGroups, [$gid]);
1573
+        $this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1574
+    }
1575
+
1576
+    /**
1577
+     * @inheritdoc
1578
+     */
1579
+    public function userDeletedFromGroup($uid, $gid) {
1580
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1581
+        $provider->userDeletedFromGroup($uid, $gid);
1582
+    }
1583
+
1584
+    /**
1585
+     * Get access list to a path. This means
1586
+     * all the users that can access a given path.
1587
+     *
1588
+     * Consider:
1589
+     * -root
1590
+     * |-folder1 (23)
1591
+     *  |-folder2 (32)
1592
+     *   |-fileA (42)
1593
+     *
1594
+     * fileA is shared with user1 and user1@server1
1595
+     * folder2 is shared with group2 (user4 is a member of group2)
1596
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1597
+     *
1598
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1599
+     * [
1600
+     *  users  => [
1601
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1602
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1603
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1604
+     *  ],
1605
+     *  remote => [
1606
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1607
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1608
+     *  ],
1609
+     *  public => bool
1610
+     *  mail => bool
1611
+     * ]
1612
+     *
1613
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1614
+     * [
1615
+     *  users  => ['user1', 'user2', 'user4'],
1616
+     *  remote => bool,
1617
+     *  public => bool
1618
+     *  mail => bool
1619
+     * ]
1620
+     *
1621
+     * This is required for encryption/activity
1622
+     *
1623
+     * @param \OCP\Files\Node $path
1624
+     * @param bool $recursive Should we check all parent folders as well
1625
+     * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1626
+     * @return array
1627
+     */
1628
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1629
+        $owner = $path->getOwner();
1630
+
1631
+        if ($owner === null) {
1632
+            return [];
1633
+        }
1634
+
1635
+        $owner = $owner->getUID();
1636
+
1637
+        if ($currentAccess) {
1638
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1639
+        } else {
1640
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1641
+        }
1642
+        if (!$this->userManager->userExists($owner)) {
1643
+            return $al;
1644
+        }
1645
+
1646
+        //Get node for the owner and correct the owner in case of external storages
1647
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1648
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1649
+            $nodes = $userFolder->getById($path->getId());
1650
+            $path = array_shift($nodes);
1651
+            if ($path->getOwner() === null) {
1652
+                return [];
1653
+            }
1654
+            $owner = $path->getOwner()->getUID();
1655
+        }
1656
+
1657
+        $providers = $this->factory->getAllProviders();
1658
+
1659
+        /** @var Node[] $nodes */
1660
+        $nodes = [];
1661
+
1662
+
1663
+        if ($currentAccess) {
1664
+            $ownerPath = $path->getPath();
1665
+            $ownerPath = explode('/', $ownerPath, 4);
1666
+            if (count($ownerPath) < 4) {
1667
+                $ownerPath = '';
1668
+            } else {
1669
+                $ownerPath = $ownerPath[3];
1670
+            }
1671
+            $al['users'][$owner] = [
1672
+                'node_id' => $path->getId(),
1673
+                'node_path' => '/' . $ownerPath,
1674
+            ];
1675
+        } else {
1676
+            $al['users'][] = $owner;
1677
+        }
1678
+
1679
+        // Collect all the shares
1680
+        while ($path->getPath() !== $userFolder->getPath()) {
1681
+            $nodes[] = $path;
1682
+            if (!$recursive) {
1683
+                break;
1684
+            }
1685
+            $path = $path->getParent();
1686
+        }
1687
+
1688
+        foreach ($providers as $provider) {
1689
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1690
+
1691
+            foreach ($tmp as $k => $v) {
1692
+                if (isset($al[$k])) {
1693
+                    if (is_array($al[$k])) {
1694
+                        if ($currentAccess) {
1695
+                            $al[$k] += $v;
1696
+                        } else {
1697
+                            $al[$k] = array_merge($al[$k], $v);
1698
+                            $al[$k] = array_unique($al[$k]);
1699
+                            $al[$k] = array_values($al[$k]);
1700
+                        }
1701
+                    } else {
1702
+                        $al[$k] = $al[$k] || $v;
1703
+                    }
1704
+                } else {
1705
+                    $al[$k] = $v;
1706
+                }
1707
+            }
1708
+        }
1709
+
1710
+        return $al;
1711
+    }
1712
+
1713
+    /**
1714
+     * Create a new share
1715
+     *
1716
+     * @return IShare
1717
+     */
1718
+    public function newShare() {
1719
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1720
+    }
1721
+
1722
+    /**
1723
+     * Is the share API enabled
1724
+     *
1725
+     * @return bool
1726
+     */
1727
+    public function shareApiEnabled() {
1728
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1729
+    }
1730
+
1731
+    /**
1732
+     * Is public link sharing enabled
1733
+     *
1734
+     * @return bool
1735
+     */
1736
+    public function shareApiAllowLinks() {
1737
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1738
+    }
1739
+
1740
+    /**
1741
+     * Is password on public link requires
1742
+     *
1743
+     * @return bool
1744
+     */
1745
+    public function shareApiLinkEnforcePassword() {
1746
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1747
+    }
1748
+
1749
+    /**
1750
+     * Is default link expire date enabled
1751
+     *
1752
+     * @return bool
1753
+     */
1754
+    public function shareApiLinkDefaultExpireDate() {
1755
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1756
+    }
1757
+
1758
+    /**
1759
+     * Is default link expire date enforced
1760
+     *`
1761
+     * @return bool
1762
+     */
1763
+    public function shareApiLinkDefaultExpireDateEnforced() {
1764
+        return $this->shareApiLinkDefaultExpireDate() &&
1765
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1766
+    }
1767
+
1768
+
1769
+    /**
1770
+     * Number of default link expire days
1771
+     * @return int
1772
+     */
1773
+    public function shareApiLinkDefaultExpireDays() {
1774
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1775
+    }
1776
+
1777
+    /**
1778
+     * Is default internal expire date enabled
1779
+     *
1780
+     * @return bool
1781
+     */
1782
+    public function shareApiInternalDefaultExpireDate(): bool {
1783
+        return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1784
+    }
1785
+
1786
+    /**
1787
+     * Is default expire date enforced
1788
+     *`
1789
+     * @return bool
1790
+     */
1791
+    public function shareApiInternalDefaultExpireDateEnforced(): bool {
1792
+        return $this->shareApiInternalDefaultExpireDate() &&
1793
+            $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1794
+    }
1795
+
1796
+
1797
+    /**
1798
+     * Number of default expire days
1799
+     * @return int
1800
+     */
1801
+    public function shareApiInternalDefaultExpireDays(): int {
1802
+        return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1803
+    }
1804
+
1805
+    /**
1806
+     * Allow public upload on link shares
1807
+     *
1808
+     * @return bool
1809
+     */
1810
+    public function shareApiLinkAllowPublicUpload() {
1811
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1812
+    }
1813
+
1814
+    /**
1815
+     * check if user can only share with group members
1816
+     * @return bool
1817
+     */
1818
+    public function shareWithGroupMembersOnly() {
1819
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1820
+    }
1821
+
1822
+    /**
1823
+     * Check if users can share with groups
1824
+     * @return bool
1825
+     */
1826
+    public function allowGroupSharing() {
1827
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1828
+    }
1829
+
1830
+    public function allowEnumeration(): bool {
1831
+        return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1832
+    }
1833
+
1834
+    public function limitEnumerationToGroups(): bool {
1835
+        return $this->allowEnumeration() &&
1836
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1837
+    }
1838
+
1839
+    public function limitEnumerationToPhone(): bool {
1840
+        return $this->allowEnumeration() &&
1841
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
1842
+    }
1843
+
1844
+    public function allowEnumerationFullMatch(): bool {
1845
+        return $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match', 'yes') === 'yes';
1846
+    }
1847
+
1848
+    /**
1849
+     * Copied from \OC_Util::isSharingDisabledForUser
1850
+     *
1851
+     * TODO: Deprecate fuction from OC_Util
1852
+     *
1853
+     * @param string $userId
1854
+     * @return bool
1855
+     */
1856
+    public function sharingDisabledForUser($userId) {
1857
+        if ($userId === null) {
1858
+            return false;
1859
+        }
1860
+
1861
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1862
+            return $this->sharingDisabledForUsersCache[$userId];
1863
+        }
1864
+
1865
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1866
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1867
+            $excludedGroups = json_decode($groupsList);
1868
+            if (is_null($excludedGroups)) {
1869
+                $excludedGroups = explode(',', $groupsList);
1870
+                $newValue = json_encode($excludedGroups);
1871
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1872
+            }
1873
+            $user = $this->userManager->get($userId);
1874
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1875
+            if (!empty($usersGroups)) {
1876
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1877
+                // if the user is only in groups which are disabled for sharing then
1878
+                // sharing is also disabled for the user
1879
+                if (empty($remainingGroups)) {
1880
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1881
+                    return true;
1882
+                }
1883
+            }
1884
+        }
1885
+
1886
+        $this->sharingDisabledForUsersCache[$userId] = false;
1887
+        return false;
1888
+    }
1889
+
1890
+    /**
1891
+     * @inheritdoc
1892
+     */
1893
+    public function outgoingServer2ServerSharesAllowed() {
1894
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1895
+    }
1896
+
1897
+    /**
1898
+     * @inheritdoc
1899
+     */
1900
+    public function outgoingServer2ServerGroupSharesAllowed() {
1901
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1902
+    }
1903
+
1904
+    /**
1905
+     * @inheritdoc
1906
+     */
1907
+    public function shareProviderExists($shareType) {
1908
+        try {
1909
+            $this->factory->getProviderForType($shareType);
1910
+        } catch (ProviderException $e) {
1911
+            return false;
1912
+        }
1913
+
1914
+        return true;
1915
+    }
1916
+
1917
+    public function registerShareProvider(string $shareProviderClass): void {
1918
+        $this->factory->registerProvider($shareProviderClass);
1919
+    }
1920
+
1921
+    public function getAllShares(): iterable {
1922
+        $providers = $this->factory->getAllProviders();
1923
+
1924
+        foreach ($providers as $provider) {
1925
+            yield from $provider->getAllShares();
1926
+        }
1927
+    }
1928 1928
 }
Please login to merge, or discard this patch.