Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120839160
mbdump.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
20 KB
Referenced Files
None
Subscribers
None
mbdump.c
View Options
/* mbdump.c -- Mailbox dump routines
* $Id: mbdump.c,v 1.30 2004/05/22 03:45:51 rjs3 Exp $
* Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any other legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include
<config.h>
#ifdef HAVE_UNISTD_H
#include
<unistd.h>
#endif
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<errno.h>
#include
<syslog.h>
#include
<sys/types.h>
#include
<fcntl.h>
#include
<netinet/in.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<ctype.h>
#include
<unistd.h>
#include
<dirent.h>
#include
<assert.h>
#include
"annotate.h"
#include
"exitcodes.h"
#include
"global.h"
#include
"imap_err.h"
#include
"imparse.h"
#include
"mailbox.h"
#include
"map.h"
#include
"mbdump.h"
#include
"mboxlist.h"
#include
"prot.h"
#include
"quota.h"
#include
"seen.h"
#include
"xmalloc.h"
#include
"util.h"
/* is this the active script? */
static
int
sieve_isactive
(
char
*
sievepath
,
char
*
name
)
{
char
filename
[
1024
];
char
linkname
[
1024
];
char
activelink
[
1024
];
char
*
file
,
*
link
;
int
len
;
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
sievepath
,
name
);
snprintf
(
linkname
,
sizeof
(
linkname
),
"%s/defaultbc"
,
sievepath
);
len
=
readlink
(
linkname
,
activelink
,
sizeof
(
activelink
)
-1
);
if
(
len
<
0
)
{
if
(
errno
!=
ENOENT
)
syslog
(
LOG_ERR
,
"readlink(defaultbc): %m"
);
return
0
;
}
activelink
[
len
]
=
'\0'
;
/* Only compare the part of the file after the last /,
* since that is what timsieved does */
file
=
strrchr
(
filename
,
'/'
);
link
=
strrchr
(
activelink
,
'/'
);
if
(
!
file
)
file
=
filename
;
else
file
++
;
if
(
!
link
)
link
=
activelink
;
else
link
++
;
if
(
!
strcmp
(
file
,
link
))
{
return
1
;
}
else
{
return
0
;
}
}
struct
dump_annotation_rock
{
struct
protstream
*
pout
;
const
char
*
tag
;
};
static
int
dump_annotations
(
const
char
*
mailbox
__attribute__
((
unused
)),
const
char
*
entry
,
const
char
*
userid
,
struct
annotation_data
*
attrib
,
void
*
rock
)
{
struct
dump_annotation_rock
*
ctx
=
(
struct
dump_annotation_rock
*
)
rock
;
/* "A-" userid entry */
/* entry is delimited by its leading / */
unsigned
long
ename_size
=
2
+
strlen
(
userid
)
+
strlen
(
entry
);
/* Transfer all attributes for this annotation, don't transfer size
* separately since that can be implicitly determined */
prot_printf
(
ctx
->
pout
,
" {%ld%s}
\r\n
A-%s%s (%ld {%d%s}
\r\n
%s {%d%s}
\r\n
%s)"
,
ename_size
,
(
!
ctx
->
tag
?
"+"
:
""
),
userid
,
entry
,
attrib
->
modifiedsince
,
attrib
->
size
,
(
!
ctx
->
tag
?
"+"
:
""
),
attrib
->
value
,
strlen
(
attrib
->
contenttype
),
(
!
ctx
->
tag
?
"+"
:
""
),
attrib
->
contenttype
);
return
0
;
}
int
dump_mailbox
(
const
char
*
tag
,
const
char
*
mbname
,
const
char
*
mbpath
,
const
char
*
mbacl
,
int
uid_start
,
struct
protstream
*
pin
,
struct
protstream
*
pout
,
struct
auth_state
*
auth_state
)
{
DIR
*
mbdir
=
NULL
;
int
r
=
0
;
struct
dirent
*
next
=
NULL
;
char
filename
[
MAX_MAILBOX_PATH
+
1024
];
int
filefd
;
const
char
*
base
;
unsigned
long
len
;
int
first
=
1
;
struct
mailbox
mb
;
struct
stat
sbuf
;
char
c
;
int
i
;
const
char
*
data_files
[]
=
{
"cyrus.header"
,
"cyrus.cache"
,
"cyrus.index"
,
NULL
};
/* non-null userid means we are moving the user */
const
char
*
userid
=
NULL
;
enum
{
SEEN_DB
=
0
,
SUBS_DB
=
1
};
char
*
user_data_files
[
3
];
int
domainlen
=
0
;
char
*
p
=
NULL
,
userbuf
[
81
];
assert
(
mbpath
);
if
(
config_virtdomains
&&
(
p
=
strchr
(
mbname
,
'!'
)))
domainlen
=
p
-
mbname
+
1
;
/* include separator */
if
(
!
strncmp
(
mbname
+
domainlen
,
"user."
,
5
)
&&
!
strchr
(
mbname
+
domainlen
+
5
,
'.'
))
{
strcpy
(
userbuf
,
mbname
+
domainlen
+
5
);
if
(
domainlen
)
sprintf
(
userbuf
+
strlen
(
userbuf
),
"@%.*s"
,
domainlen
-1
,
mbname
);
userid
=
userbuf
;
memset
(
user_data_files
,
0
,
sizeof
(
user_data_files
));
user_data_files
[
SEEN_DB
]
=
seen_getpath
(
userid
);
user_data_files
[
SUBS_DB
]
=
mboxlist_hash_usersubs
(
userid
);
}
mbdir
=
opendir
(
mbpath
);
if
(
!
mbdir
&&
errno
==
EACCES
)
{
syslog
(
LOG_ERR
,
"could not dump mailbox in %s (permission denied)"
,
mbpath
);
return
IMAP_PERMISSION_DENIED
;
}
else
if
(
!
mbdir
)
{
syslog
(
LOG_ERR
,
"could not dump mailbox in %s (unknown error)"
,
mbpath
);
return
IMAP_SYS_ERROR
;
}
r
=
mailbox_open_locked
(
mbname
,
mbpath
,
mbacl
,
auth_state
,
&
mb
,
0
);
if
(
r
)
{
closedir
(
mbdir
);
return
r
;
}
/* after this point we have to both close the directory and unlock
* the mailbox */
/* xxx check to ensure we have the cyrus.* files, but we send those last */
if
(
tag
)
prot_printf
(
pout
,
"%s DUMP "
,
tag
);
prot_putc
(
'('
,
pout
);
/* The first member is either a number (if it is a quota root), or NIL
* (if it isn't) */
{
struct
quota
quota
;
quota
.
root
=
(
char
*
)
mbname
;
/* xxx */
r
=
quota_read
(
&
quota
,
NULL
,
0
);
if
(
r
)
{
prot_printf
(
pout
,
"NIL "
);
if
(
r
==
IMAP_QUOTAROOT_NONEXISTENT
)
r
=
0
;
goto
dump_files
;
}
prot_printf
(
pout
,
"%d "
,
quota
.
limit
);
}
dump_files
:
while
((
next
=
readdir
(
mbdir
))
!=
NULL
)
{
char
*
name
=
next
->
d_name
;
/* Alias */
char
*
p
=
name
;
/* special case for '.'
(well, it gets '..' too) */
if
(
name
[
0
]
==
'.'
)
continue
;
/* skip non-message files */
while
(
*
p
&&
isdigit
((
int
)(
*
p
)))
p
++
;
if
(
p
[
0
]
!=
'.'
||
p
[
1
]
!=
'\0'
)
continue
;
/* ensure (number) is >= our target uid */
if
(
atoi
(
name
)
<
uid_start
)
continue
;
/* map file */
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
mbpath
,
name
);
filefd
=
open
(
filename
,
O_RDONLY
,
0666
);
if
(
filefd
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: open on %s: %m"
,
filename
);
r
=
IMAP_SYS_ERROR
;
goto
done
;
}
if
(
fstat
(
filefd
,
&
sbuf
)
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: fstat on %s: %m"
,
filename
);
fatal
(
"can't fstat message file"
,
EC_OSFILE
);
}
base
=
NULL
;
len
=
0
;
map_refresh
(
filefd
,
1
,
&
base
,
&
len
,
sbuf
.
st_size
,
filename
,
NULL
);
close
(
filefd
);
/* send filename, size, and contents */
if
(
first
)
{
prot_printf
(
pout
,
"{%d}
\r\n
"
,
strlen
(
name
));
if
(
!
tag
)
{
/* synchronize */
c
=
prot_getc
(
pin
);
eatline
(
pin
,
c
);
/* We eat it no matter what */
if
(
c
!=
'+'
)
{
/* Synchronization Failure, Abort! */
syslog
(
LOG_ERR
,
"Sync Error: expected '+' got '%c'"
,
c
);
r
=
IMAP_SERVER_UNAVAILABLE
;
goto
done
;
}
}
prot_printf
(
pout
,
"%s {%lu%s}
\r\n
"
,
name
,
len
,
(
!
tag
?
"+"
:
""
));
first
=
0
;
}
else
{
prot_printf
(
pout
,
" {%d%s}
\r\n
%s {%lu%s}
\r\n
"
,
strlen
(
name
),
(
!
tag
?
"+"
:
""
),
name
,
len
,
(
!
tag
?
"+"
:
""
));
}
prot_write
(
pout
,
base
,
len
);
map_free
(
&
base
,
&
len
);
}
for
(
i
=
0
;
data_files
[
i
];
i
++
)
{
/* map file */
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
mbpath
,
data_files
[
i
]);
filefd
=
open
(
filename
,
O_RDONLY
,
0666
);
if
(
filefd
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: open on %s: %m"
,
filename
);
r
=
IMAP_SYS_ERROR
;
goto
done
;
}
if
(
fstat
(
filefd
,
&
sbuf
)
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: fstat on %s: %m"
,
filename
);
fatal
(
"can't fstat message file"
,
EC_OSFILE
);
}
base
=
NULL
;
len
=
0
;
map_refresh
(
filefd
,
1
,
&
base
,
&
len
,
sbuf
.
st_size
,
filename
,
NULL
);
close
(
filefd
);
/* send filename, size, and contents */
if
(
first
)
{
prot_printf
(
pout
,
"{%d}
\r\n
"
,
strlen
(
data_files
[
i
]));
if
(
!
tag
)
{
/* synchronize */
c
=
prot_getc
(
pin
);
if
(
c
!=
'+'
)
{
/* Synchronization Failure, Abort! */
r
=
IMAP_SERVER_UNAVAILABLE
;
goto
done
;
}
else
{
eatline
(
pin
,
c
);
}
}
prot_printf
(
pout
,
"%s {%lu%s}
\r\n
"
,
data_files
[
i
],
len
,
(
!
tag
?
"+"
:
""
));
first
=
0
;
}
else
{
prot_printf
(
pout
,
" {%d%s}
\r\n
%s {%lu%s}
\r\n
"
,
strlen
(
data_files
[
i
]),
(
!
tag
?
"+"
:
""
),
data_files
[
i
],
len
,
(
!
tag
?
"+"
:
""
));
}
prot_write
(
pout
,
base
,
len
);
map_free
(
&
base
,
&
len
);
}
/* now dump annotations */
{
struct
dump_annotation_rock
actx
;
actx
.
tag
=
tag
;
actx
.
pout
=
pout
;
annotatemore_findall
(
mbname
,
"*"
,
dump_annotations
,
(
void
*
)
&
actx
,
NULL
);
}
if
(
userid
)
{
char
sieve_path
[
MAX_MAILBOX_PATH
];
int
sieve_usehomedir
=
config_getswitch
(
IMAPOPT_SIEVEUSEHOMEDIR
);
/* need to transfer seen, subs, and sieve files */
for
(
i
=
0
;
i
<
3
;
i
++
)
{
if
(
!
user_data_files
[
i
])
continue
;
/* map file */
filefd
=
open
(
user_data_files
[
i
],
O_RDONLY
,
0666
);
if
(
filefd
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: open on %s: %m (continuing)"
,
user_data_files
[
i
]);
/* but it is allowed to not exist, so... */
continue
;
}
if
(
fstat
(
filefd
,
&
sbuf
)
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: fstat on %s: %m"
,
user_data_files
[
i
]);
fatal
(
"can't fstat message file"
,
EC_OSFILE
);
}
base
=
NULL
;
len
=
0
;
map_refresh
(
filefd
,
1
,
&
base
,
&
len
,
sbuf
.
st_size
,
user_data_files
[
i
],
NULL
);
close
(
filefd
);
/* send user data file type, size, and contents */
/* No need to test synchronization, all mailboxes should have
* sent a file by this point! */
if
(
i
==
SEEN_DB
)
prot_printf
(
pout
,
" {4%s}
\r\n
SEEN"
,
(
!
tag
?
"+"
:
""
));
else
if
(
i
==
SUBS_DB
)
prot_printf
(
pout
,
"
{
4
%
s
}
\
r
\
nSUBS
",
(
!
tag
?
"+"
:
""
));
else
fatal
(
"unknown user_data_file"
,
EC_OSFILE
);
prot_printf
(
pout
,
" {%lu%s}
\r\n
"
,
len
,
(
!
tag
?
"+"
:
""
));
prot_write
(
pout
,
base
,
len
);
map_free
(
&
base
,
&
len
);
}
/* xxx can't use home directories currently
* (it makes almost no sense in the conext of a murder) */
if
(
!
sieve_usehomedir
)
{
char
ext_fname
[
2048
];
if
(
mbdir
)
closedir
(
mbdir
);
mbdir
=
NULL
;
if
(
domainlen
)
{
*
p
=
'\0'
;
/* separate domain!mboxname */
snprintf
(
sieve_path
,
sizeof
(
sieve_path
),
"%s%s%c/%s/%c/%s"
,
config_getstring
(
IMAPOPT_SIEVEDIR
),
FNAME_DOMAINDIR
,
(
char
)
dir_hash_c
(
mbname
),
mbname
,
(
char
)
dir_hash_c
(
p
+
6
),
p
+
6
);
/* unqualified userid */
*
p
=
'!'
;
/* reassemble domain!mboxname */
}
else
{
snprintf
(
sieve_path
,
sizeof
(
sieve_path
),
"%s/%c/%s"
,
config_getstring
(
IMAPOPT_SIEVEDIR
),
(
char
)
dir_hash_c
(
userid
),
userid
);
}
mbdir
=
opendir
(
sieve_path
);
if
(
mbdir
)
{
while
((
next
=
readdir
(
mbdir
))
!=
NULL
)
{
int
length
=
strlen
(
next
->
d_name
);
/* 7 == strlen(".script"); 3 == strlen(".bc") */
if
((
length
>=
7
&&
!
strcmp
(
next
->
d_name
+
(
length
-
7
),
".script"
))
||
(
length
>=
3
&&
!
strcmp
(
next
->
d_name
+
(
length
-
3
),
".bc"
)))
{
/* map file */
snprintf
(
filename
,
sizeof
(
filename
),
"%s/%s"
,
sieve_path
,
next
->
d_name
);
syslog
(
LOG_DEBUG
,
"wanting to dump %s"
,
filename
);
filefd
=
open
(
filename
,
O_RDONLY
,
0666
);
if
(
filefd
==
-1
)
{
/* non-fatal */
syslog
(
LOG_ERR
,
"IOERROR: open on %s: %m"
,
filename
);
continue
;
}
if
(
fstat
(
filefd
,
&
sbuf
)
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: fstat on %s: %m"
,
filename
);
fatal
(
"can't fstat message file"
,
EC_OSFILE
);
}
base
=
NULL
;
len
=
0
;
map_refresh
(
filefd
,
1
,
&
base
,
&
len
,
sbuf
.
st_size
,
filename
,
NULL
);
close
(
filefd
);
/* send filename w/tag + contents */
if
(
sieve_isactive
(
sieve_path
,
next
->
d_name
))
{
snprintf
(
ext_fname
,
sizeof
(
ext_fname
),
"SIEVED-%s"
,
next
->
d_name
);
}
else
{
snprintf
(
ext_fname
,
sizeof
(
ext_fname
),
"SIEVE-%s"
,
next
->
d_name
);
}
prot_printf
(
pout
,
" {%d%s}
\r\n
%s {%lu%s}
\r\n
"
,
strlen
(
ext_fname
),
(
!
tag
?
"+"
:
""
),
ext_fname
,
len
,
(
!
tag
?
"+"
:
""
));
prot_write
(
pout
,
base
,
len
);
map_free
(
&
base
,
&
len
);
}
}
}
}
/* transmit sieve script(s) */
/* free strings for user_data_files */
}
/* end if user */
prot_printf
(
pout
,
")
\r\n
"
);
done
:
prot_flush
(
pout
);
mailbox_close
(
&
mb
);
if
(
mbdir
)
closedir
(
mbdir
);
return
r
;
}
int
undump_mailbox
(
const
char
*
mbname
,
const
char
*
mbpath
,
const
char
*
mbacl
,
struct
protstream
*
pin
,
struct
protstream
*
pout
,
struct
auth_state
*
auth_state
)
{
struct
buf
file
,
data
;
char
c
;
int
quotaused
=
0
;
int
r
=
0
;
int
curfile
=
-1
;
const
char
*
userid
=
NULL
;
struct
mailbox
mb
;
char
sieve_path
[
2048
];
int
sieve_usehomedir
=
config_getswitch
(
IMAPOPT_SIEVEUSEHOMEDIR
);
int
domainlen
=
0
;
char
*
p
=
NULL
,
userbuf
[
81
];
memset
(
&
file
,
0
,
sizeof
(
file
));
memset
(
&
data
,
0
,
sizeof
(
data
));
c
=
getword
(
pin
,
&
data
);
if
(
config_virtdomains
&&
(
p
=
strchr
(
mbname
,
'!'
)))
domainlen
=
p
-
mbname
+
1
;
/* include separator */
if
(
!
strncmp
(
mbname
+
domainlen
,
"user."
,
5
)
&&
!
strchr
(
mbname
+
domainlen
+
5
,
'.'
))
{
strcpy
(
userbuf
,
mbname
+
domainlen
+
5
);
if
(
domainlen
)
sprintf
(
userbuf
+
strlen
(
userbuf
),
"@%.*s"
,
domainlen
-1
,
mbname
);
userid
=
userbuf
;
if
(
!
sieve_usehomedir
)
{
if
(
domainlen
)
{
*
p
=
'\0'
;
/* separate domain!mboxname */
snprintf
(
sieve_path
,
sizeof
(
sieve_path
),
"%s%s%c/%s/%c/%s"
,
config_getstring
(
IMAPOPT_SIEVEDIR
),
FNAME_DOMAINDIR
,
(
char
)
dir_hash_c
(
mbname
),
mbname
,
(
char
)
dir_hash_c
(
p
+
6
),
p
+
6
);
/* unqualified userid */
*
p
=
'!'
;
/* reassemble domain!mboxname */
}
else
{
snprintf
(
sieve_path
,
sizeof
(
sieve_path
),
"%s/%c/%s"
,
config_getstring
(
IMAPOPT_SIEVEDIR
),
(
char
)
dir_hash_c
(
userid
),
userid
);
}
}
}
/* we better be in a list now */
if
(
c
!=
'('
||
data
.
s
[
0
])
{
freebuf
(
&
data
);
eatline
(
pin
,
c
);
return
IMAP_PROTOCOL_BAD_PARAMETERS
;
}
/* We should now have a number or a NIL */
c
=
getword
(
pin
,
&
data
);
if
(
!
strcmp
(
data
.
s
,
"NIL"
))
{
/* Remove any existing quotaroot */
mboxlist_unsetquota
(
mbname
);
}
else
if
(
imparse_isnumber
(
data
.
s
))
{
/* Set a Quota */
mboxlist_setquota
(
mbname
,
atoi
(
data
.
s
),
0
);
}
else
{
/* Huh? */
freebuf
(
&
data
);
eatline
(
pin
,
c
);
return
IMAP_PROTOCOL_BAD_PARAMETERS
;
}
if
(
c
!=
' '
&&
c
!=
')'
)
{
freebuf
(
&
data
);
eatline
(
pin
,
c
);
return
IMAP_PROTOCOL_BAD_PARAMETERS
;
}
else
if
(
c
==
')'
)
{
goto
done
;
}
r
=
mailbox_open_locked
(
mbname
,
mbpath
,
mbacl
,
auth_state
,
&
mb
,
0
);
if
(
r
)
goto
done
;
while
(
1
)
{
char
fnamebuf
[
MAX_MAILBOX_PATH
+
1024
];
char
*
seen_file
=
NULL
;
c
=
getastring
(
pin
,
pout
,
&
file
);
if
(
c
!=
' '
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
if
(
!
strncmp
(
file
.
s
,
"A-"
,
2
))
{
/* Annotation */
char
*
userid
;
char
*
annotation
;
char
*
contenttype
;
char
*
content
;
size_t
contentsize
;
time_t
modtime
=
0
;
int
i
;
for
(
i
=
2
;
file
.
s
[
i
];
i
++
)
{
if
(
file
.
s
[
i
]
==
'/'
)
break
;
}
if
(
!
file
.
s
[
i
])
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
userid
=
xmalloc
(
i
-2
+
1
);
memcpy
(
userid
,
&
(
file
.
s
[
2
]),
i
-2
);
userid
[
i
-2
]
=
'\0'
;
annotation
=
xstrdup
(
&
(
file
.
s
[
i
]));
if
(
prot_getc
(
pin
)
!=
'('
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
/* Parse the modtime */
c
=
getword
(
pin
,
&
data
);
if
(
c
!=
' '
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
if
(
data
.
s
[
0
]
==
'\0'
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
for
(
p
=
data
.
s
;
*
p
;
p
++
)
{
if
(
!
isdigit
((
int
)
*
p
))
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
modtime
=
modtime
*
10
+
*
p
-
'0'
;
/* xxx - we won't catch overflow here, but we really
* don't care *THAT* much, do we? */
}
c
=
getbastring
(
pin
,
pout
,
&
data
);
/* xxx binary */
content
=
xstrdup
(
data
.
s
);
contentsize
=
data
.
len
;
if
(
c
!=
' '
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
c
=
getastring
(
pin
,
pout
,
&
data
);
contenttype
=
xstrdup
(
data
.
s
);
if
(
c
!=
')'
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
annotatemore_write_entry
(
mbname
,
annotation
,
userid
,
content
,
contenttype
,
contentsize
,
modtime
,
NULL
);
free
(
userid
);
free
(
annotation
);
free
(
content
);
free
(
contenttype
);
c
=
prot_getc
(
pin
);
if
(
c
==
')'
)
break
;
/* that was the last item */
else
if
(
c
!=
' '
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
continue
;
}
c
=
getbastring
(
pin
,
pout
,
&
data
);
if
(
c
!=
' '
&&
c
!=
')'
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
if
(
userid
&&
!
strcmp
(
file
.
s
,
"SUBS"
))
{
/* overwriting this outright is absolutely what we want to do */
char
*
s
=
mboxlist_hash_usersubs
(
userid
);
strlcpy
(
fnamebuf
,
s
,
sizeof
(
fnamebuf
));
free
(
s
);
}
else
if
(
userid
&&
!
strcmp
(
file
.
s
,
"SEEN"
))
{
seen_file
=
seen_getpath
(
userid
);
snprintf
(
fnamebuf
,
sizeof
(
fnamebuf
),
"%s.%d"
,
seen_file
,
getpid
());
}
else
if
(
userid
&&
!
strncmp
(
file
.
s
,
"SIEVE"
,
5
))
{
int
isdefault
=
!
strncmp
(
file
.
s
,
"SIEVED"
,
6
);
char
*
realname
;
int
ret
;
/* skip prefixes */
if
(
isdefault
)
realname
=
file
.
s
+
7
;
else
realname
=
file
.
s
+
6
;
if
(
sieve_usehomedir
)
{
/* xxx! */
syslog
(
LOG_ERR
,
"dropping sieve file %s since this host is "
\
"configured for sieve_usehomedir"
,
realname
);
continue
;
}
else
{
if
(
snprintf
(
fnamebuf
,
sizeof
(
fnamebuf
),
"%s/%s"
,
sieve_path
,
realname
)
==
-1
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
else
if
(
isdefault
)
{
char
linkbuf
[
2048
];
snprintf
(
linkbuf
,
sizeof
(
linkbuf
),
"%s/defaultbc"
,
sieve_path
);
ret
=
symlink
(
realname
,
linkbuf
);
if
(
ret
&&
errno
==
ENOENT
)
{
if
(
cyrus_mkdir
(
linkbuf
,
0750
)
==
0
)
{
ret
=
symlink
(
realname
,
linkbuf
);
}
}
if
(
ret
)
{
syslog
(
LOG_ERR
,
"symlink(%s, %s): %m"
,
realname
,
linkbuf
);
/* Non-fatal,
let's get the file transferred if we can */
}
}
}
}
else
{
if
(
snprintf
(
fnamebuf
,
sizeof
(
fnamebuf
),
"%s/%s"
,
mbpath
,
file
.
s
)
==
-1
)
{
r
=
IMAP_PROTOCOL_ERROR
;
goto
done
;
}
if
(
strncmp
(
file
.
s
,
"cyrus."
,
6
))
{
/* it doesn't match cyrus.*, so its a message file.
* charge it against the quota */
quotaused
+=
data
.
len
;
}
}
/* if we haven't opened it, do so */
curfile
=
open
(
fnamebuf
,
O_WRONLY
|
O_TRUNC
|
O_CREAT
,
0640
);
if
(
curfile
==
-1
&&
errno
==
ENOENT
)
{
if
(
cyrus_mkdir
(
fnamebuf
,
0750
)
==
0
)
{
curfile
=
open
(
fnamebuf
,
O_WRONLY
|
O_TRUNC
|
O_CREAT
,
0640
);
}
}
if
(
curfile
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: creating %s: %m"
,
fnamebuf
);
r
=
IMAP_IOERROR
;
goto
done
;
}
if
(
write
(
curfile
,
data
.
s
,
data
.
len
)
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: writing %s: %m"
,
fnamebuf
);
r
=
IMAP_IOERROR
;
goto
done
;
}
close
(
curfile
);
/* we were operating on the seen state, so merge it and cleanup */
if
(
seen_file
)
{
seen_merge
(
fnamebuf
,
seen_file
);
free
(
seen_file
);
seen_file
=
NULL
;
unlink
(
fnamebuf
);
}
if
(
c
==
')'
)
break
;
}
if
(
!
r
&&
quotaused
)
{
struct
quota
quota
;
char
quota_root
[
MAX_MAILBOX_PATH
+
1
];
struct
txn
*
tid
=
NULL
;
if
(
quota_findroot
(
quota_root
,
sizeof
(
quota_root
),
mbname
))
{
/* update the quota file */
memset
(
&
quota
,
0
,
sizeof
(
quota
));
quota
.
root
=
quota_root
;
r
=
quota_read
(
&
quota
,
&
tid
,
1
);
if
(
!
r
)
{
quota
.
used
+=
quotaused
;
r
=
quota_write
(
&
quota
,
&
tid
);
if
(
!
r
)
quota_commit
(
&
tid
);
}
else
{
syslog
(
LOG_ERR
,
"could not lock quota file for %s (%s)"
,
quota_root
,
error_message
(
r
));
}
if
(
r
)
{
syslog
(
LOG_ERR
,
"failed writing quota file for %s (%s)"
,
quota_root
,
error_message
(
r
));
}
}
}
done
:
/* eat the rest of the line, we have atleast a \r\n coming */
eatline
(
pin
,
c
);
freebuf
(
&
file
);
freebuf
(
&
data
);
if
(
curfile
>=
0
)
close
(
curfile
);
mailbox_close
(
&
mb
);
return
r
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Apr 24, 2:09 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18833024
Default Alt Text
mbdump.c (20 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline