All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aoindustries.aoserv.client.email.CyrusImapdServer Maven / Gradle / Ivy

There is a newer version: 1.92.0
Show newest version
/*
 * aoserv-client - Java client for the AOServ Platform.
 * Copyright (C) 2017, 2018, 2019  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoserv-client.
 *
 * aoserv-client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aoserv-client is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with aoserv-client.  If not, see .
 */
package com.aoindustries.aoserv.client.email;

import com.aoindustries.aoserv.client.CachedObjectIntegerKey;
import com.aoindustries.aoserv.client.linux.Server;
import com.aoindustries.aoserv.client.net.AppProtocol;
import com.aoindustries.aoserv.client.net.Bind;
import com.aoindustries.aoserv.client.net.Host;
import com.aoindustries.aoserv.client.pki.Certificate;
import com.aoindustries.aoserv.client.schema.AoservProtocol;
import com.aoindustries.aoserv.client.schema.Table;
import com.aoindustries.io.stream.StreamableInput;
import com.aoindustries.io.stream.StreamableOutput;
import com.aoindustries.math.SafeMath;
import com.aoindustries.net.DomainName;
import com.aoindustries.validation.ValidationException;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;

/**
 * An CyrusImapdServer represents one running instance of Cyrus IMAPD.
 *
 * @see  CyrusImapdBind
 *
 * @author  AO Industries, Inc.
 */
final public class CyrusImapdServer extends CachedObjectIntegerKey {

	static final int
		COLUMN_AO_SERVER = 0,
		COLUMN_SIEVE_NET_BIND = 1,
		COLUMN_CERTIFICATE = 3
	;
	static final String COLUMN_AO_SERVER_name = "ao_server";

	// Matches aoserv-master-db/aoindustries/email/CyrusImapdServer.TimeUnit-type.sql
	public enum TimeUnit {
		DAYS('d') {
			@Override
			float convertToDays(float duration) {
				return duration;
			}
		},
		HOURS('h') {
			@Override
			float convertToDays(float duration) {
				return duration / 24;
			}
		},
		MINUTES('m') {
			@Override
			float convertToDays(float duration) {
				return duration / (24 * 60);
			}
		},
		SECONDS('s') {
			@Override
			float convertToDays(float duration) {
				return duration / (24 * 60 * 60);
			}
		};

		private static final TimeUnit[] values = values();
		private static TimeUnit getFromSuffix(String suffix) {
			if(suffix == null) return null;
			if(suffix.length() != 1) throw new IllegalArgumentException("Suffix must be one character: " + suffix);
			char ch = suffix.charAt(0);
			for(TimeUnit value : values) {
				if(ch == value.suffix) return value;
			}
			throw new IllegalArgumentException("TimeUnit not found from suffix: " + ch);
		}

		private final char suffix;

		private TimeUnit(char suffix) {
			this.suffix = suffix;
		}

		public char getSuffix() {
			return suffix;
		}

		/**
		 * Converts to a number of days, rounded-up.
		 */
		public int getDays(float duration) {
			if(Float.isNaN(duration)) throw new IllegalArgumentException("duration is NaN");
			return SafeMath.castInt(Math.round(Math.ceil(convertToDays(duration))));
		}

		abstract float convertToDays(float duration);
	}

	/**
	 * Default value for cyrus_imapd_servers.allow_plaintext_auth
	 */
	public static final boolean DEFAULT_ALLOW_PLAINTEXT_AUTH = false;

	// Delayed delete seems unreliable so far
	//
	// It is difficult to delete folders and millions of lock files accumulating
	// under /var/lib/imap/lock/u/DELETED/user/*/**/*.lock
	//
	// Turned-off on all servers and removed defaults
	/**
	 * Default value for cyrus_imapd_servers.delete_duration
	 */
	public static final float DEFAULT_DELETE_DURATION = Float.NaN; // 3;

	/**
	 * Default value for cyrus_imapd_servers.delete_duration_unit
	 */
	public static final TimeUnit DEFAULT_DELETE_DURATION_UNIT = null; // TimeUnit.DAYS;

	/**
	 * Default value for cyrus_imapd_servers.expire_duration
	 */
	public static final float DEFAULT_EXPIRE_DURATION = 3;

	/**
	 * Default value for cyrus_imapd_servers.expire_duration_unit
	 */
	public static final TimeUnit DEFAULT_EXPIRE_DURATION_UNIT = TimeUnit.DAYS;

	/**
	 * Default value for cyrus_imapd_servers.expunge_duration
	 */
	public static final float DEFAULT_EXPUNGE_DURATION = 3;

	/**
	 * Default value for cyrus_imapd_servers.expunge_duration_unit
	 */
	public static final TimeUnit DEFAULT_EXPUNGE_DURATION_UNIT = TimeUnit.DAYS;

	private int sieveNetBind;
	private DomainName servername;
	private int certificate;
	private boolean allowPlaintextAuth;
	private float deleteDuration;
	private TimeUnit deleteDurationUnit;
	private float expireDuration;
	private TimeUnit expireDurationUnit;
	private float expungeDuration;
	private TimeUnit expungeDurationUnit;

	@Override
	public String toStringImpl() throws IOException, SQLException {
		return "Cyrus IMAPD @ " + (servername != null ? servername : getLinuxServer().getHostname());
	}

	@Override
	protected Object getColumnImpl(int i) {
		switch(i) {
			case COLUMN_AO_SERVER: return pkey;
			case COLUMN_SIEVE_NET_BIND: return sieveNetBind==-1 ? null : sieveNetBind;
			case 2: return servername;
			case COLUMN_CERTIFICATE: return certificate;
			case 4: return allowPlaintextAuth;
			case 5: return deleteDuration;
			case 6: return deleteDurationUnit==null ? null : String.valueOf(deleteDurationUnit.getSuffix());
			case 7: return expireDuration;
			case 8: return expireDurationUnit==null ? null : String.valueOf(expireDurationUnit.getSuffix());
			case 9: return expungeDuration;
			case 10: return expungeDurationUnit==null ? null : String.valueOf(expungeDurationUnit.getSuffix());
			default: throw new IllegalArgumentException("Invalid index: " + i);
		}
	}

	@Override
	public Table.TableID getTableID() {
		return Table.TableID.CYRUS_IMAPD_SERVERS;
	}

	@Override
	public void init(ResultSet result) throws SQLException {
		try {
			int pos = 1;
			pkey = result.getInt(pos++);
			sieveNetBind = result.getInt(pos++);
			if(result.wasNull()) sieveNetBind = -1;
			servername = DomainName.valueOf(result.getString(pos++));
			certificate = result.getInt(pos++);
			allowPlaintextAuth = result.getBoolean(pos++);
			deleteDuration = result.getFloat(pos++);
			if(result.wasNull()) deleteDuration = Float.NaN;
			deleteDurationUnit = TimeUnit.getFromSuffix(result.getString(pos++));
			expireDuration = result.getFloat(pos++);
			expireDurationUnit = TimeUnit.getFromSuffix(result.getString(pos++));
			expungeDuration = result.getFloat(pos++);
			if(result.wasNull()) expungeDuration = Float.NaN;
			expungeDurationUnit = TimeUnit.getFromSuffix(result.getString(pos++));
		} catch(ValidationException e) {
			throw new SQLException(e);
		}
	}

	@Override
	public void read(StreamableInput in, AoservProtocol.Version protocolVersion) throws IOException {
		try {
			pkey = in.readCompressedInt();
			sieveNetBind = in.readCompressedInt();
			servername = DomainName.valueOf(in.readNullUTF());
			certificate = in.readCompressedInt();
			allowPlaintextAuth = in.readBoolean();
			deleteDuration = in.readFloat();
			deleteDurationUnit = in.readNullEnum(TimeUnit.class);
			expireDuration = in.readFloat();
			expireDurationUnit = in.readNullEnum(TimeUnit.class);
			expungeDuration = in.readFloat();
			expungeDurationUnit = in.readNullEnum(TimeUnit.class);
		} catch(ValidationException e) {
			throw new IOException(e);
		}
	}

	@Override
	public void write(StreamableOutput out, AoservProtocol.Version protocolVersion) throws IOException {
		out.writeCompressedInt(pkey);
		out.writeCompressedInt(sieveNetBind);
		out.writeNullUTF(Objects.toString(servername, null));
		out.writeCompressedInt(certificate);
		out.writeBoolean(allowPlaintextAuth);
		out.writeFloat(deleteDuration);
		out.writeNullEnum(deleteDurationUnit);
		out.writeFloat(expireDuration);
		out.writeNullEnum(expireDurationUnit);
		out.writeFloat(expungeDuration);
		out.writeNullEnum(expungeDurationUnit);
	}

	public Server getLinuxServer() throws SQLException, IOException {
		Server obj = table.getConnector().getLinux().getServer().get(pkey);
		if(obj == null) throw new SQLException("Unable to find linux.Server: " + pkey);
		return obj;
	}

	public Bind getSieveNetBind() throws IOException, SQLException {
		if(sieveNetBind == -1) return null;
		Bind nb = table.getConnector().getNet().getBind().get(sieveNetBind);
		// May be filtered
		if(nb == null) return null;
		String protocol = nb.getAppProtocol().getProtocol();
		if(!AppProtocol.SIEVE.equals(protocol)) throw new SQLException("Sieve NetBind is incorrect app_protocol for NetBind #" + nb.getPkey() + ": " + protocol);
		Host server = nb.getHost();
		if(!server.equals(getLinuxServer().getHost())) throw new SQLException("Sieve NetBind is not on this server for NetBind #" + nb.getPkey());
		return nb;
	}

	/**
	 * The fully qualified hostname for servername.
	 *
	 * When {@code null}, defaults to {@link Server#getHostname()}.
	 */
	public DomainName getServername() {
		return servername;
	}

	/**
	 * Gets the SSL certificate for this server.
	 *
	 * @return  the SSL certificate or {@code null} when filtered
	 */
	public Certificate getCertificate() throws SQLException, IOException {
		// May be filtered
		return table.getConnector().getPki().getCertificate().get(certificate);
	}

	/**
	 * Allows plaintext authentication (PLAIN/LOGIN) on non-TLS links.
	 */
	public boolean getAllowPlaintextAuth() {
		return allowPlaintextAuth;
	}

	/**
	 * Gets the duration after which delayed delete folders are removed.
	 * Enables delete_mode: delayed
	 *
	 * @return  the duration or {@link Float#NaN} when not set
	 *
	 * @see  #getDeleteDurationUnit()
	 */
	public float getDeleteDuration() {
		return deleteDuration;
	}

	/**
	 * Gets the time unit for {@link #getDeleteDuration()}.
	 * When not set, the duration represents days.
	 *
	 * @return  the unit or {@code null} when not set
	 */
	public TimeUnit getDeleteDurationUnit() {
		return deleteDurationUnit;
	}

	/**
	 * Prune the duplicate database of entries older than expire-duration.
	 *
	 * @return  the duration (never {@link Float#NaN})
	 *
	 * @see  #getExpireDurationUnit()
	 */
	public float getExpireDuration() {
		return expireDuration;
	}

	/**
	 * Gets the time unit for {@link #getExpireDuration()}.
	 * When not set, the duration represents days.
	 *
	 * @return  the unit or {@code null} when not set
	 */
	public TimeUnit getExpireDurationUnit() {
		return expireDurationUnit;
	}

	/**
	 * Gets the duration after which delayed expunge messages are removed.
	 * Enables expunge_mode: delayed
	 *
	 * @return  the duration or {@link Float#NaN} when not set
	 *
	 * @see  #getExpungeDurationUnit()
	 */
	public float getExpungeDuration() {
		return expungeDuration;
	}

	/**
	 * Gets the time unit for {@link #getExpungeDuration()}.
	 * When not set, the duration represents days.
	 *
	 * @return  the unit or {@code null} when not set
	 */
	public TimeUnit getExpungeDurationUnit() {
		return expungeDurationUnit;
	}

	public List getCyrusImapdBinds() throws IOException, SQLException {
		return table.getConnector().getEmail().getCyrusImapdBind().getCyrusImapdBinds(this);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy