Example #1
0
static void imapc_sync_index_flags(struct imapc_sync_context *ctx,
				   const struct mail_index_sync_rec *sync_rec)
{
	string_t *str = t_str_new(128);

	i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);

	if (sync_rec->add_flags != 0) {
		i_assert((sync_rec->add_flags & MAIL_RECENT) == 0);
		str_printfa(str, "UID STORE %u:%u +FLAGS (",
			    sync_rec->uid1, sync_rec->uid2);
		imap_write_flags(str, sync_rec->add_flags, NULL);
		str_append_c(str, ')');
		imapc_sync_cmd(ctx, str_c(str));
	}

	if (sync_rec->remove_flags != 0) {
		i_assert((sync_rec->remove_flags & MAIL_RECENT) == 0);
		str_truncate(str, 0);
		str_printfa(str, "UID STORE %u:%u -FLAGS (",
			    sync_rec->uid1, sync_rec->uid2);
		imap_write_flags(str, sync_rec->remove_flags, NULL);
		str_append_c(str, ')');
		imapc_sync_cmd(ctx, str_c(str));
	}
}
Example #2
0
void client_send_mailbox_flags(struct client *client, bool selecting)
{
	struct mailbox_status status;
	unsigned int count = array_count(client->keywords.names);
	const char *const *keywords;
	string_t *str;

	if (!selecting && count == client->keywords.announce_count) {
		/* no changes to keywords and we're not selecting a mailbox */
		return;
	}

	client->keywords.announce_count = count;
	mailbox_get_open_status(client->mailbox, STATUS_PERMANENT_FLAGS,
				&status);

	keywords = count == 0 ? NULL :
		array_idx(client->keywords.names, 0);
	str = t_str_new(128);
	str_append(str, "* FLAGS (");
	imap_write_flags(str, MAIL_FLAGS_NONRECENT, keywords);
	str_append_c(str, ')');
	client_send_line(client, str_c(str));

	if (!status.permanent_keywords)
		keywords = NULL;

	str_truncate(str, 0);
	str_append(str, "* OK [PERMANENTFLAGS (");
	imap_write_flags(str, status.permanent_flags, keywords);
	if (status.allow_new_keywords) {
		if (status.permanent_flags != 0 || keywords != NULL)
			str_append_c(str, ' ');
		str_append(str, "\\*");
	}
	str_append(str, ")] ");

	if (mailbox_is_readonly(client->mailbox))
		str_append(str, "Read-only mailbox.");
	else
		str_append(str, "Flags permitted.");
	client_send_line(client, str_c(str));
}
bool mail_search_arg_to_imap(string_t *dest, const struct mail_search_arg *arg,
			     const char **error_r)
{
	unsigned int start_pos;

	if (arg->match_not)
		str_append(dest, "NOT ");
	start_pos = str_len(dest);
	switch (arg->type) {
	case SEARCH_OR:
		if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
						 "OR ", error_r))
			return FALSE;
		break;
	case SEARCH_SUB:
		if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
						 "", error_r))
			return FALSE;
		break;
	case SEARCH_ALL:
		str_append(dest, "ALL");
		break;
	case SEARCH_SEQSET:
		imap_write_seq_range(dest, &arg->value.seqset);
		break;
	case SEARCH_UIDSET:
		str_append(dest, "UID ");
		imap_write_seq_range(dest, &arg->value.seqset);
		break;
	case SEARCH_FLAGS:
		i_assert((arg->value.flags & MAIL_FLAGS_MASK) != 0);
		str_append_c(dest, '(');
		if ((arg->value.flags & MAIL_ANSWERED) != 0)
			str_append(dest, "ANSWERED ");
		if ((arg->value.flags & MAIL_FLAGGED) != 0)
			str_append(dest, "FLAGGED ");
		if ((arg->value.flags & MAIL_DELETED) != 0)
			str_append(dest, "DELETED ");
		if ((arg->value.flags & MAIL_SEEN) != 0)
			str_append(dest, "SEEN ");
		if ((arg->value.flags & MAIL_DRAFT) != 0)
			str_append(dest, "DRAFT ");
		if ((arg->value.flags & MAIL_RECENT) != 0)
			str_append(dest, "RECENT ");
		str_truncate(dest, str_len(dest)-1);
		str_append_c(dest, ')');
		break;
	case SEARCH_KEYWORDS: {
		const struct mail_keywords *kw = arg->value.keywords;
		const ARRAY_TYPE(keywords) *names_arr;
		const char *const *namep;
		unsigned int i;

		if (kw == NULL) {
			/* uninitialized */
			str_printfa(dest, "KEYWORD %s", arg->value.str);
			break;
		}

		names_arr = mail_index_get_keywords(kw->index);

		str_append_c(dest, '(');
		for (i = 0; i < kw->count; i++) {
			namep = array_idx(names_arr, kw->idx[i]);
			if (i > 0)
				str_append_c(dest, ' ');
			str_printfa(dest, "KEYWORD %s", *namep);
		}
		str_append_c(dest, ')');
		break;
	}

	case SEARCH_BEFORE:
		switch (arg->value.date_type) {
		case MAIL_SEARCH_DATE_TYPE_SENT:
			str_append(dest, "SENTBEFORE");
			break;
		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
			str_append(dest, "BEFORE");
			break;
		case MAIL_SEARCH_DATE_TYPE_SAVED:
			str_append(dest, "X-SAVEDBEFORE");
			break;
		}
		if (mail_search_arg_to_imap_date(dest, arg))
			;
		else if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_RECEIVED ||
			 arg->value.time > ioloop_time) {
			*error_r = t_strdup_printf(
				"SEARCH_BEFORE can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
				(long)arg->value.time, arg->value.date_type,
				(arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
			return FALSE;
		} else {
			str_truncate(dest, start_pos);
			str_printfa(dest, "OLDER %u",
				    (unsigned int)(ioloop_time - arg->value.time + 1));
		}
		break;
	case SEARCH_ON:
		switch (arg->value.date_type) {
		case MAIL_SEARCH_DATE_TYPE_SENT:
			str_append(dest, "SENTON");
			break;
		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
			str_append(dest, "ON");
			break;
		case MAIL_SEARCH_DATE_TYPE_SAVED:
			str_append(dest, "X-SAVEDON");
			break;
		}
		if (!mail_search_arg_to_imap_date(dest, arg)) {
			*error_r = t_strdup_printf(
				"SEARCH_ON can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
				(long)arg->value.time, arg->value.date_type,
				(arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
			return FALSE;
		}
		break;
	case SEARCH_SINCE:
		switch (arg->value.date_type) {
		case MAIL_SEARCH_DATE_TYPE_SENT:
			str_append(dest, "SENTSINCE");
			break;
		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
			str_append(dest, "SINCE");
			break;
		case MAIL_SEARCH_DATE_TYPE_SAVED:
			str_append(dest, "X-SAVEDSINCE");
			break;
		}
		if (mail_search_arg_to_imap_date(dest, arg))
			;
		else if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_RECEIVED ||
			 arg->value.time >= ioloop_time) {
			*error_r = t_strdup_printf(
				"SEARCH_SINCE can't be written as IMAP for timestamp %ld (type=%d, use_tz=%d)",
				(long)arg->value.time, arg->value.date_type,
				(arg->value.search_flags & MAIL_SEARCH_ARG_FLAG_USE_TZ) != 0);
			return FALSE;
		} else {
			str_truncate(dest, start_pos);
			str_printfa(dest, "YOUNGER %u",
				    (unsigned int)(ioloop_time - arg->value.time));
		}
		break;
	case SEARCH_SMALLER:
		str_printfa(dest, "SMALLER %llu", (unsigned long long)arg->value.size);
		break;
	case SEARCH_LARGER:
		str_printfa(dest, "LARGER %llu", (unsigned long long)arg->value.size);
		break;
	case SEARCH_HEADER:
	case SEARCH_HEADER_ADDRESS:
	case SEARCH_HEADER_COMPRESS_LWSP:
		if (strcasecmp(arg->hdr_field_name, "From") == 0 ||
		    strcasecmp(arg->hdr_field_name, "To") == 0 ||
		    strcasecmp(arg->hdr_field_name, "Cc") == 0 ||
		    strcasecmp(arg->hdr_field_name, "Bcc") == 0 ||
		    strcasecmp(arg->hdr_field_name, "Subject") == 0)
			str_append(dest, t_str_ucase(arg->hdr_field_name));
		else {
			str_append(dest, "HEADER ");
			imap_append_astring(dest, arg->hdr_field_name);
		}
		str_append_c(dest, ' ');
		imap_append_astring(dest, arg->value.str);
		break;

	case SEARCH_BODY:
		str_append(dest, "BODY ");
		imap_append_astring(dest, arg->value.str);
		break;
	case SEARCH_TEXT:
		str_append(dest, "TEXT ");
		imap_append_astring(dest, arg->value.str);
		break;

	/* extensions */
	case SEARCH_MODSEQ: {
		bool extended_output = FALSE;

		str_append(dest, "MODSEQ ");
		if (arg->value.str != NULL) {
			str_printfa(dest, "/flags/%s", arg->value.str);
			extended_output = TRUE;
		} else if (arg->value.flags != 0) {
			str_append(dest, "/flags/");
			imap_write_flags(dest, arg->value.flags, NULL);
			extended_output = TRUE;
		}
		if (extended_output) {
			str_append_c(dest, ' ');
			switch (arg->value.modseq->type) {
			case MAIL_SEARCH_MODSEQ_TYPE_ANY:
				str_append(dest, "all");
				break;
			case MAIL_SEARCH_MODSEQ_TYPE_PRIVATE:
				str_append(dest, "priv");
				break;
			case MAIL_SEARCH_MODSEQ_TYPE_SHARED:
				str_append(dest, "shared");
				break;
			}
			str_append_c(dest, ' ');
		}
		str_printfa(dest, "%llu", (unsigned long long)arg->value.modseq->modseq);
		break;
	}
	case SEARCH_INTHREAD:
		str_append(dest, "INTHREAD ");
		imap_append_astring(dest, mail_thread_type_to_str(arg->value.thread_type));
		str_append_c(dest, ' ');
		if (!mail_search_subargs_to_imap(dest, arg->value.subargs,
						 "", error_r))
			return FALSE;
		break;
	case SEARCH_GUID:
		str_append(dest, "X-GUID ");
		imap_append_astring(dest, arg->value.str);
		break;
	case SEARCH_MAILBOX:
		*error_r = "SEARCH_MAILBOX can't be written as IMAP";
		return FALSE;
	case SEARCH_MAILBOX_GUID:
		*error_r = "SEARCH_MAILBOX_GUID can't be written as IMAP";
		return FALSE;
	case SEARCH_MAILBOX_GLOB:
		str_append(dest, "X-MAILBOX ");
		imap_append_astring(dest, arg->value.str);
		break;
	case SEARCH_REAL_UID:
		str_append(dest, "X-REAL-UID ");
		imap_write_seq_range(dest, &arg->value.seqset);
		break;
	}
	return TRUE;
}
Example #4
0
static void
mail_log_append_mail_message_real(struct mail_log_mail_txn_context *ctx,
				  struct mail *mail, enum mail_log_event event,
				  const char *desc)
{
	struct mail_log_user *muser =
		MAIL_LOG_USER_CONTEXT(mail->box->storage->user);
	struct mail_log_message *msg;
	string_t *text;
	uoff_t size;
	
	msg = p_new(ctx->pool, struct mail_log_message, 1);

	text = t_str_new(128);
	str_append(text, desc);
	str_append(text, ": ");
	if ((muser->fields & MAIL_LOG_FIELD_BOX) != 0) {
		mail_log_append_mailbox_name(text, mail);
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_UID) != 0) {
		if (event != MAIL_LOG_EVENT_SAVE &&
		    event != MAIL_LOG_EVENT_COPY)
			mail_log_append_uid(ctx, msg, text, mail->uid);
		else {
			/* with mbox mail->uid contains the uid, but handle
			   this consistently with all mailbox formats */
			mail_log_append_uid(ctx, msg, text, 0);
		}
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_MSGID) != 0) {
		mail_log_append_mail_header(text, mail, "msgid", "Message-ID");
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_PSIZE) != 0) {
		if (mail_get_physical_size(mail, &size) == 0)
			str_printfa(text, "size=%"PRIuUOFF_T, size);
		else
			str_printfa(text, "size=error");
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_VSIZE) != 0) {
		if (mail_get_virtual_size(mail, &size) == 0)
			str_printfa(text, "vsize=%"PRIuUOFF_T, size);
		else
			str_printfa(text, "vsize=error");
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_FROM) != 0) {
		mail_log_append_mail_header(text, mail, "from", "From");
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_SUBJECT) != 0) {
		mail_log_append_mail_header(text, mail, "subject", "Subject");
		str_append(text, ", ");
	}
	if ((muser->fields & MAIL_LOG_FIELD_FLAGS) != 0) {
		str_printfa(text, "flags=(");
		imap_write_flags(text, mail_get_flags(mail),
				 mail_get_keywords(mail));
		str_append(text, "), ");
	}
	str_truncate(text, str_len(text)-2);

	msg->event = event;
	msg->text = p_strdup(ctx->pool, str_c(text));
	DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg);
}