Skip to content

Commit

Permalink
Use 64bit integer to store quota values, also fixes issue #15
Browse files Browse the repository at this point in the history
  • Loading branch information
buschmann23 committed Jun 30, 2017
1 parent c17066a commit 01813e7
Show file tree
Hide file tree
Showing 38 changed files with 330 additions and 266 deletions.
1 change: 1 addition & 0 deletions cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set(skaffaricmd_SRCS
configinput.h
../common/password.cpp
../common/password.h
../common/global.h
tester.cpp
tester.h
)
Expand Down
8 changes: 4 additions & 4 deletions cmd/imap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ QStringList Imap::getCapabilities(bool forceReload)



std::pair<quint32,quint32> Imap::getQuota(const QString &user)
quota_pair Imap::getQuota(const QString &user)
{
std::pair<quint32,quint32> quota(0, 0);
quota_pair quota(0, 0);

const QString tag = getTag();
const QString command = tag + QLatin1String(" GETQUOTA user") + m_hierarchysep + user + QChar(QChar::CarriageReturn) + QChar(QChar::LineFeed);
Expand All @@ -295,14 +295,14 @@ std::pair<quint32,quint32> Imap::getQuota(const QString &user)
// 8 is the length of "STORAGE" + 1
startUsage += 8;
int startQuota = respLine.indexOf(' ', startUsage);
quota.first = respLine.mid(startUsage, startQuota - (startUsage)).toULong();
quota.first = respLine.mid(startUsage, startQuota - (startUsage)).toULongLong();
// advancing 1 to be at the start of the quota value
startQuota++;
int endQuota = respLine.indexOf(' ', startQuota);
if (endQuota < 0) {
endQuota = respLine.indexOf(')', startQuota);
}
quota.second = respLine.mid(startQuota, endQuota - startQuota).toULong();
quota.second = respLine.mid(startQuota, endQuota - startQuota).toULongLong();
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/imap.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <QSslSocket>
#include <QStringList>

#include "../common/global.h"

class Imap : public QSslSocket
{
Q_OBJECT
Expand All @@ -47,7 +49,7 @@ class Imap : public QSslSocket
bool logout();

QStringList getCapabilities(bool forceReload = false);
std::pair<quint32,quint32> getQuota(const QString &user);
quota_pair getQuota(const QString &user);

void setUser(const QString &user);
void setPassword(const QString &password);
Expand Down
5 changes: 3 additions & 2 deletions cmd/setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "imap.h"
#include "../common/password.h"
#include "../common/config.h"
#include "../common/global.h"

Setup::Setup(const QString &confFile) :
m_confFile(confFile)
Expand Down Expand Up @@ -516,8 +517,8 @@ int Setup::exec() const

os.beginGroup(QStringLiteral("Defaults"));
QString defaultLang = os.value(QStringLiteral("language"), QStringLiteral(SK_DEF_DEF_LANGUAGE)).toString();
quint32 defaultQuota = os.value(QStringLiteral("quota"), SK_DEF_DEF_QUOTA).value<quint32>();
quint32 defaultDomainQuota = os.value(QStringLiteral("domainquota"), SK_DEF_DEF_DOMAINQUOTA).value<quint32>();
quota_size_t defaultQuota = os.value(QStringLiteral("quota"), SK_DEF_DEF_QUOTA).value<quota_size_t>();
quota_size_t defaultDomainQuota = os.value(QStringLiteral("domainquota"), SK_DEF_DEF_DOMAINQUOTA).value<quota_size_t>();
quint32 defaultMaxAccounts = os.value(QStringLiteral("maxaccounts"), SK_DEF_DEF_MAXACCOUNTS).value<quint32>();
QString defaultTimezone = os.value(QStringLiteral("timezone"), QStringLiteral(SK_DEF_DEF_TIMEZONE)).toString();
os.endGroup();
Expand Down
27 changes: 14 additions & 13 deletions cmd/webcyradmimporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "imap.h"
#include "../common/password.h"
#include "../common/config.h"
#include "../common/global.h"

#include <QDebug>

Expand Down Expand Up @@ -175,8 +176,8 @@ int WebCyradmImporter::exec() const
QString imappeername;

QString defaultLang = vars.value(QStringLiteral("DEFAULTLANG"));
quint32 defaultQuota = vars.value(QStringLiteral("DEFAULT_QUOTA")).toLong();
quint32 defaultDomainQuota = vars.value(QStringLiteral("DEFAULT_DOMAIN_QUOTA")).toLong();
quota_size_t defaultQuota = vars.value(QStringLiteral("DEFAULT_QUOTA")).toLongLong();
quota_size_t defaultDomainQuota = vars.value(QStringLiteral("DEFAULT_DOMAIN_QUOTA")).toLongLong();
QString defaultTimezone;
quint32 defaultMaxAccounts = 1000;

Expand Down Expand Up @@ -465,9 +466,9 @@ int WebCyradmImporter::exec() const
return dbError(wq.lastError());
}

QHash<QString,quint32> domainPrefixId;
QHash<QString,quint32> domainNameId;
QHash<quint32,QStringList> domainFolders;
QHash<QString,dbid_t> domainPrefixId;
QHash<QString,dbid_t> domainNameId;
QHash<dbid_t,QStringList> domainFolders;

if (sq.prepare(QStringLiteral("INSERT INTO domain (domain_name, prefix, maxaccounts, quota, domainquota, transport, freenames, freeaddress, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)"))) {
while (wq.next()) {
Expand All @@ -487,7 +488,7 @@ int WebCyradmImporter::exec() const
const QStringList folders = wq.value(8).toString().split(QLatin1Char(','));

if (sq.exec()) {
const quint32 id = sq.lastInsertId().value<quint32>();
const dbid_t id = sq.lastInsertId().value<dbid_t>();
domainPrefixId.insert(prefix, id);
domainNameId.insert(name, id);
if (!folders.empty()) {
Expand All @@ -512,7 +513,7 @@ int WebCyradmImporter::exec() const

auto i = domainFolders.constBegin();
while (i != domainFolders.constEnd()) {
const quint32 id = i.key();
const dbid_t id = i.key();
const QStringList folders = i.value();
for (const QString &folder : folders) {
sq.addBindValue(id);
Expand Down Expand Up @@ -542,7 +543,7 @@ int WebCyradmImporter::exec() const
return dbError(wq.lastError());
}

QHash<QString,quint32> adminNameIds;
QHash<QString,dbid_t> adminNameIds;

if (sq.prepare(QStringLiteral("INSERT INTO adminuser (username, password, type, created_at, updated_at) VALUES (?,?,?,?,?)"))) {
while (wq.next()) {
Expand All @@ -554,7 +555,7 @@ int WebCyradmImporter::exec() const
sq.addBindValue(currentTime);

if (sq.exec()) {
adminNameIds.insert(name, sq.lastInsertId().value<quint32>());
adminNameIds.insert(name, sq.lastInsertId().value<dbid_t>());
} else {
printFailed();
return dbError(sq.lastError());
Expand Down Expand Up @@ -634,7 +635,7 @@ int WebCyradmImporter::exec() const
while (wq.next()) {
const QString username = wq.value(0).toString();
const QString domainName = wq.value(3).toString();
std::pair<quint32,quint32> quota = imap.getQuota(username);
quota_pair quota = imap.getQuota(username);
sq.addBindValue(domainNameId.value(domainName));
sq.addBindValue(username);
sq.addBindValue(wq.value(1));
Expand Down Expand Up @@ -755,8 +756,8 @@ int WebCyradmImporter::exec() const
auto domainIt = domainPrefixId.constBegin();
while (domainIt != domainPrefixId.constEnd()) {
quint32 users;
quint32 quotaused;
const quint32 domainId = domainIt.value();
quota_size_t quotaused;
const dbid_t domainId = domainIt.value();
if (sq.prepare(QStringLiteral("SELECT COUNT(*) FROM accountuser WHERE domain_id = ?"))) {
sq.addBindValue(domainId);
if (sq.exec() && sq.next()) {
Expand All @@ -772,7 +773,7 @@ int WebCyradmImporter::exec() const
if (sq.prepare(QStringLiteral("SELECT SUM(quota) FROM accountuser WHERE domain_id = ?"))) {
sq.addBindValue(domainId);
if (sq.exec() && sq.next()) {
quotaused = sq.value(0).value<quint32>();
quotaused = sq.value(0).value<quota_size_t>();
} else {
printFailed();
return dbError(sq.lastError());
Expand Down
37 changes: 37 additions & 0 deletions common/global.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Skaffari - a mail account administration web interface based on Cutelyst
* Copyright (C) 2017 Matthias Fehring <kontakt@buschmann23.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SKAFFARIGLOBAL_H
#define SKAFFARIGLOBAL_H

#include <QtGlobal>
#include <utility>

typedef quint64 quota_size_t;
typedef quint32 dbid_t;
typedef std::pair<quota_size_t,quota_size_t> quota_pair;

#ifndef SKAFFARI_STRING_TO_DBID
# define SKAFFARI_STRING_TO_DBID(str) str.toULong()
#endif

#ifndef qUtf8Printable
# define qUtf8Printable(string) QString(string).toUtf8().constData()
#endif

#endif // SKAFFARIGLOBAL_H
2 changes: 1 addition & 1 deletion release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ for TMPL in default
do
pushd $TMPL
npm update --dev
./gulp --production
./gulp
pushd static
find $PWD -type f -name "*.css" -o -type f -name "*.js" | parallel compasset
popd
Expand Down
8 changes: 4 additions & 4 deletions sql/QMYSQL/0.0.1.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CREATE TABLE IF NOT EXISTS accountuser (
pop tinyint(1) unsigned NOT NULL DEFAULT 1,
sieve tinyint(1) unsigned NOT NULL DEFAULT 1,
smtpauth tinyint(1) unsigned NOT NULL DEFAULT 1,
quota int(10) unsigned NOT NULL DEFAULT 0,
quota bigint(20) unsigned NOT NULL DEFAULT 0,
created_at datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
updated_at datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
valid_until datetime NOT NULL DEFAULT '2998-12-31 23:59:59',
Expand Down Expand Up @@ -44,9 +44,9 @@ CREATE TABLE IF NOT EXISTS domain (
domain_name varchar(255) NOT NULL,
prefix varchar(50) NOT NULL,
maxaccounts int(11) NOT NULL DEFAULT 20,
quota int(10) unsigned NOT NULL DEFAULT 100000,
domainquota int(10) unsigned NOT NULL DEFAULT 0,
domainquotaused int(10) unsigned NOT NULL DEFAULT 0,
quota bigint(20) unsigned NOT NULL DEFAULT 100000,
domainquota bigint(20) unsigned NOT NULL DEFAULT 0,
domainquotaused bigint(20) unsigned NOT NULL DEFAULT 0,
transport varchar(255) NOT NULL DEFAULT 'cyrus',
freenames tinyint(1) unsigned NOT NULL DEFAULT 0,
freeaddress tinyint(1) unsigned NOT NULL DEFAULT 0,
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ set(skaffari_SRCS
skaffari.h
../common/password.cpp
../common/password.h
../common/global.h
)

# Create the application
Expand Down
13 changes: 7 additions & 6 deletions src/accounteditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "objects/helpentry.h"
#include "utils/skaffariconfig.h"
#include "utils/utils.h"
#include "../common/global.h"

#include <Cutelyst/Plugins/Session/Session>
#include <Cutelyst/Plugins/Utils/Validator> // includes the main validator
Expand All @@ -50,10 +51,10 @@ AccountEditor::~AccountEditor()

void AccountEditor::base(Context* c, const QString &domainId, const QString& accountId)
{
const quint32 domId = domainId.toULong();
const dbid_t domId = SKAFFARI_STRING_TO_DBID(domainId);
if (Domain::checkAccess(c, domId)) {
Domain::toStash(c, domId);
Account::toStash(c, Domain::fromStash(c), accountId.toULong());
Account::toStash(c, Domain::fromStash(c), SKAFFARI_STRING_TO_DBID(accountId));
}
}

Expand All @@ -65,7 +66,7 @@ void AccountEditor::edit(Context* c)
Account a = Account::fromStash(c);
Domain dom = Domain::fromStash(c);

const quint32 freeQuota = (dom.getDomainQuota() - dom.getDomainQuotaUsed() + a.getQuota());
const quota_size_t freeQuota = (dom.getDomainQuota() - dom.getDomainQuotaUsed() + a.getQuota());

auto req = c->req();

Expand Down Expand Up @@ -96,7 +97,7 @@ void AccountEditor::edit(Context* c)
bool enoughQuotaLeft = true;
if (dom.getDomainQuota() > 0) {

quint32 accQuota = 0;
quota_size_t accQuota = 0;
bool quotaOk = true;

if (p.contains(QStringLiteral("humanQuota"))) {
Expand Down Expand Up @@ -156,8 +157,8 @@ void AccountEditor::edit(Context* c)

const QString quotaTitle = c->translate("DomainEditor", "Quota");
if (dom.getDomainQuota() > 0) {
help.insert(QStringLiteral("quota"), HelpEntry(quotaTitle, c->translate("AccountEditor", "You have to set a storage quota for this account that does not exceed %1.").arg(Utils::humanBinarySize(c, static_cast<quint64>(freeQuota) * Q_UINT64_C(1024)))));
help.insert(QStringLiteral("humanQuota"), HelpEntry(quotaTitle, c->translate("AccountEditor", "You have to set a storage quota for this account that does not exceed %1. You can use the multipliers M, MiB, G, GiB, T and TiB. Without a multiplier, KiB is the default.").arg(Utils::humanBinarySize(c, static_cast<quint64>(freeQuota) * Q_UINT64_C(1024)))));
help.insert(QStringLiteral("quota"), HelpEntry(quotaTitle, c->translate("AccountEditor", "You have to set a storage quota for this account that does not exceed %1.").arg(Utils::humanBinarySize(c, freeQuota * Q_UINT64_C(1024)))));
help.insert(QStringLiteral("humanQuota"), HelpEntry(quotaTitle, c->translate("AccountEditor", "You have to set a storage quota for this account that does not exceed %1. You can use the multipliers M, MiB, G, GiB, T and TiB. Without a multiplier, KiB is the default.").arg(Utils::humanBinarySize(c, freeQuota * Q_UINT64_C(1024)))));
} else {
help.insert(QStringLiteral("quota"), HelpEntry(quotaTitle, c->translate("AccountEditor", "You can freely set a storage quota for this account or set the quota to 0 to disable it.")));
help.insert(QStringLiteral("humanQuota"), HelpEntry(quotaTitle, c->translate("AccountEditor", "You can freely set a storage quota for this account or set the quota to 0 to disable it. You can use the multipliers M, MiB, G, GiB, T and TiB. Without a multiplier, KiB is the default.")));
Expand Down
3 changes: 2 additions & 1 deletion src/authstoresql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <QSqlQuery>
#include <QSqlError>
#include <QVariantList>
#include "../common/global.h"

AuthStoreSql::AuthStoreSql(QObject *parent) : AuthenticationStore(parent)
{
Expand Down Expand Up @@ -52,7 +53,7 @@ AuthenticationUser AuthStoreSql::findUser(Context *c, const ParamsMultiMap &user
}

q = CPreparedSqlQueryThread(QStringLiteral("SELECT domain_id FROM domainadmin WHERE admin_id = :admin_id"));
q.bindValue(QStringLiteral(":admin_id"), QVariant::fromValue<quint32>(user.id().toULong()));
q.bindValue(QStringLiteral(":admin_id"), QVariant::fromValue<dbid_t>(user.id().toULong()));

q.exec();

Expand Down
17 changes: 9 additions & 8 deletions src/domaineditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "objects/helpentry.h"
#include "utils/skaffariconfig.h"
#include "utils/utils.h"
#include "../common/global.h"

#include <Cutelyst/Plugins/Utils/Validator> // includes the main validator
#include <Cutelyst/Plugins/Utils/Validators> // includes all validator rules
Expand Down Expand Up @@ -71,7 +72,7 @@ void DomainEditor::index(Context *c)

void DomainEditor::base(Context* c, const QString &id)
{
const quint32 domainId = id.toULong();
const dbid_t domainId = SKAFFARI_STRING_TO_DBID(id);
if (Domain::checkAccess(c, domainId)) {
Domain::toStash(c, domainId);
}
Expand Down Expand Up @@ -265,9 +266,9 @@ void DomainEditor::create(Context* c)

c->stash({
{QStringLiteral("defQuota"), SkaffariConfig::defQuota()},
{QStringLiteral("defHumanQuota"), Utils::humanBinarySize(c, static_cast<quint64>(SkaffariConfig::defQuota()) * Q_UINT64_C(1024))},
{QStringLiteral("defHumanQuota"), Utils::humanBinarySize(c, SkaffariConfig::defQuota() * Q_UINT64_C(1024))},
{QStringLiteral("defDomainQuota"), SkaffariConfig::defDomainquota()},
{QStringLiteral("defHumanDomainQuota"), Utils::humanBinarySize(c, static_cast<quint64>(SkaffariConfig::defDomainquota()) * Q_UINT64_C(1024))},
{QStringLiteral("defHumanDomainQuota"), Utils::humanBinarySize(c, SkaffariConfig::defDomainquota() * Q_UINT64_C(1024))},
{QStringLiteral("defMaxAccounts"), SkaffariConfig::defMaxaccounts()},
{QStringLiteral("template"), QStringLiteral("domain/create.html")},
{QStringLiteral("domainAsPrefix"), SkaffariConfig::imapDomainasprefix()},
Expand Down Expand Up @@ -378,7 +379,7 @@ void DomainEditor::add_account(Context* c)

if (Q_LIKELY((user.value(QStringLiteral("type")).value<qint16>() == 0) || user.value(QStringLiteral("domains")).value<QVariantList>().contains(dom.id()))) {

const quint32 freeQuota = (dom.getDomainQuota() - dom.getDomainQuotaUsed());
const quota_size_t freeQuota = (dom.getDomainQuota() - dom.getDomainQuotaUsed());

auto req = c->req();

Expand Down Expand Up @@ -428,7 +429,7 @@ void DomainEditor::add_account(Context* c)

if (dom.getDomainQuota() > 0) {

quint32 accQuota = 0;
quota_size_t accQuota = 0;
bool quotaOk = true;

if (p.contains(QStringLiteral("humanQuota"))) {
Expand Down Expand Up @@ -571,8 +572,8 @@ void DomainEditor::add_account(Context* c)
const QString domainQuotaTitle = c->translate("DomainEditor", "DomainQuota");
if (dom.getDomainQuota() > 0) {
help.insert(QStringLiteral("domainQuota"), HelpEntry(domainQuotaTitle, c->translate("DomainEditor", "Used and total amount of storage quota for this domain.")));
help.insert(QStringLiteral("quota"), HelpEntry(quotaTitle, c->translate("DomainEditor", "You have to set a storage quota for this account that does not exceed %1 KiB.").arg(static_cast<quint64>(freeQuota) * Q_UINT64_C(1024))));
help.insert(QStringLiteral("humanQuota"), HelpEntry(quotaTitle, c->translate("DomainEditor", "You have to set a storage quota for this account that does not exceed %1. You can use the multipliers M, MiB, G, GiB, T and TiB. Without a multiplier, KiB is the default.").arg(Utils::humanBinarySize(c, static_cast<quint64>(freeQuota) * Q_UINT64_C(1024)))));
help.insert(QStringLiteral("quota"), HelpEntry(quotaTitle, c->translate("DomainEditor", "You have to set a storage quota for this account that does not exceed %1 KiB.").arg(freeQuota * Q_UINT64_C(1024))));
help.insert(QStringLiteral("humanQuota"), HelpEntry(quotaTitle, c->translate("DomainEditor", "You have to set a storage quota for this account that does not exceed %1. You can use the multipliers M, MiB, G, GiB, T and TiB. Without a multiplier, KiB is the default.").arg(Utils::humanBinarySize(c, freeQuota * Q_UINT64_C(1024)))));
} else {
help.insert(QStringLiteral("domainQuota"), HelpEntry(domainQuotaTitle, c->translate("DomainEditor", "This domain has no overall quota limit, so the value shows the sum of the quota limit of all accounts in this domain.")));
help.insert(QStringLiteral("quota"), HelpEntry(quotaTitle, c->translate("DomainEditor", "You can freely set a storage quota for this account or set the quota to 0 to disable it.")));
Expand Down Expand Up @@ -636,7 +637,7 @@ void DomainEditor::check(Context *c)
if (Q_LIKELY(q.exec())) {
QStringList accountIds;
while (q.next()) {
accountIds << QString::number(q.value(0).value<quint32>());
accountIds << QString::number(q.value(0).value<dbid_t>());
}
c->setStash(QStringLiteral("accountids"), accountIds.join(QLatin1Char(',')));
} else {
Expand Down
Loading

0 comments on commit 01813e7

Please sign in to comment.