2 * Maildir Plugin -- Maildir++ support for Sylpheed
3 * Copyright (C) 2003-2004 Christoph Hohmann
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 static gboolean initialized = FALSE;
39 db_env_create(&dbenv, 0);
40 dbenv->open(dbenv, get_tmp_dir(), DB_INIT_MPOOL | DB_INIT_CDB | DB_CREATE, 0600);
47 dbenv->close(dbenv, 0);
52 int get_secondary_key(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey)
56 memset(skey, 0, sizeof(DBT));
58 uniq = pdata->data + sizeof(guint32);
60 skey->size = strlen(uniq);
65 UIDDB *uiddb_open(const gchar *dbfile)
71 g_return_val_if_fail(initialized, NULL);
73 /* open uid key based database */
74 if ((ret = db_create(&db_uid, dbenv, 0)) != 0) {
75 debug_print("db_create: %s\n", db_strerror(ret));
78 if ((ret = db_uid->open(db_uid, NULL, dbfile, "uidkey", DB_BTREE, DB_CREATE, 0600)) != 0) {
79 debug_print("DB->open: %s\n", db_strerror(ret));
80 db_uid->close(db_uid, 0);
83 debug_print("UID based database opened\n");
85 /* open uniq key based database */
86 if ((ret = db_create(&db_uniq, dbenv, 0)) != 0) {
87 debug_print("db_create: %s\n", db_strerror(ret));
88 db_uid->close(db_uid, 0);
91 if ((ret = db_uniq->open(db_uniq, NULL, dbfile, "uniqkey", DB_BTREE, DB_CREATE, 0600)) != 0) {
92 debug_print("DB->open: %s\n", db_strerror(ret));
93 db_uniq->close(db_uniq, 0);
94 db_uid->close(db_uid, 0);
97 debug_print("Uniq based database opened\n");
99 if ((ret = db_uid->associate(db_uid, NULL, db_uniq, get_secondary_key, 0)) != 0) {
100 debug_print("DB->associate: %s\n", db_strerror(ret));
101 db_uid->close(db_uid, 0);
102 db_uniq->close(db_uniq, 0);
105 debug_print("Databases associated\n");
107 uiddb = g_new0(UIDDB, 1);
108 uiddb->db_uid = db_uid;
109 uiddb->db_uniq = db_uniq;
115 void uiddb_close(UIDDB *uiddb)
117 g_return_if_fail(uiddb != NULL);
119 if (uiddb->db_uid != NULL)
120 uiddb->db_uid->close(uiddb->db_uid, 0);
121 if (uiddb->db_uniq != NULL)
122 uiddb->db_uniq->close(uiddb->db_uniq, 0);
125 void uiddb_free_msgdata(MessageData *msgdata)
127 g_free(msgdata->uniq);
128 g_free(msgdata->info);
129 g_free(msgdata->dir);
133 static DBT marshal(MessageData *msgdata)
138 memset(&dbt, 0, sizeof(dbt));
139 dbt.size = sizeof(msgdata->uid) + \
140 strlen(msgdata->uniq) + 1 + \
141 strlen(msgdata->info) + 1 + \
142 strlen(msgdata->dir) + 1;
143 dbt.data = g_malloc0(dbt.size);
147 #define ADD_DATA(dataptr, size) \
149 memcpy(ptr, dataptr, size); \
153 ADD_DATA(&msgdata->uid, sizeof(msgdata->uid));
154 ADD_DATA(msgdata->uniq, strlen(msgdata->uniq) + 1);
155 ADD_DATA(msgdata->info, strlen(msgdata->info) + 1);
156 ADD_DATA(msgdata->dir, strlen(msgdata->dir) + 1);
163 static MessageData *unmarshal(DBT dbt)
166 MessageData *msgdata;
169 msgdata = g_new0(MessageData, 1);
171 memcpy(&msgdata->uid, ptr, sizeof(msgdata->uid));
172 ptr += sizeof(msgdata->uid);
173 msgdata->uniq = g_strdup(ptr);
174 ptr += strlen(ptr) + 1;
175 msgdata->info = g_strdup(ptr);
176 ptr += strlen(ptr) + 1;
177 msgdata->dir = g_strdup(ptr);
182 guint32 uiddb_get_new_uid(UIDDB *uiddb)
187 guint32 uid, lastuid = -1;
189 g_return_val_if_fail(uiddb != NULL, 0);
191 lastuid = uiddb->lastuid;
193 if (uiddb->lastuid > 0)
194 return ++uiddb->lastuid;
196 ret = uiddb->db_uid->cursor(uiddb->db_uid, NULL, &cursor, 0);
198 debug_print("DB->cursor: %s\n", db_strerror(ret));
202 memset(&key, 0, sizeof(key));
203 memset(&data, 0, sizeof(data));
204 while ((ret = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
205 uid = *((guint32 *) key.data);
210 memset(&key, 0, sizeof(key));
211 memset(&data, 0, sizeof(data));
214 cursor->c_close(cursor);
216 uiddb->lastuid = ++lastuid;
220 MessageData *uiddb_get_entry_for_uid(UIDDB *uiddb, guint32 uid)
224 g_return_val_if_fail(uiddb, NULL);
226 memset(&key, 0, sizeof(key));
227 memset(&data, 0, sizeof(data));
229 key.size = sizeof(guint32);
232 if (uiddb->db_uid->get(uiddb->db_uid, NULL, &key, &data, 0) != 0)
235 return unmarshal(data);
238 MessageData *uiddb_get_entry_for_uniq(UIDDB *uiddb, gchar *uniq)
242 g_return_val_if_fail(uiddb, NULL);
244 memset(&key, 0, sizeof(key));
245 memset(&pkey, 0, sizeof(pkey));
246 memset(&data, 0, sizeof(data));
248 key.size = strlen(uniq);
251 if (uiddb->db_uniq->pget(uiddb->db_uniq, NULL, &key, &pkey, &data, 0) != 0)
254 return unmarshal(data);
257 void uiddb_delete_entry(UIDDB *uiddb, guint32 uid)
261 g_return_if_fail(uiddb);
263 memset(&key, 0, sizeof(key));
265 key.size = sizeof(guint32);
268 uiddb->db_uid->del(uiddb->db_uid, NULL, &key, 0);
271 void uiddb_insert_entry(UIDDB *uiddb, MessageData *msgdata)
276 g_return_if_fail(uiddb);
278 memset(&key, 0, sizeof(key));
279 memset(&data, 0, sizeof(data));
281 key.size = sizeof(guint32);
282 key.data = &msgdata->uid;
284 data = marshal(msgdata);
286 ret = uiddb->db_uid->put(uiddb->db_uid, NULL, &key, &data, 0);
288 debug_print("DB->put: %s\n", db_strerror(ret));
293 static int uiddb_uid_compare(const void *a, const void *b)
295 return *(guint32*)a - *(guint32*)b;
298 void uiddb_delete_entries_not_in_list(UIDDB *uiddb, MsgNumberList *list)
305 g_return_if_fail(uiddb);
309 ret = uiddb->db_uid->cursor(uiddb->db_uid, NULL, &cursor, DB_WRITECURSOR);
311 debug_print("DB->cursor: %s\n", db_strerror(ret));
315 uidcnt = g_slist_length(list);
316 uid_sorted = g_new(guint32, uidcnt);
317 for (i = 0; i < uidcnt; i++) {
318 uid_sorted[i] = GPOINTER_TO_INT(list->data);
319 list = g_slist_next(list);
322 memset(&key, 0, sizeof(key));
323 memset(&data, 0, sizeof(data));
324 while ((ret = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
325 guint32 uid = *((guint32 *) key.data);
327 if (bsearch(&uid, uid_sorted, uidcnt, sizeof(guint32), &uiddb_uid_compare) == NULL)
328 cursor->c_del(cursor, 0);
330 memset(&key, 0, sizeof(key));
331 memset(&data, 0, sizeof(data));
336 cursor->c_close(cursor);