1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "ioloop.h"
5 #include "buffer.h"
6 #include "hash.h"
7 #include "hex-binary.h"
8 #include "crc32.h"
9 #include "sha1.h"
10 #include "hostpid.h"
11 #include "istream.h"
12 #include "mail-cache.h"
13 #include "mail-storage-private.h"
14 #include "message-id.h"
15 #include "message-part-data.h"
16 #include "imap-bodystructure.h"
17 
18 #include <time.h>
19 
mail_alloc(struct mailbox_transaction_context * t,enum mail_fetch_field wanted_fields,struct mailbox_header_lookup_ctx * wanted_headers)20 struct mail *mail_alloc(struct mailbox_transaction_context *t,
21 			enum mail_fetch_field wanted_fields,
22 			struct mailbox_header_lookup_ctx *wanted_headers)
23 {
24 	struct mail *mail;
25 
26 	i_assert(wanted_headers == NULL || wanted_headers->box == t->box);
27 
28 	T_BEGIN {
29 		mail = t->box->v.mail_alloc(t, wanted_fields, wanted_headers);
30 		hook_mail_allocated(mail);
31 	} T_END;
32 
33 	return mail;
34 }
35 
mail_free(struct mail ** mail)36 void mail_free(struct mail **mail)
37 {
38 	struct mail_private *p = (struct mail_private *)*mail;
39 
40 	/* make sure mailbox_search_*() users don't try to free the mail
41 	   directly */
42 	i_assert(!p->search_mail);
43 
44 	p->v.free(*mail);
45 	*mail = NULL;
46 }
47 
mail_set_seq(struct mail * mail,uint32_t seq)48 void mail_set_seq(struct mail *mail, uint32_t seq)
49 {
50 	struct mail_private *p = (struct mail_private *)mail;
51 
52 	T_BEGIN {
53 		p->v.set_seq(mail, seq, FALSE);
54 	} T_END;
55 }
56 
mail_set_seq_saving(struct mail * mail,uint32_t seq)57 void mail_set_seq_saving(struct mail *mail, uint32_t seq)
58 {
59 	struct mail_private *p = (struct mail_private *)mail;
60 
61 	T_BEGIN {
62 		p->v.set_seq(mail, seq, TRUE);
63 	} T_END;
64 }
65 
mail_set_uid(struct mail * mail,uint32_t uid)66 bool mail_set_uid(struct mail *mail, uint32_t uid)
67 {
68 	struct mail_private *p = (struct mail_private *)mail;
69 	bool ret;
70 
71 	T_BEGIN {
72 		ret = p->v.set_uid(mail, uid);
73 	} T_END;
74 	return ret;
75 }
76 
mail_prefetch(struct mail * mail)77 bool mail_prefetch(struct mail *mail)
78 {
79 	struct mail_private *p = (struct mail_private *)mail;
80 	bool ret;
81 
82 	T_BEGIN {
83 		ret = p->v.prefetch(mail);
84 	} T_END;
85 	return ret;
86 }
87 
mail_add_temp_wanted_fields(struct mail * mail,enum mail_fetch_field fields,struct mailbox_header_lookup_ctx * headers)88 void mail_add_temp_wanted_fields(struct mail *mail,
89 				 enum mail_fetch_field fields,
90 				 struct mailbox_header_lookup_ctx *headers)
91 {
92 	struct mail_private *p = (struct mail_private *)mail;
93 
94 	i_assert(headers == NULL || headers->box == mail->box);
95 
96 	p->v.add_temp_wanted_fields(mail, fields, headers);
97 }
98 
mail_get_flags(struct mail * mail)99 enum mail_flags mail_get_flags(struct mail *mail)
100 {
101 	struct mail_private *p = (struct mail_private *)mail;
102 
103 	return p->v.get_flags(mail);
104 }
105 
mail_get_modseq(struct mail * mail)106 uint64_t mail_get_modseq(struct mail *mail)
107 {
108 	struct mail_private *p = (struct mail_private *)mail;
109 
110 	return p->v.get_modseq(mail);
111 }
112 
mail_get_pvt_modseq(struct mail * mail)113 uint64_t mail_get_pvt_modseq(struct mail *mail)
114 {
115 	struct mail_private *p = (struct mail_private *)mail;
116 
117 	return p->v.get_pvt_modseq(mail);
118 }
119 
mail_get_keywords(struct mail * mail)120 const char *const *mail_get_keywords(struct mail *mail)
121 {
122 	struct mail_private *p = (struct mail_private *)mail;
123 
124 	return p->v.get_keywords(mail);
125 }
126 
ARRAY_TYPE(keyword_indexes)127 const ARRAY_TYPE(keyword_indexes) *mail_get_keyword_indexes(struct mail *mail)
128 {
129 	struct mail_private *p = (struct mail_private *)mail;
130 
131 	return p->v.get_keyword_indexes(mail);
132 }
133 
mail_get_parts(struct mail * mail,struct message_part ** parts_r)134 int mail_get_parts(struct mail *mail, struct message_part **parts_r)
135 {
136 	struct mail_private *p = (struct mail_private *)mail;
137 	int ret;
138 
139 	T_BEGIN {
140 		ret = p->v.get_parts(mail, parts_r);
141 	} T_END;
142 	return ret;
143 }
144 
mail_get_date(struct mail * mail,time_t * date_r,int * timezone_r)145 int mail_get_date(struct mail *mail, time_t *date_r, int *timezone_r)
146 {
147 	struct mail_private *p = (struct mail_private *)mail;
148 	int ret;
149 
150 	T_BEGIN {
151 		ret = p->v.get_date(mail, date_r, timezone_r);
152 	} T_END;
153 	return ret;
154 }
155 
mail_get_received_date(struct mail * mail,time_t * date_r)156 int mail_get_received_date(struct mail *mail, time_t *date_r)
157 {
158 	struct mail_private *p = (struct mail_private *)mail;
159 	int ret;
160 
161 	T_BEGIN {
162 		ret = p->v.get_received_date(mail, date_r);
163 	} T_END;
164 	return ret;
165 }
166 
mail_get_save_date(struct mail * mail,time_t * date_r)167 int mail_get_save_date(struct mail *mail, time_t *date_r)
168 {
169 	struct mail_private *p = (struct mail_private *)mail;
170 	int ret;
171 
172 	T_BEGIN {
173 		ret = p->v.get_save_date(mail, date_r);
174 	} T_END;
175 	return ret;
176 }
177 
mail_get_virtual_size(struct mail * mail,uoff_t * size_r)178 int mail_get_virtual_size(struct mail *mail, uoff_t *size_r)
179 {
180 	struct mail_private *p = (struct mail_private *)mail;
181 	int ret;
182 
183 	T_BEGIN {
184 		ret = p->v.get_virtual_size(mail, size_r);
185 	} T_END;
186 	return ret;
187 }
188 
mail_get_physical_size(struct mail * mail,uoff_t * size_r)189 int mail_get_physical_size(struct mail *mail, uoff_t *size_r)
190 {
191 	struct mail_private *p = (struct mail_private *)mail;
192 	int ret;
193 
194 	T_BEGIN {
195 		ret = p->v.get_physical_size(mail, size_r);
196 	} T_END;
197 	return ret;
198 }
199 
mail_get_first_header(struct mail * mail,const char * field,const char ** value_r)200 int mail_get_first_header(struct mail *mail, const char *field,
201 			  const char **value_r)
202 {
203 	struct mail_private *p = (struct mail_private *)mail;
204 	int ret;
205 
206 	T_BEGIN {
207 		ret = p->v.get_first_header(mail, field, FALSE, value_r);
208 	} T_END;
209 	return ret;
210 }
211 
mail_get_first_header_utf8(struct mail * mail,const char * field,const char ** value_r)212 int mail_get_first_header_utf8(struct mail *mail, const char *field,
213 			       const char **value_r)
214 {
215 	struct mail_private *p = (struct mail_private *)mail;
216 	int ret;
217 
218 	T_BEGIN {
219 		ret = p->v.get_first_header(mail, field, TRUE, value_r);
220 	} T_END;
221 	return ret;
222 }
223 
mail_get_headers(struct mail * mail,const char * field,const char * const ** value_r)224 int mail_get_headers(struct mail *mail, const char *field,
225 		     const char *const **value_r)
226 {
227 	struct mail_private *p = (struct mail_private *)mail;
228 	int ret;
229 
230 	T_BEGIN {
231 		ret = p->v.get_headers(mail, field, FALSE, value_r);
232 	} T_END;
233 	return ret;
234 }
235 
mail_get_headers_utf8(struct mail * mail,const char * field,const char * const ** value_r)236 int mail_get_headers_utf8(struct mail *mail, const char *field,
237 			  const char *const **value_r)
238 {
239 	struct mail_private *p = (struct mail_private *)mail;
240 	int ret;
241 
242 	T_BEGIN {
243 		ret = p->v.get_headers(mail, field, TRUE, value_r);
244 	} T_END;
245 	return ret;
246 }
247 
mail_get_header_stream(struct mail * mail,struct mailbox_header_lookup_ctx * headers,struct istream ** stream_r)248 int mail_get_header_stream(struct mail *mail,
249 			   struct mailbox_header_lookup_ctx *headers,
250 			   struct istream **stream_r)
251 {
252 	struct mail_private *p = (struct mail_private *)mail;
253 	int ret;
254 
255 	i_assert(headers->count > 0);
256 	i_assert(headers->box == mail->box);
257 
258 	T_BEGIN {
259 		ret = p->v.get_header_stream(mail, headers, stream_r);
260 	} T_END;
261 	return ret;
262 }
263 
mail_set_aborted(struct mail * mail)264 void mail_set_aborted(struct mail *mail)
265 {
266 	mail_storage_set_error(mail->box->storage, MAIL_ERROR_LOOKUP_ABORTED,
267 			       "Mail field not cached");
268 }
269 
mail_get_stream(struct mail * mail,struct message_size * hdr_size,struct message_size * body_size,struct istream ** stream_r)270 int mail_get_stream(struct mail *mail, struct message_size *hdr_size,
271 		    struct message_size *body_size, struct istream **stream_r)
272 {
273 	return mail_get_stream_because(mail, hdr_size, body_size,
274 				       "mail stream", stream_r);
275 }
276 
mail_get_stream_because(struct mail * mail,struct message_size * hdr_size,struct message_size * body_size,const char * reason,struct istream ** stream_r)277 int mail_get_stream_because(struct mail *mail, struct message_size *hdr_size,
278 			    struct message_size *body_size,
279 			    const char *reason, struct istream **stream_r)
280 {
281 	struct mail_private *p = (struct mail_private *)mail;
282 	int ret;
283 
284 	if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
285 		mail_set_aborted(mail);
286 		return -1;
287 	}
288 	T_BEGIN {
289 		p->get_stream_reason = reason;
290 		ret = p->v.get_stream(mail, TRUE, hdr_size, body_size, stream_r);
291 		p->get_stream_reason = "";
292 	} T_END;
293 	i_assert(ret < 0 || (*stream_r)->blocking);
294 	return ret;
295 }
296 
mail_get_hdr_stream(struct mail * mail,struct message_size * hdr_size,struct istream ** stream_r)297 int mail_get_hdr_stream(struct mail *mail, struct message_size *hdr_size,
298 			struct istream **stream_r)
299 {
300 	return mail_get_hdr_stream_because(mail, hdr_size, "header stream", stream_r);
301 }
302 
mail_get_hdr_stream_because(struct mail * mail,struct message_size * hdr_size,const char * reason,struct istream ** stream_r)303 int mail_get_hdr_stream_because(struct mail *mail,
304 				struct message_size *hdr_size,
305 				const char *reason, struct istream **stream_r)
306 {
307 	struct mail_private *p = (struct mail_private *)mail;
308 	int ret;
309 
310 	if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
311 		mail_set_aborted(mail);
312 		return -1;
313 	}
314 	T_BEGIN {
315 		p->get_stream_reason = reason;
316 		ret = p->v.get_stream(mail, FALSE, hdr_size, NULL, stream_r);
317 		p->get_stream_reason = "";
318 	} T_END;
319 	i_assert(ret < 0 || (*stream_r)->blocking);
320 	return ret;
321 }
322 
mail_get_binary_stream(struct mail * mail,const struct message_part * part,bool include_hdr,uoff_t * size_r,bool * binary_r,struct istream ** stream_r)323 int mail_get_binary_stream(struct mail *mail, const struct message_part *part,
324 			   bool include_hdr, uoff_t *size_r,
325 			   bool *binary_r, struct istream **stream_r)
326 {
327 	struct mail_private *p = (struct mail_private *)mail;
328 	int ret;
329 
330 	if (mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER) {
331 		mail_set_aborted(mail);
332 		return -1;
333 	}
334 	T_BEGIN {
335 		ret = p->v.get_binary_stream(mail, part, include_hdr,
336 					     size_r, NULL, binary_r, stream_r);
337 	} T_END;
338 	i_assert(ret < 0 || (*stream_r)->blocking);
339 	return ret;
340 }
341 
mail_get_binary_size(struct mail * mail,const struct message_part * part,bool include_hdr,uoff_t * size_r,unsigned int * lines_r)342 int mail_get_binary_size(struct mail *mail, const struct message_part *part,
343 			 bool include_hdr, uoff_t *size_r,
344 			 unsigned int *lines_r)
345 {
346 	struct mail_private *p = (struct mail_private *)mail;
347 	bool binary;
348 	int ret;
349 
350 	T_BEGIN {
351 		ret = p->v.get_binary_stream(mail, part, include_hdr,
352 					     size_r, lines_r, &binary, NULL);
353 	} T_END;
354 	return ret;
355 }
356 
mail_get_special(struct mail * mail,enum mail_fetch_field field,const char ** value_r)357 int mail_get_special(struct mail *mail, enum mail_fetch_field field,
358 		     const char **value_r)
359 {
360 	struct mail_private *p = (struct mail_private *)mail;
361 
362 	if (p->v.get_special(mail, field, value_r) < 0)
363 		return -1;
364 	i_assert(*value_r != NULL);
365 	return 0;
366 }
367 
mail_get_backend_mail(struct mail * mail,struct mail ** real_mail_r)368 int mail_get_backend_mail(struct mail *mail, struct mail **real_mail_r)
369 {
370 	struct mail_private *p = (struct mail_private *)mail;
371 	return p->v.get_backend_mail(mail, real_mail_r);
372 }
373 
mail_get_message_id(struct mail * mail,const char ** value_r)374 int mail_get_message_id(struct mail *mail, const char **value_r)
375 {
376 	const char *hdr_value, *msgid_bare;
377 	int ret;
378 
379 	*value_r = NULL;
380 
381 	ret = mail_get_first_header(mail, "Message-ID", &hdr_value);
382 	if (ret <= 0)
383 		return ret;
384 
385 	msgid_bare = message_id_get_next(&hdr_value);
386 	if (msgid_bare == NULL)
387 		return 0;
388 
389 	/* Complete the message ID with surrounding `<' and `>'. */
390 	*value_r = t_strconcat("<",  msgid_bare, ">", NULL);
391 	return 1;
392 }
393 
mail_update_flags(struct mail * mail,enum modify_type modify_type,enum mail_flags flags)394 void mail_update_flags(struct mail *mail, enum modify_type modify_type,
395 		       enum mail_flags flags)
396 {
397 	struct mail_private *p = (struct mail_private *)mail;
398 
399 	p->v.update_flags(mail, modify_type, flags);
400 }
401 
mail_update_keywords(struct mail * mail,enum modify_type modify_type,struct mail_keywords * keywords)402 void mail_update_keywords(struct mail *mail, enum modify_type modify_type,
403 			  struct mail_keywords *keywords)
404 {
405 	struct mail_private *p = (struct mail_private *)mail;
406 
407 	p->v.update_keywords(mail, modify_type, keywords);
408 }
409 
mail_update_modseq(struct mail * mail,uint64_t min_modseq)410 void mail_update_modseq(struct mail *mail, uint64_t min_modseq)
411 {
412 	struct mail_private *p = (struct mail_private *)mail;
413 
414 	p->v.update_modseq(mail, min_modseq);
415 }
416 
mail_update_pvt_modseq(struct mail * mail,uint64_t min_pvt_modseq)417 void mail_update_pvt_modseq(struct mail *mail, uint64_t min_pvt_modseq)
418 {
419 	struct mail_private *p = (struct mail_private *)mail;
420 
421 	p->v.update_pvt_modseq(mail, min_pvt_modseq);
422 }
423 
mail_update_pop3_uidl(struct mail * mail,const char * uidl)424 void mail_update_pop3_uidl(struct mail *mail, const char *uidl)
425 {
426 	struct mail_private *p = (struct mail_private *)mail;
427 
428 	if (p->v.update_pop3_uidl != NULL)
429 		p->v.update_pop3_uidl(mail, uidl);
430 }
431 
mail_expunge(struct mail * mail)432 void mail_expunge(struct mail *mail)
433 {
434 	struct mail_private *p = (struct mail_private *)mail;
435 
436 	T_BEGIN {
437 		p->v.expunge(mail);
438 	} T_END;
439 	mail_expunge_requested_event(mail);
440 }
441 
mail_autoexpunge(struct mail * mail)442 void mail_autoexpunge(struct mail *mail)
443 {
444 	struct mail_private *p = (struct mail_private *)mail;
445 	p->autoexpunged = TRUE;
446 	mail_expunge(mail);
447 	p->autoexpunged = FALSE;
448 }
449 
mail_set_expunged(struct mail * mail)450 void mail_set_expunged(struct mail *mail)
451 {
452 	mail_storage_set_error(mail->box->storage, MAIL_ERROR_EXPUNGED,
453 			       "Message was expunged");
454 	mail->expunged = TRUE;
455 }
456 
mail_precache(struct mail * mail)457 int mail_precache(struct mail *mail)
458 {
459 	struct mail_private *p = (struct mail_private *)mail;
460 	int ret;
461 
462 	T_BEGIN {
463 		ret = p->v.precache(mail);
464 	} T_END;
465 	return ret;
466 }
467 
mail_set_cache_corrupted(struct mail * mail,enum mail_fetch_field field,const char * reason)468 void mail_set_cache_corrupted(struct mail *mail,
469 			      enum mail_fetch_field field,
470 			      const char *reason)
471 {
472 	struct mail_private *p = (struct mail_private *)mail;
473 	p->v.set_cache_corrupted(mail, field, reason);
474 }
475 
mail_generate_guid_128_hash(const char * guid,guid_128_t guid_128_r)476 void mail_generate_guid_128_hash(const char *guid, guid_128_t guid_128_r)
477 {
478 	unsigned char sha1_sum[SHA1_RESULTLEN];
479 	buffer_t buf;
480 
481 	if (guid_128_from_string(guid, guid_128_r) < 0) {
482 		/* not 128bit hex. use a hash of it instead. */
483 		buffer_create_from_data(&buf, guid_128_r, GUID_128_SIZE);
484 		buffer_set_used_size(&buf, 0);
485 		sha1_get_digest(guid, strlen(guid), sha1_sum);
486 #if SHA1_RESULTLEN < GUID_128_SIZE
487 #  error not possible
488 #endif
489 		buffer_append(&buf,
490 			      sha1_sum + SHA1_RESULTLEN - GUID_128_SIZE,
491 			      GUID_128_SIZE);
492 	}
493 }
494 
495 static bool
mail_message_has_attachment(struct message_part * part,const struct message_part_attachment_settings * set)496 mail_message_has_attachment(struct message_part *part,
497 			    const struct message_part_attachment_settings *set)
498 {
499 	for (; part != NULL; part = part->next) {
500 		if (message_part_is_attachment(part, set) ||
501 		    mail_message_has_attachment(part->children, set))
502 			return TRUE;
503 	}
504 
505 	return FALSE;
506 }
507 
mail_has_attachment_keywords(struct mail * mail)508 bool mail_has_attachment_keywords(struct mail *mail)
509 {
510 	const char *const *kw = mail_get_keywords(mail);
511 	return (str_array_icase_find(kw, MAIL_KEYWORD_HAS_ATTACHMENT) !=
512 		str_array_icase_find(kw, MAIL_KEYWORD_HAS_NO_ATTACHMENT));
513 }
514 
mail_parse_parts(struct mail * mail,struct message_part ** parts_r)515 static int mail_parse_parts(struct mail *mail, struct message_part **parts_r)
516 {
517 	const char *structure, *error;
518 	struct mail_private *pmail = (struct mail_private*)mail;
519 
520 	/* need to get bodystructure first */
521 	if (mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
522 			     &structure) < 0) {
523 		/* Don't bother logging an error. See
524 		   mail_set_attachment_keywords(). */
525 		return -1;
526 	}
527 	if (imap_bodystructure_parse_full(structure, pmail->data_pool, parts_r,
528 					  &error) < 0) {
529 		mail_set_cache_corrupted(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE,
530 					 error);
531 		return -1;
532 	}
533 	return 0;
534 }
535 
mail_set_attachment_keywords(struct mail * mail)536 int mail_set_attachment_keywords(struct mail *mail)
537 {
538 	int ret;
539 	const struct mail_storage_settings *mail_set =
540 		mail_storage_get_settings(mailbox_get_storage(mail->box));
541 
542 	const char *const keyword_has_attachment[] = {
543 		MAIL_KEYWORD_HAS_ATTACHMENT,
544 		NULL,
545 	};
546 	const char *const keyword_has_no_attachment[] = {
547 		MAIL_KEYWORD_HAS_NO_ATTACHMENT,
548 		NULL
549 	};
550 	struct message_part_attachment_settings set = {
551 		.content_type_filter =
552 			mail_set->parsed_mail_attachment_content_type_filter,
553 		.exclude_inlined =
554 			mail_set->parsed_mail_attachment_exclude_inlined,
555 	};
556 	struct mail_keywords *kw_has = NULL, *kw_has_not = NULL;
557 
558 	/* walk all parts and see if there is an attachment */
559 	struct message_part *parts;
560 	if (mail_get_parts(mail, &parts) < 0) {
561 		/* Callers don't really care about the exact error, and
562 		   critical errors were already logged. Most importantly we
563 		   don't want to log MAIL_ERROR_LOOKUP_ABORTED since that is
564 		   an expected error. */
565 		ret = -1;
566 	} else if (parts->data == NULL &&
567 		   mail_parse_parts(mail, &parts) < 0) {
568 		ret = -1;
569 	} else if (mailbox_keywords_create(mail->box, keyword_has_attachment, &kw_has) < 0 ||
570 		   mailbox_keywords_create(mail->box, keyword_has_no_attachment, &kw_has_not) < 0) {
571 		mail_set_critical(mail, "Failed to add attachment keywords: "
572 				  "mailbox_keywords_create(%s) failed: %s",
573 				  mailbox_get_vname(mail->box),
574 				  mail_storage_get_last_internal_error(mail->box->storage, NULL));
575 		ret = -1;
576 	} else {
577 		bool has_attachment = mail_message_has_attachment(parts, &set);
578 
579 		/* make sure only one of the keywords gets set */
580 		mail_update_keywords(mail, MODIFY_REMOVE, has_attachment ? kw_has_not : kw_has);
581 		mail_update_keywords(mail, MODIFY_ADD, has_attachment ? kw_has : kw_has_not);
582 		ret = has_attachment ? 1 : 0;
583 	}
584 
585 	if (kw_has != NULL)
586 		mailbox_keywords_unref(&kw_has);
587 	if (kw_has_not != NULL)
588 		mailbox_keywords_unref(&kw_has_not);
589 
590 	return ret;
591 }
592 
mail_opened_event(struct mail * mail)593 void mail_opened_event(struct mail *mail)
594 {
595 	struct mail_private *pmail =
596 		container_of(mail, struct mail_private, mail);
597 	struct event_passthrough *e = event_create_passthrough(mail->event)->
598 		set_name("mail_opened")->
599 		add_str("reason", pmail->get_stream_reason);
600 	if (pmail->get_stream_reason != NULL)
601 		e_debug(e->event(), "Opened mail because: %s",
602 			pmail->get_stream_reason);
603 	else
604 		e_debug(e->event(), "Opened mail");
605 }
606 
mail_expunge_requested_event(struct mail * mail)607 void mail_expunge_requested_event(struct mail *mail)
608 {
609 	struct event_passthrough *e = event_create_passthrough(mail->event)->
610 		set_name("mail_expunge_requested")->
611 		add_int("uid", mail->uid)->
612 		add_int("seq", mail->seq);
613 	e_debug(e->event(), "Expunge requested");
614 }
615