Implement IMAP SPECIAL-USE mailboxes
This commit is contained in:
@@ -71,6 +71,24 @@ typedef enum {
|
||||
/* DOCTYPE_COLLECTION flags: */
|
||||
#define STORE_COLLECTION_FLAG_HIERARCHY_ONLY (1 << 0)
|
||||
#define STORE_COLLECTION_FLAG_NON_SUBSCRIBED (1 << 1)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_ALL (1 << 2)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_ARCHIVE (1 << 3)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_DRAFTS (1 << 4)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_FLAGGED (1 << 5)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_JUNK (1 << 6)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_SENT (1 << 7)
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_TRASH (1 << 8)
|
||||
|
||||
#define STORE_COLLECTION_FLAG_SPECIAL_USE_MASK \
|
||||
(STORE_COLLECTION_FLAG_SPECIAL_ALL | STORE_COLLECTION_FLAG_SPECIAL_ARCHIVE | \
|
||||
STORE_COLLECTION_FLAG_SPECIAL_DRAFTS | STORE_COLLECTION_FLAG_SPECIAL_FLAGGED | \
|
||||
STORE_COLLECTION_FLAG_SPECIAL_JUNK | STORE_COLLECTION_FLAG_SPECIAL_SENT | \
|
||||
STORE_COLLECTION_FLAG_SPECIAL_TRASH)
|
||||
|
||||
/* Stable GUIDs used by both the Store and protocol agents. */
|
||||
#define STORE_MAIL_INBOX_GUID 6
|
||||
#define STORE_MAIL_DRAFTS_GUID 7
|
||||
#define STORE_MAIL_ARCHIVES_GUID 8
|
||||
|
||||
|
||||
/** end of document flags **/
|
||||
|
||||
@@ -3,6 +3,7 @@ add_executable(bongoimap
|
||||
capabilities.c
|
||||
idle.c
|
||||
uidplus.c
|
||||
special-use.c
|
||||
copy.c
|
||||
event.c
|
||||
fetch.c
|
||||
@@ -53,4 +54,13 @@ if(BUILD_TESTING)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_test(NAME imap-uidplus COMMAND imap-uidplus-test)
|
||||
|
||||
add_executable(imap-special-use-test
|
||||
tests/special-use-test.c
|
||||
special-use.c
|
||||
)
|
||||
target_include_directories(imap-special-use-test PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_test(NAME imap-special-use COMMAND imap-special-use-test)
|
||||
endif()
|
||||
|
||||
@@ -55,7 +55,8 @@ IMAPFormatCapabilities(char *buffer, size_t buffer_size,
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (!Append(buffer, buffer_size, &length,
|
||||
"* CAPABILITY IMAP4rev1 IMAP4 NAMESPACE IDLE UIDPLUS MOVE XSENDER") ||
|
||||
"* CAPABILITY IMAP4rev1 IMAP4 NAMESPACE IDLE UIDPLUS MOVE "
|
||||
"SPECIAL-USE CREATE-SPECIAL-USE XSENDER") ||
|
||||
(!authenticated && tls_active &&
|
||||
!Append(buffer, buffer_size, &length,
|
||||
" AUTH=PLAIN AUTH=LOGIN SASL-IR")) ||
|
||||
|
||||
+50
-5
@@ -46,6 +46,7 @@
|
||||
#include "capabilities.h"
|
||||
#include "idle.h"
|
||||
#include "uidplus.h"
|
||||
#include "special-use.h"
|
||||
|
||||
ImapGlobal Imap;
|
||||
|
||||
@@ -528,6 +529,14 @@ ParseCollectionLine(char *buffer, FolderInformation *folder)
|
||||
if ((ptr > start) &&
|
||||
(*ptr == ' ')) {
|
||||
folder->flags = atol(start);
|
||||
/* Stores created before SPECIAL-USE support did not have
|
||||
* role bits. The stable default-folder GUIDs preserve
|
||||
* those roles across renames without a schema migration. */
|
||||
if (folder->guid == STORE_MAIL_DRAFTS_GUID) {
|
||||
folder->flags |= STORE_COLLECTION_FLAG_SPECIAL_DRAFTS;
|
||||
} else if (folder->guid == STORE_MAIL_ARCHIVES_GUID) {
|
||||
folder->flags |= STORE_COLLECTION_FLAG_SPECIAL_ARCHIVE;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
len = strlen(ptr);
|
||||
@@ -1157,6 +1166,7 @@ ImapCommandCreate(void *param)
|
||||
char *pathUtf8;
|
||||
int len;
|
||||
FolderInformation *folder;
|
||||
uint32_t specialUseFlags;
|
||||
|
||||
if ((ccode = CheckState(session, STATE_AUTH)) != STATUS_CONTINUE) {
|
||||
return(SendError(session->client.conn, session->command.tag, "CREATE", ccode));
|
||||
@@ -1171,6 +1181,12 @@ ImapCommandCreate(void *param)
|
||||
return(SendError(session->client.conn, session->command.tag, "CREATE", ccode));
|
||||
}
|
||||
|
||||
if (!IMAPSpecialUseParseCreateOptions(ptr, &specialUseFlags)) {
|
||||
FreePathArgument(&path);
|
||||
return(SendError(session->client.conn, session->command.tag, "CREATE",
|
||||
STATUS_INVALID_ARGUMENT));
|
||||
}
|
||||
|
||||
/* prohibition of naming a folder the same name as the userid; don't know why (rprice) */
|
||||
if (XplStrCaseCmp(path.name, session->user.name) == 0) {
|
||||
FreePathArgument(&path);
|
||||
@@ -1212,12 +1228,14 @@ ImapCommandCreate(void *param)
|
||||
}
|
||||
|
||||
/* this folder is just hierarchy. Make it a real folder */
|
||||
if (NMAPSendCommandF(session->store.conn, "FLAG /mail/%s -%u\r\n", pathUtf8, STORE_COLLECTION_FLAG_HIERARCHY_ONLY) == -1) {
|
||||
folder->flags &= ~(STORE_COLLECTION_FLAG_HIERARCHY_ONLY |
|
||||
STORE_COLLECTION_FLAG_SPECIAL_USE_MASK);
|
||||
folder->flags |= specialUseFlags;
|
||||
if (NMAPSendCommandF(session->store.conn, "FLAG /mail/%s %lu\r\n",
|
||||
pathUtf8, folder->flags) == -1) {
|
||||
MemFree(pathUtf8);
|
||||
return(STATUS_NMAP_COMM_ERROR);
|
||||
}
|
||||
|
||||
folder->flags &= ~(STORE_COLLECTION_FLAG_HIERARCHY_ONLY);
|
||||
|
||||
MemFree(pathUtf8);
|
||||
ccode = NMAPReadResponse(session->store.conn, NULL, 0, 0);
|
||||
@@ -1234,7 +1252,15 @@ ImapCommandCreate(void *param)
|
||||
return(SendError(session->client.conn, session->command.tag, "CREATE", ccode));
|
||||
}
|
||||
|
||||
if (NMAPSendCommandF(session->store.conn, "CREATE \"/mail/%s\"\r\n", pathUtf8) == -1) {
|
||||
if (specialUseFlags != 0) {
|
||||
ccode = NMAPSendCommandF(session->store.conn,
|
||||
"CREATE \"/mail/%s\" 0 %u\r\n",
|
||||
pathUtf8, (unsigned int)specialUseFlags);
|
||||
} else {
|
||||
ccode = NMAPSendCommandF(session->store.conn,
|
||||
"CREATE \"/mail/%s\"\r\n", pathUtf8);
|
||||
}
|
||||
if (ccode == -1) {
|
||||
MemFree(pathUtf8);
|
||||
return(SendError(session->client.conn, session->command.tag, "CREATE", STATUS_NMAP_COMM_ERROR));
|
||||
}
|
||||
@@ -1746,7 +1772,26 @@ ImapCommandUnsubscribe(void *param)
|
||||
__inline static long
|
||||
SendFolderInfo(Connection *conn, const char *command, FolderInformation *folder)
|
||||
{
|
||||
if (ConnWriteF(conn, "* %s (%s) \"/\" \"%s\"\r\n", command, ((folder->flags & STORE_COLLECTION_FLAG_HIERARCHY_ONLY) == 0) ? "" : "\\NoSelect", folder->name.utf7) != -1) {
|
||||
char attributes[128];
|
||||
char specialUse[96];
|
||||
size_t length = 0;
|
||||
size_t specialUseLength;
|
||||
|
||||
attributes[0] = '\0';
|
||||
if (folder->flags & STORE_COLLECTION_FLAG_HIERARCHY_ONLY) {
|
||||
memcpy(attributes, "\\NoSelect", sizeof("\\NoSelect"));
|
||||
length = strlen(attributes);
|
||||
}
|
||||
specialUseLength = IMAPSpecialUseFormat((uint32_t)folder->flags,
|
||||
specialUse, sizeof(specialUse));
|
||||
if (specialUseLength != 0 &&
|
||||
length + (length ? 1 : 0) + specialUseLength < sizeof(attributes)) {
|
||||
if (length) attributes[length++] = ' ';
|
||||
memcpy(attributes + length, specialUse, specialUseLength + 1);
|
||||
}
|
||||
|
||||
if (ConnWriteF(conn, "* %s (%s) \"/\" \"%s\"\r\n", command,
|
||||
attributes, folder->name.utf7) != -1) {
|
||||
return(STATUS_CONTINUE);
|
||||
}
|
||||
return(STATUS_ABORT);
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/****************************************************************************
|
||||
* <Novell-copyright>
|
||||
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail, you
|
||||
* may find current contact information at www.novell.com.
|
||||
* </Novell-copyright>
|
||||
****************************************************************************/
|
||||
|
||||
#include "special-use.h"
|
||||
|
||||
#include <bongostore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
uint32_t flag;
|
||||
} SpecialUseAttribute;
|
||||
|
||||
static const SpecialUseAttribute Attributes[] = {
|
||||
{ "\\All", STORE_COLLECTION_FLAG_SPECIAL_ALL },
|
||||
{ "\\Archive", STORE_COLLECTION_FLAG_SPECIAL_ARCHIVE },
|
||||
{ "\\Drafts", STORE_COLLECTION_FLAG_SPECIAL_DRAFTS },
|
||||
{ "\\Flagged", STORE_COLLECTION_FLAG_SPECIAL_FLAGGED },
|
||||
{ "\\Junk", STORE_COLLECTION_FLAG_SPECIAL_JUNK },
|
||||
{ "\\Sent", STORE_COLLECTION_FLAG_SPECIAL_SENT },
|
||||
{ "\\Trash", STORE_COLLECTION_FLAG_SPECIAL_TRASH }
|
||||
};
|
||||
|
||||
static const char *
|
||||
SkipSpace(const char *text)
|
||||
{
|
||||
while (*text && isspace((unsigned char)*text)) text++;
|
||||
return text;
|
||||
}
|
||||
|
||||
static int
|
||||
TokenEquals(const char *start, size_t length, const char *expected)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (strlen(expected) != length) return 0;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (tolower((unsigned char)start[i]) !=
|
||||
tolower((unsigned char)expected[i])) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
IMAPSpecialUseParseCreateOptions(const char *text, uint32_t *flags)
|
||||
{
|
||||
const char *start;
|
||||
size_t i;
|
||||
uint32_t result = 0;
|
||||
|
||||
if (!text || !flags) return 0;
|
||||
text = SkipSpace(text);
|
||||
if (!*text) {
|
||||
*flags = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
start = text;
|
||||
while (*text && !isspace((unsigned char)*text) && *text != '(') text++;
|
||||
if (!TokenEquals(start, (size_t)(text - start), "USE")) return 0;
|
||||
text = SkipSpace(text);
|
||||
if (*text++ != '(') return 0;
|
||||
|
||||
for (;;) {
|
||||
text = SkipSpace(text);
|
||||
if (*text == ')') {
|
||||
text = SkipSpace(text + 1);
|
||||
if (*text || result == 0) return 0;
|
||||
*flags = result;
|
||||
return 1;
|
||||
}
|
||||
if (!*text) return 0;
|
||||
|
||||
start = text;
|
||||
while (*text && !isspace((unsigned char)*text) && *text != ')') text++;
|
||||
for (i = 0; i < sizeof(Attributes) / sizeof(Attributes[0]); i++) {
|
||||
if (TokenEquals(start, (size_t)(text - start), Attributes[i].name)) {
|
||||
if (result & Attributes[i].flag) return 0;
|
||||
result |= Attributes[i].flag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == sizeof(Attributes) / sizeof(Attributes[0])) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
IMAPSpecialUseFormat(uint32_t flags, char *buffer, size_t buffer_size)
|
||||
{
|
||||
size_t i;
|
||||
size_t length = 0;
|
||||
|
||||
if (!buffer || buffer_size == 0) return 0;
|
||||
buffer[0] = '\0';
|
||||
|
||||
for (i = 0; i < sizeof(Attributes) / sizeof(Attributes[0]); i++) {
|
||||
int written;
|
||||
if (!(flags & Attributes[i].flag)) continue;
|
||||
written = snprintf(buffer + length, buffer_size - length, "%s%s",
|
||||
length ? " " : "", Attributes[i].name);
|
||||
if (written < 0 || (size_t)written >= buffer_size - length) {
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
length += (size_t)written;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/****************************************************************************
|
||||
* <Novell-copyright>
|
||||
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail, you
|
||||
* may find current contact information at www.novell.com.
|
||||
* </Novell-copyright>
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef BONGO_IMAP_SPECIAL_USE_H
|
||||
#define BONGO_IMAP_SPECIAL_USE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int IMAPSpecialUseParseCreateOptions(const char *text, uint32_t *flags);
|
||||
size_t IMAPSpecialUseFormat(uint32_t flags, char *buffer, size_t buffer_size);
|
||||
|
||||
#endif
|
||||
@@ -37,6 +37,8 @@ main(void)
|
||||
assert(strstr(buffer, "IDLE"));
|
||||
assert(strstr(buffer, "UIDPLUS"));
|
||||
assert(strstr(buffer, "MOVE"));
|
||||
assert(strstr(buffer, "SPECIAL-USE"));
|
||||
assert(strstr(buffer, "CREATE-SPECIAL-USE"));
|
||||
assert(strstr(buffer, "XSENDER"));
|
||||
assert(strstr(buffer, "LOGINDISABLED"));
|
||||
assert(!strstr(buffer, "STARTTLS"));
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
* <Novell-copyright>
|
||||
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc.
|
||||
*
|
||||
* To contact Novell about this file by physical or electronic mail, you
|
||||
* may find current contact information at www.novell.com.
|
||||
* </Novell-copyright>
|
||||
****************************************************************************/
|
||||
|
||||
#include "special-use.h"
|
||||
|
||||
#include <bongostore.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
uint32_t flags;
|
||||
char buffer[96];
|
||||
|
||||
assert(IMAPSpecialUseParseCreateOptions("", &flags));
|
||||
assert(flags == 0);
|
||||
assert(IMAPSpecialUseParseCreateOptions(" USE (\\Sent \\Archive) ", &flags));
|
||||
assert(flags == (STORE_COLLECTION_FLAG_SPECIAL_SENT |
|
||||
STORE_COLLECTION_FLAG_SPECIAL_ARCHIVE));
|
||||
assert(!IMAPSpecialUseParseCreateOptions("USE ()", &flags));
|
||||
assert(!IMAPSpecialUseParseCreateOptions("USE (\\Sent \\Sent)", &flags));
|
||||
assert(!IMAPSpecialUseParseCreateOptions("USE (\\Unknown)", &flags));
|
||||
assert(!IMAPSpecialUseParseCreateOptions("OTHER (\\Sent)", &flags));
|
||||
|
||||
flags = STORE_COLLECTION_FLAG_SPECIAL_DRAFTS |
|
||||
STORE_COLLECTION_FLAG_SPECIAL_TRASH;
|
||||
assert(IMAPSpecialUseFormat(flags, buffer, sizeof(buffer)) > 0);
|
||||
assert(strcmp(buffer, "\\Drafts \\Trash") == 0);
|
||||
assert(IMAPSpecialUseFormat(0, buffer, sizeof(buffer)) == 0);
|
||||
assert(buffer[0] == '\0');
|
||||
assert(IMAPSpecialUseFormat(flags, buffer, 4) == 0);
|
||||
assert(buffer[0] == '\0');
|
||||
return 0;
|
||||
}
|
||||
@@ -646,14 +646,17 @@ StoreCommandLoop(StoreClient *client)
|
||||
break;
|
||||
|
||||
case STORE_COMMAND_CREATE:
|
||||
/* CREATE <collection name> [<guid>] */
|
||||
/* CREATE <collection name> [<guid> [<flags>]] */
|
||||
|
||||
guid = 0;
|
||||
ulong = 0;
|
||||
if (TOKEN_OK == (ccode = RequireStore(client)) &&
|
||||
TOKEN_OK == (ccode = CheckTokC(client, n, 2, 3)) &&
|
||||
(n <= 2 || TOKEN_OK == (ccode = ParseGUID(client, tokens[2], &guid))))
|
||||
TOKEN_OK == (ccode = CheckTokC(client, n, 2, 4)) &&
|
||||
(n <= 2 || (n == 4 && strcmp(tokens[2], "0") == 0) ||
|
||||
TOKEN_OK == (ccode = ParseGUID(client, tokens[2], &guid))) &&
|
||||
(n <= 3 || TOKEN_OK == (ccode = ParseUnsignedLong(client, tokens[3], &ulong))))
|
||||
{
|
||||
ccode = StoreCommandCREATE(client, tokens[1], guid);
|
||||
ccode = StoreCommandCREATE(client, tokens[1], guid, (uint32_t)ulong);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1686,7 +1689,7 @@ finish:
|
||||
// FIXME: doesn't detect all error conditions
|
||||
// [LOCKING] Create(X) => RwLock(Parent(X))
|
||||
CCode
|
||||
StoreCommandCREATE(StoreClient *client, char *name, uint64_t guid)
|
||||
StoreCommandCREATE(StoreClient *client, char *name, uint64_t guid, uint32_t flags)
|
||||
{
|
||||
StoreObject object;
|
||||
StoreObject container;
|
||||
@@ -1725,6 +1728,7 @@ StoreCommandCREATE(StoreClient *client, char *name, uint64_t guid)
|
||||
memset(&object, 0, sizeof(StoreObject));
|
||||
object.type = STORE_DOCTYPE_FOLDER;
|
||||
object.guid = guid;
|
||||
object.flags = flags;
|
||||
strncpy(object.filename, name, MAX_FILE_NAME);
|
||||
|
||||
ret = StoreObjectCreate(client, &object);
|
||||
|
||||
@@ -158,7 +158,8 @@ CCode StoreCommandCOOKIELIST(StoreClient *client);
|
||||
|
||||
CCode StoreCommandCOPY(StoreClient *client, StoreObject *object, StoreObject *collection);
|
||||
|
||||
CCode StoreCommandCREATE(StoreClient *client, char *collection, uint64_t guid);
|
||||
CCode StoreCommandCREATE(StoreClient *client, char *collection, uint64_t guid,
|
||||
uint32_t flags);
|
||||
|
||||
CCode StoreCommandDELETE(StoreClient *client, StoreObject *object);
|
||||
|
||||
|
||||
@@ -86,11 +86,14 @@ StoreObjectDBCreate(StoreClient *client)
|
||||
|
||||
collection.guid = STORE_MAIL_DRAFTS_GUID;
|
||||
snprintf(collection.filename, MAX_FILE_NAME, "/mail/drafts");
|
||||
collection.flags = STORE_COLLECTION_FLAG_SPECIAL_DRAFTS;
|
||||
StoreObjectCreate(client, &collection);
|
||||
|
||||
collection.guid = STORE_MAIL_ARCHIVES_GUID;
|
||||
snprintf(collection.filename, MAX_FILE_NAME, "/mail/archives");
|
||||
collection.flags = STORE_COLLECTION_FLAG_SPECIAL_ARCHIVE;
|
||||
StoreObjectCreate(client, &collection);
|
||||
collection.flags = 0;
|
||||
|
||||
collection.guid = STORE_ADDRESSBOOK_PERSONAL_GUID;
|
||||
snprintf(collection.filename, MAX_FILE_NAME, "/addressbook/personal");
|
||||
|
||||
@@ -453,9 +453,6 @@ void LogicalLockDestroy();
|
||||
#define STORE_CALENDARS_GUID 3
|
||||
#define STORE_ADDRESBOOK_GUID 4
|
||||
#define STORE_MAIL_GUID 5
|
||||
#define STORE_MAIL_INBOX_GUID 6
|
||||
#define STORE_MAIL_DRAFTS_GUID 7
|
||||
#define STORE_MAIL_ARCHIVES_GUID 8
|
||||
#define STORE_ADDRESSBOOK_PERSONAL_GUID 9
|
||||
#define STORE_ADDRESSBOOK_COLLECTED_GUID 10
|
||||
#define STORE_PREFERENCES_GUID 11
|
||||
|
||||
Reference in New Issue
Block a user