diff -dNru cyrus-imapd-2.2.12/configure cyrus-imapd-2.2.12.fjo/configure --- cyrus-imapd-2.2.12/configure Mon Feb 14 18:59:46 2005 +++ cyrus-imapd-2.2.12.fjo/configure Tue Feb 13 14:08:20 2007 @@ -6390,7 +6390,7 @@ echo "${ECHO_T}$WITH_AUTH" >&6 -CYRUSDB_OBJS="cyrusdb_flat.o cyrusdb_skiplist.o cyrusdb_quotalegacy.o" +CYRUSDB_OBJS="cyrusdb_pgsql.o cyrusdb_flat.o cyrusdb_skiplist.o cyrusdb_quotalegacy.o" diff -dNru cyrus-imapd-2.2.12/lib/cyrusdb.c cyrus-imapd-2.2.12.fjo/lib/cyrusdb.c --- cyrus-imapd-2.2.12/lib/cyrusdb.c Tue Jan 20 02:11:03 2004 +++ cyrus-imapd-2.2.12.fjo/lib/cyrusdb.c Tue Feb 13 14:08:20 2007 @@ -69,6 +69,7 @@ &cyrusdb_flat, &cyrusdb_skiplist, &cyrusdb_quotalegacy, + &cyrusdb_pgsql, NULL }; void cyrusdb_init() diff -dNru cyrus-imapd-2.2.12/lib/cyrusdb.h cyrus-imapd-2.2.12.fjo/lib/cyrusdb.h --- cyrus-imapd-2.2.12/lib/cyrusdb.h Thu Mar 11 19:36:44 2004 +++ cyrus-imapd-2.2.12.fjo/lib/cyrusdb.h Tue Feb 13 14:08:20 2007 @@ -186,6 +186,7 @@ extern struct cyrusdb_backend cyrusdb_flat; extern struct cyrusdb_backend cyrusdb_skiplist; extern struct cyrusdb_backend cyrusdb_quotalegacy; +extern struct cyrusdb_backend cyrusdb_pgsql; extern int cyrusdb_copyfile(const char *srcname, const char *dstname); diff -dNru cyrus-imapd-2.2.12/lib/cyrusdb_pgsql.c cyrus-imapd-2.2.12.fjo/lib/cyrusdb_pgsql.c --- cyrus-imapd-2.2.12/lib/cyrusdb_pgsql.c Thu Jan 1 01:00:00 1970 +++ cyrus-imapd-2.2.12.fjo/lib/cyrusdb_pgsql.c Tue Feb 13 14:08:02 2007 @@ -0,0 +1,837 @@ +/* + * cyrusdb_pgsql.c + * PostgreSQL/Cyrus-IMAP database glue layer + * (c) 2004, F.J. Ogris + * published under GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "libpq-fe.h" +#include "cyrusdb.h" +#include "xmalloc.h" + +#if 0 +# include +# define mydebug(fmt,args...) { \ + char buf[4096]; \ + int f; \ + sprintf(buf, "pid:%i %s:%i %s(): " fmt "\n", getpid(), __FILE__, __LINE__, \ + __FUNCTION__, ##args); \ + f = open("/tmp/cyrusdb_pgsql.log", O_CREAT|O_APPEND|O_WRONLY, 00644); \ + if (f != -1) { \ + write(f, buf, strlen(buf)); \ + close(f); \ + } \ + } +#else +# define mydebug(fmt,args...) +#endif + +#define mywarn(fmt, args...) syslog(LOG_WARNING, "%s:%i %s(): " fmt, \ + __FILE__, __LINE__, __FUNCTION__, ## args) +#define myerr(fmt, args...) syslog(LOG_ERR, "%s:%i %s(): " fmt, \ + __FILE__, __LINE__, __FUNCTION__, ## args) + + +struct db { + PGconn *conn; + char *table; +}; + +static struct txn { + int foobar; +} txn_lock = { + .foobar = 0x19781204, +}; + + +static char *conninfo = NULL; + + +static int myinit (const char *dbdir, int myflags) +{ + struct stat st; + char *connfile, *c; + int fh; + + mydebug("dbdir:%s flags:%i", dbdir, myflags); + + if (!dbdir) { + myerr("%s", "dbdir is null"); + return CYRUSDB_INTERNAL; + } + + if (conninfo) { + myerr("%s", "called twice (conninfo is not null)"); + return CYRUSDB_INTERNAL; + } + + connfile = xstrdup(dbdir); + connfile = xrealloc(connfile, strlen(connfile) + 12); + strcat(connfile, "/pgconn.opts"); + fh = open(connfile, O_RDONLY); + if (fh < 0) { + if (errno == ENOENT) { + conninfo = xstrdup("dbname=cyrus user=cyrus password=cyrus"); + mywarn("%s: %s (using hardcoded default values for pgsql connection)", + connfile, strerror(errno)); + fh = CYRUSDB_OK; + } + else { + myerr("%s: %s", connfile, strerror(errno)); + fh = CYRUSDB_IOERROR; + } + + free(connfile); + return fh; + } + + if (fstat(fh, &st)) { + myerr("fstat(%s): %s", connfile, strerror(errno)); + free(connfile); + close(fh); + return CYRUSDB_IOERROR; + } + + conninfo = xmalloc(st.st_size); + if (read(fh, conninfo, st.st_size) != (signed) st.st_size) { + myerr("read(%s): cannot read whole file", connfile); + free(connfile); + free(conninfo); + conninfo = NULL; + close(fh); + return CYRUSDB_IOERROR; + } + + close(fh); + free(connfile); + for (c = conninfo; *c; ++c) + if ((*c == '\r') || (*c == '\n')) break; + + *c = '\0'; + + return CYRUSDB_OK; +} + +static int mydone (void) +{ + mydebug("%s", "(void)"); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + free(conninfo); + conninfo = NULL; + + return CYRUSDB_OK; +} + +static int mysync (void) +{ + mydebug("%s", "(void)"); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + sync(); + + return CYRUSDB_OK; +} + +static PGresult *my_do_dump (PGconn *conn, const char *table) +{ + PGresult *res; + char *query; + + query = xmalloc(strlen(table) + 256); + strcpy(query, "SELECT replace(id, '\\t', '\\\\t') || '\\t' || " + "replace(key, '\\t', '\\\\t') || '\\t' || " + "replace(value, '\\t', '\\\\t') || '\\n' FROM \""); + strcat(query, table); + strcat(query, "\" ORDER BY key DESC"); + res = PQexec(conn, query); + free(query); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + myerr("%s", PQresultErrorMessage(res)); + PQclear(res); + res = NULL; + } + return res; +} + +static int myarchive (const char **fnames, const char *dirname) +{ + PGconn *conn; + PGresult *res; + size_t len; + ssize_t ret; + int fh, rows; + char *c, *file; + + mydebug("dirname:%s", dirname); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!fnames) { + myerr("%s", "fnames is null"); + return CYRUSDB_INTERNAL; + } + + if (!*fnames) { + myerr("%s", "no fnames given"); + return CYRUSDB_INTERNAL; + } + + if (!dirname) { + myerr("%s", "dirname is null"); + return CYRUSDB_INTERNAL; + } + + conn = PQconnectdb(conninfo); + if (PQstatus(conn) != CONNECTION_OK) { + myerr("%s", PQerrorMessage(conn)); + return CYRUSDB_IOERROR; + } + + for (; *fnames; ++fnames) { + mydebug(" fname:%s", *fnames); + res = my_do_dump(conn, *fnames); + if (!res) { + myerr("%s", "my_do_dump yields error"); + PQfinish(conn); + return CYRUSDB_IOERROR; + } + + file = xmalloc(strlen(*fnames) + strlen(dirname) + 2); + strcpy(file, dirname); + if (*(dirname + strlen(dirname) - 1) != '/') strcat(file, "/"); + strcat(file, *fnames); + + fh = open(file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); + if (fh < 0) { + myerr("%s: %s", file, strerror(errno)); + free(file); + PQclear(res); + PQfinish(conn); + return CYRUSDB_IOERROR; + } + + for (rows = PQntuples(res); rows; --rows) { + c = PQgetvalue(res, rows, 0); + len = strlen(c); + ret = write(fh, c, len); + if (ret != (ssize_t) len) { + if (ret < 0) myerr("write(%s): %s", file, strerror(errno)); + else myerr("write(%s): cannot write whole file", file); + close(fh); + free(file); + PQclear(res); + PQfinish(conn); + return CYRUSDB_IOERROR; + } + } + + PQclear(res); + if (close(fh) < 0) { + myerr("close(%s): %s", file, strerror(errno)); + free(file); + PQfinish(conn); + return CYRUSDB_IOERROR; + } + free(file); + } + + PQfinish(conn); + + return CYRUSDB_OK; +} + +static int myclose (struct db *mydb) +{ + mydebug("db:%p", mydb); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + if (!mydb->conn) { + myerr("%s", "mydb->conn is null"); + return CYRUSDB_INTERNAL; + } + + if (!mydb->table) { + myerr("%s", "mydb->table is null"); + return CYRUSDB_INTERNAL; + } + + PQfinish(mydb->conn); + free(mydb->table); + free(mydb); + + return CYRUSDB_OK; +} + +static int myopen (const char *fname, int flags, struct db **ret) +{ + PGresult *res; + struct db *mydb; + struct stat st; + int fh; + char *slash, *query; + ssize_t len; + + mydebug("fname:%s flags:%i ret:%p", fname, flags, ret); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!ret) { + myerr("%s", "ret is null"); + return CYRUSDB_INTERNAL; + } + + if (stat(fname, &st)) { + if (errno != ENOENT) { + myerr("%s: %s", fname, strerror(errno)); + return CYRUSDB_IOERROR; + } + else if (!(flags & CYRUSDB_CREATE)) { + myerr("%s does not exist, but creation flag is not set", fname); + return CYRUSDB_INTERNAL; + } + } + else flags &= !CYRUSDB_CREATE; + + mydb = (struct db*) xmalloc(sizeof(struct db)); + slash = strrchr(fname, '/'); + mydb->table = xstrdup((slash)?(++slash):(fname)); + for (slash = mydb->table; *slash; ++slash) if (*slash == '.') *slash = '_'; + mydb->conn = PQconnectdb(conninfo); + + if (PQstatus(mydb->conn) != CONNECTION_OK) { + myerr("%s", PQerrorMessage(mydb->conn)); + return CYRUSDB_IOERROR; + } + + if (!(flags & CYRUSDB_CREATE)) { + *ret = mydb; + return CYRUSDB_OK; + } + + if (mkdir(fname, 0775)) return CYRUSDB_IOERROR; + + query = xmalloc(2 * strlen(mydb->table) + 128); + strcpy(query, "CREATE TABLE \""); + strcat(query, mydb->table); + strcat(query, "\" (id SERIAL8 NOT NULL UNIQUE PRIMARY KEY, " + "key TEXT NOT NULL UNIQUE, value TEXT)"); + res = PQexec(mydb->conn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + myerr("%s", PQresultErrorMessage(res)); + PQclear(res); + free(query); + rmdir(fname); + return CYRUSDB_IOERROR; + } + + PQclear(res); + *ret = mydb; + return CYRUSDB_OK; +} + +static int my_fetch_or_fetchlock (struct db *mydb, + const char *key, int keylen, + const char **data, int *datalen, + struct txn **mytid, int lock) +{ + PGresult *res; + int rows; + char *query; + + mydebug("db:%p key:%s keylen:%i data:%p datalen:%p txn:%p lock:%i", + mydb, key, keylen, data, datalen, mytid, lock); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + if (!key) { + myerr("%s", "key is null"); + return CYRUSDB_INTERNAL; + } + + query = xmalloc(2 * keylen + strlen(mydb->table) + 128); + *query = '\0'; + if (mytid) if (!*mytid) { + *mytid = &txn_lock; + strcat(query, "BEGIN; "); + } + + strcat(query, "SELECT value FROM \""); + strcat(query, mydb->table); + strcat(query, "\" WHERE key='"); + PQescapeString(query + strlen(query), key, keylen); + if (lock) { + if (!mytid) mywarn("%s", "called without transaction"); + strcat(query, "' FOR UPDATE"); + } + else strcat(query, "'"); + + res = PQexec(mydb->conn, query); + free(query); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + myerr("%s", PQresultErrorMessage(res)); + PQclear(res); + return CYRUSDB_IOERROR; + } + + rows = PQntuples(res); + if (rows == 1) { + if (data && datalen) { + *data = xstrdup(PQgetvalue(res, 0, 0)); + *datalen = strlen(*data); + } + PQclear(res); + return CYRUSDB_OK; + } + + PQclear(res); + if (!rows) return CYRUSDB_NOTFOUND; + + if (rows > 1) { + myerr("%s", "more than one row in result (violates unique key)"); + return CYRUSDB_IOERROR; + } + + myerr("%s", "less than zero rows in result"); + + return CYRUSDB_IOERROR; +} + +static int myfetch (struct db *mydb, + const char *key, int keylen, + const char **data, int *datalen, + struct txn **mytid) +{ + mydebug("db:%p key:%s keylen:%i data:%p datalen:%p txn:%p", + mydb, key, keylen, data, datalen, mytid); + + return my_fetch_or_fetchlock(mydb, key, keylen, data, datalen, mytid, 0); +} + +static int myfetchlock (struct db *mydb, + const char *key, int keylen, + const char **data, int *datalen, + struct txn **mytid) +{ + mydebug("db:%p key:%s keylen:%i data:%p datalen:%p txn:%p", + mydb, key, keylen, data, datalen, mytid); + + return my_fetch_or_fetchlock(mydb, key, keylen, data, datalen, mytid, 1); +} + +static int myforeach (struct db *mydb, + char *prefix, int prefixlen, + foreach_p *p, + foreach_cb *cb, void *rock, + struct txn **mytid) +{ + PGresult *res; + size_t keylen, datalen; + int rows, ret; + char *query, *key, *data; + + mydebug("db:%p prefix:%s prefixlen:%i foreach_p:%p foreach_cb:%p " + "rock:%p txn:%p", + mydb, prefix, prefixlen, p, cb, rock, mytid); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + if (!prefix) { + myerr("%s", "prefix is null"); + return CYRUSDB_INTERNAL; + } + + query = xmalloc(2 * prefixlen + strlen(mydb->table) + 128); + *query = '\0'; + if (mytid) if (!*mytid) { + *mytid = &txn_lock; + strcat(query, "BEGIN; "); + } + + strcat(query, "SELECT key, value FROM \""); + strcat(query, mydb->table); + strcat(query, "\" WHERE key LIKE '"); + PQescapeString(query + strlen(query), prefix, prefixlen); + strcat(query, "%' ORDER BY key DESC"); + res = PQexec(mydb->conn, query); + free(query); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + myerr("%s", PQresultErrorMessage(res)); + PQclear(res); + return CYRUSDB_IOERROR; + } + + rows = PQntuples(res); + if (rows > 0) { + do { + --rows; + key = xstrdup(PQgetvalue(res, rows, 0)); + keylen = strlen(key); + data = xstrdup(PQgetvalue(res, rows, 1)); + datalen = strlen(data); + if (p) ret = p(rock, key, keylen, data, datalen); + else ret = 1; + if (ret) cb(rock, key, keylen, data, datalen); + free(data); + free(key); + } while (rows); + PQclear(res); + return CYRUSDB_OK; + } + + PQclear(res); + if (!rows) return CYRUSDB_NOTFOUND; + + myerr("%s", "less than zero rows in result"); + + return CYRUSDB_IOERROR; +} + +static int my_create_or_store (struct db *mydb, + const char *key, int keylen, + const char *data, int datalen, + struct txn **mytid, int overwrite) +{ + PGresult *res; + int ret; + char *query; + + mydebug("db:%p key:%s keylen:%i data:%s datalen:%i txn:%p overwrite:%i", + mydb, key, keylen, data, datalen, mytid, overwrite); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + if (!key) { + myerr("%s", "key is null"); + return CYRUSDB_INTERNAL; + } + + if (!data) { + myerr("%s", "data is null"); + return CYRUSDB_INTERNAL; + } + + if (!mytid) mywarn("%s", "called without transaction"); + else if (!*mytid) mywarn("%s", "beginning new transaction"); + + ret = my_fetch_or_fetchlock(mydb, key, keylen, NULL, NULL, mytid, 1); + switch (ret) { + case CYRUSDB_OK: + if (overwrite) break; + myerr("%s", "data exists, but overwrite flag is not set"); + return CYRUSDB_EXISTS; + + case CYRUSDB_NOTFOUND: + break; + + default: + myerr("%s", "my_fetch_or_fetchlock yields error"); + return ret; + } + + query = xmalloc(2 * keylen + 2 * datalen + strlen(mydb->table) + 128); + + if (ret == CYRUSDB_OK) { + strcpy(query, "UPDATE \""); + strcat(query, mydb->table); + strcat(query, "\" SET value='"); + PQescapeString(query + strlen(query), data, datalen); + strcat(query, "' WHERE key='"); + PQescapeString(query + strlen(query), key, keylen); + strcat(query, "'"); + } + else { + strcpy(query, "INSERT INTO \""); + strcat(query, mydb->table); + strcat(query, "\" (key, value) VALUES ('"); + PQescapeString(query + strlen(query), key, keylen); + strcat(query, "', '"); + PQescapeString(query + strlen(query), data, datalen); + strcat(query, "')"); + } + + res = PQexec(mydb->conn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + myerr("%s", PQresultErrorMessage(res)); + ret = CYRUSDB_IOERROR; + } + else ret = CYRUSDB_OK; + + PQclear(res); + free(query); + + return ret; +} + +static int mycreate (struct db *mydb, + const char *key, int keylen, + const char *data, int datalen, + struct txn **mytid) +{ + mydebug("db:%p key:%s keylen:%i data:%s datalen:%i txn:%p", + mydb, key, keylen, data, datalen, mytid); + + return my_create_or_store(mydb, key, keylen, data, datalen, mytid, 0); +} + +static int mystore (struct db *mydb, + const char *key, int keylen, + const char *data, int datalen, + struct txn **mytid) +{ + mydebug("db:%p key:%s keylen:%i data:%s datalen:%i txn:%p", + mydb, key, keylen, data, datalen, mytid); + + return my_create_or_store(mydb, key, keylen, data, datalen, mytid, 1); +} + +static int mydelete (struct db *mydb, + const char *key, int keylen, + struct txn **mytid, + int force) +{ + PGresult *res; + int ret; + char *query; + + mydebug("db:%p key:%s keylen:%i txn:%p force:%i", + mydb, key, keylen, mytid, force); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + if (!key) { + myerr("%s", "key is null"); + return CYRUSDB_INTERNAL; + } + + if (!mytid) mywarn("%s", "called without transaction"); + else if (!*mytid) mywarn("%s", "beginning new transaction"); + + ret = my_fetch_or_fetchlock(mydb, key, keylen, NULL, NULL, mytid, 1); + switch (ret) { + case CYRUSDB_NOTFOUND: + if (!force) break; + myerr("%s", "data does not exist, but force flag is set"); + return CYRUSDB_NOTFOUND; + + case CYRUSDB_OK: + break; + + default: + myerr("%s", "my_fetch_or_fetchlock yields error"); + return ret; + } + + query = xmalloc(2 * keylen + strlen(mydb->table) + 128); + + strcpy(query, "DELETE FROM \""); + strcat(query, mydb->table); + strcat(query, "\" WHERE key='"); + PQescapeString(query + strlen(query), key, keylen); + strcat(query, "'"); + + res = PQexec(mydb->conn, query); + free(query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + myerr("%s", PQresultErrorMessage(res)); + ret = CYRUSDB_IOERROR; + } + else ret = CYRUSDB_OK; + + PQclear(res); + + return ret; +} + +static int my_commit_or_abort (struct db *mydb, struct txn *mytid, char *cmd) +{ + PGresult *res; + int ret; + char *query; + + mydebug("db:%p txn:%p cmd:%s", mydb, mytid, cmd); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + if (!mytid) { + myerr("%s", "tid is null"); + return CYRUSDB_INTERNAL; + } + + res = PQexec(mydb->conn, cmd); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + myerr("%s", PQresultErrorMessage(res)); + ret = CYRUSDB_IOERROR; + } + else ret = CYRUSDB_OK; + + PQclear(res); + + return ret; +} + +static int mycommit (struct db *mydb, struct txn *mytid) +{ + mydebug("db:%p txn:%p", mydb, mytid); + + return my_commit_or_abort(mydb, mytid, "COMMIT"); +} + +static int myabort (struct db *mydb, struct txn *mytid) +{ + mydebug("db:%p txn:%p", mydb, mytid); + + return my_commit_or_abort(mydb, mytid, "ABORT"); +} + +/* + * from cyrusdb_skiplist.c: + * if detail == 1, dump all records. + * if detail == 2, also dump pointers for active records. + * if detail == 3, dump all records/all pointers. + */ +static int mydump (struct db *mydb, int detail) +{ + PGresult *res; + char *c; + int rows; + + mydebug("db:%p detail:%i", mydb, detail); + + /* make compiler happy */ + detail = detail; + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + res = my_do_dump(mydb->conn, mydb->table); + if (!res) { + myerr("%s", "my_do_dump yields error"); + return CYRUSDB_INTERNAL; + } + + for (rows = PQntuples(res); rows; --rows) { + c = PQgetvalue(res, rows, 0); + write(1, c, strlen(c)); + } + + PQclear(res); + + return CYRUSDB_OK; +} + +static int myconsistent (struct db *mydb) +{ + mydebug("db:%p", mydb); + + if (!conninfo) { + myerr("%s", "called without prior call to myinit (conninfo is null)"); + return CYRUSDB_INTERNAL; + } + + if (!mydb) { + myerr("%s", "mydb is null"); + return CYRUSDB_INTERNAL; + } + + return CYRUSDB_OK; +} + + +struct cyrusdb_backend cyrusdb_pgsql = +{ + .name = "pgsql", + .init = &myinit, + .done = &mydone, + .sync = &mysync, + .archive = &myarchive, + .open = &myopen, + .close = &myclose, + .fetch = &myfetch, + .fetchlock = &myfetchlock, + .foreach = &myforeach, + .create = &mycreate, + .store = &mystore, + .delete = &mydelete, + .commit = &mycommit, + .abort = &myabort, + .dump = &mydump, + .consistent = &myconsistent, +}; diff -dNru cyrus-imapd-2.2.12/lib/imapoptions cyrus-imapd-2.2.12.fjo/lib/imapoptions --- cyrus-imapd-2.2.12/lib/imapoptions Wed Jul 21 21:07:45 2004 +++ cyrus-imapd-2.2.12.fjo/lib/imapoptions Tue Feb 13 14:08:20 2007 @@ -455,7 +455,7 @@ messages larger than \fImaxmessagesize\fR bytes. If set to 0, this will allow messages of any size (the default). */ -{ "mboxlist_db", "skiplist", STRINGLIST("flat", "berkeley", "skiplist")} +{ "mboxlist_db", "skiplist", STRINGLIST("pgsql", "flat", "berkeley", "skiplist")} /* The cyrusdb backend to use for the mailbox list. */ # xxx badly worded @@ -656,7 +656,7 @@ strip the default realm from the userid (this does not affect the stripping of realms specified by the afspts_localrealms option) */ -{ "quota_db", "quotalegacy", STRINGLIST("flat", "berkeley", "skiplist", "quotalegacy")} +{ "quota_db", "quotalegacy", STRINGLIST("pgsql", "flat", "berkeley", "skiplist", "quotalegacy")} /* The cyrusdb backend to use for quotas. */ { "quotawarn", 90, INT }