Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
28d63fd9
...
28d63fd9026b85abd7f244d043d41ee6b7434140
authored
2004-01-08 16:28:40 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Re-implemented via AMD.
1 parent
5ba7cf41
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
96 additions
and
1338 deletions
mailbox/mh/mbox.c
mailbox/mh/mbox.c
View file @
28d63fd
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001, 2002, 2003,
2004 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
...
...
@@ -61,951 +62,65 @@
#include <mailutils/observer.h>
#include <mailbox0.h>
#include <registrar0.h>
#include <amd.h>
#define MAX_OPEN_STREAMS 16
/* Notifications ADD_MESG. */
#define DISPATCH_ADD_MSG(mbox,mhd) \
do \
{ \
int bailing = 0; \
monitor_unlock (mbox->monitor); \
if (mbox->observable) \
bailing = observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mhd)->msg_count; \
locker_unlock (mbox->locker); \
return EINTR; \
} \
monitor_wrlock (mbox->monitor); \
} while (0);
/* Note: In this particular implementation the message sequence number
serves also as its UID. This allows to avoid many problems related
to keeping the uids in the headers of the messages. */
struct
_mh_data
;
struct
_mh_message
{
struct
_mh_message
*
next
;
struct
_mh_message
*
prev
;
stream_t
stream
;
/* Associated file stream */
off_t
body_start
;
/* Offset of body start in the message file */
off_t
body_end
;
/* Offset of body end (size of file, effectively)*/
size_t
seq_number
;
/* message sequence number */
int
attr_flags
;
/* Attribute flags */
int
deleted
;
/* Was the message originally deleted */
time_t
mtime
;
/* Time of last modification */
size_t
header_lines
;
/* Number of lines in the header part */
size_t
body_lines
;
/* Number of lines in the body */
message_t
message
;
/* Corresponding message_t */
struct
_mh_data
*
mhd
;
/* Back pointer. */
};
struct
_mh_data
{
/* List of messages: */
size_t
msg_count
;
/* number of messages in the list */
struct
_mh_message
*
msg_head
;
/* First */
struct
_mh_message
*
msg_tail
;
/* Last */
unsigned
long
uidvalidity
;
char
*
name
;
/* Directory name */
/* Pool of open message streams */
struct
_mh_message
*
msg_pool
[
MAX_OPEN_STREAMS
];
int
pool_first
;
/* Index to the first used entry in msg_pool */
int
pool_last
;
/* Index to the first free entry in msg_pool */
time_t
mtime
;
/* Time of last modification */
mailbox_t
mailbox
;
/* Back pointer. */
};
static
void
mh_destroy
__P
((
mailbox_t
mailbox
));
static
int
mh_open
__P
((
mailbox_t
,
int
));
static
int
mh_close
__P
((
mailbox_t
));
static
int
mh_get_message
__P
((
mailbox_t
,
size_t
,
message_t
*
));
static
int
mh_append_message
__P
((
mailbox_t
,
message_t
));
static
int
mh_messages_count
__P
((
mailbox_t
,
size_t
*
));
static
int
mh_messages_recent
__P
((
mailbox_t
,
size_t
*
));
static
int
mh_message_unseen
__P
((
mailbox_t
,
size_t
*
));
static
int
mh_expunge
__P
((
mailbox_t
));
static
int
mh_save_attributes
__P
((
mailbox_t
));
static
int
mh_uidvalidity
__P
((
mailbox_t
,
unsigned
long
*
));
static
int
mh_uidnext
__P
((
mailbox_t
,
size_t
*
));
static
int
mh_scan
__P
((
mailbox_t
,
size_t
,
size_t
*
));
static
int
mh_scan0
__P
((
mailbox_t
mailbox
,
size_t
msgno
,
size_t
*
pcount
,
int
do_notify
));
static
int
mh_is_updated
__P
((
mailbox_t
));
static
int
mh_get_size
__P
((
mailbox_t
,
off_t
*
));
static
int
mh_body_read
__P
((
stream_t
,
char
*
,
size_t
,
off_t
,
size_t
*
));
static
int
mh_body_readline
__P
((
stream_t
,
char
*
,
size_t
,
off_t
,
size_t
*
));
static
int
mh_stream_size
__P
((
stream_t
stream
,
off_t
*
psize
));
static
int
mh_body_size
__P
((
body_t
body
,
size_t
*
psize
));
static
int
mh_body_lines
__P
((
body_t
body
,
size_t
*
plines
));
static
int
mh_message_uid
__P
((
message_t
msg
,
size_t
*
puid
));
static
int
mh_message_stream_open
__P
((
struct
_mh_message
*
mhm
));
static
void
mh_message_stream_close
__P
((
struct
_mh_message
*
mhm
));
static
int
mh_header_fill
__P
((
header_t
header
,
char
*
buffer
,
size_t
len
,
off_t
off
,
size_t
*
pnread
));
static
int
mh_header_size
__P
((
header_t
header
,
size_t
*
psize
));
static
int
mh_header_lines
__P
((
header_t
header
,
size_t
*
plines
));
static
int
mh_get_attr_flags
__P
((
attribute_t
attr
,
int
*
pflags
));
static
int
mh_set_attr_flags
__P
((
attribute_t
attr
,
int
flags
));
static
int
mh_unset_attr_flags
__P
((
attribute_t
attr
,
int
flags
));
static
void
_mh_message_insert
__P
((
struct
_mh_data
*
mhd
,
struct
_mh_message
*
msg
));
static
void
_mh_message_delete
__P
((
struct
_mh_data
*
mhd
,
struct
_mh_message
*
msg
));
static
int
mh_pool_open
__P
((
struct
_mh_message
*
mhm
));
static
int
mh_pool_open_count
__P
((
struct
_mh_data
*
mhd
));
static
struct
_mh_message
**
mh_pool_lookup
__P
((
struct
_mh_message
*
mhm
));
static
int
mh_envelope_date
__P
((
envelope_t
envelope
,
char
*
buf
,
size_t
len
,
size_t
*
psize
));
static
int
mh_envelope_sender
__P
((
envelope_t
envelope
,
char
*
buf
,
size_t
len
,
size_t
*
psize
));
/* Should be in other header file. */
extern
int
mh_message_number
__P
((
message_t
msg
,
size_t
*
pnum
));
/* Return filename for the message.
NOTE: Allocates memory. */
static
char
*
_mh_message_name
(
struct
_mh_message
*
mhm
,
int
deleted
)
{
char
*
filename
;
size_t
len
=
strlen
(
mhm
->
mhd
->
name
)
+
32
;
filename
=
malloc
(
len
);
if
(
deleted
)
snprintf
(
filename
,
len
,
"%s/,%lu"
,
mhm
->
mhd
->
name
,
(
unsigned
long
)
mhm
->
seq_number
);
else
snprintf
(
filename
,
len
,
"%s/%lu"
,
mhm
->
mhd
->
name
,
(
unsigned
long
)
mhm
->
seq_number
);
return
filename
;
}
int
_mailbox_mh_init
(
mailbox_t
mailbox
)
{
struct
_mh_data
*
mhd
;
size_t
name_len
;
if
(
mailbox
==
NULL
)
return
EINVAL
;
mhd
=
mailbox
->
data
=
calloc
(
1
,
sizeof
(
*
mhd
));
if
(
mailbox
->
data
==
NULL
)
return
ENOMEM
;
/* Back pointer. */
mhd
->
mailbox
=
mailbox
;
url_get_path
(
mailbox
->
url
,
NULL
,
0
,
&
name_len
);
mhd
->
name
=
calloc
(
name_len
+
1
,
sizeof
(
char
));
if
(
mhd
->
name
==
NULL
)
{
free
(
mhd
);
mailbox
->
data
=
NULL
;
return
ENOMEM
;
}
url_get_path
(
mailbox
->
url
,
mhd
->
name
,
name_len
+
1
,
NULL
);
/* Overloading the defaults. */
mailbox
->
_destroy
=
mh_destroy
;
mailbox
->
_open
=
mh_open
;
mailbox
->
_close
=
mh_close
;
/* Overloading of the entire mailbox object methods. */
mailbox
->
_get_message
=
mh_get_message
;
mailbox
->
_append_message
=
mh_append_message
;
mailbox
->
_messages_count
=
mh_messages_count
;
mailbox
->
_messages_recent
=
mh_messages_recent
;
mailbox
->
_message_unseen
=
mh_message_unseen
;
mailbox
->
_expunge
=
mh_expunge
;
mailbox
->
_save_attributes
=
mh_save_attributes
;
mailbox
->
_uidvalidity
=
mh_uidvalidity
;
mailbox
->
_uidnext
=
mh_uidnext
;
mailbox
->
_scan
=
mh_scan
;
mailbox
->
_is_updated
=
mh_is_updated
;
mailbox
->
_get_size
=
mh_get_size
;
/* Set our properties. */
{
property_t
property
=
NULL
;
mailbox_get_property
(
mailbox
,
&
property
);
property_set_value
(
property
,
"TYPE"
,
"MH"
,
1
);
}
MAILBOX_DEBUG1
(
mailbox
,
MU_DEBUG_TRACE
,
"mh_init(%s)
\n
"
,
mhd
->
name
);
return
0
;
}
static
void
mh_destroy
(
mailbox_t
mailbox
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
msg
,
*
next
;
if
(
!
mhd
)
return
;
monitor_wrlock
(
mailbox
->
monitor
);
msg
=
mhd
->
msg_head
;
while
(
msg
)
{
next
=
msg
->
next
;
message_destroy
(
&
msg
->
message
,
msg
);
free
(
msg
);
msg
=
next
;
}
if
(
mhd
->
name
)
free
(
mhd
->
name
);
free
(
mhd
);
mailbox
->
data
=
NULL
;
monitor_unlock
(
mailbox
->
monitor
);
}
static
int
mh_open
(
mailbox_t
mailbox
,
int
flags
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
int
status
=
0
;
struct
stat
st
;
mailbox
->
flags
=
flags
;
if
(
stat
(
mhd
->
name
,
&
st
)
<
0
)
return
errno
;
if
(
!
S_ISDIR
(
st
.
st_mode
))
return
EINVAL
;
mhd
->
mtime
=
st
.
st_mtime
;
/* FIXME: is this the right kind of locking for mh folders? */
if
(
mailbox
->
locker
==
NULL
)
status
=
locker_create
(
&
mailbox
->
locker
,
mhd
->
name
,
0
);
return
0
;
}
static
int
mh_close
(
mailbox_t
mailbox
)
{
if
(
!
mailbox
)
return
EINVAL
;
return
locker_unlock
(
mailbox
->
locker
);
}
static
struct
_mh_message
*
_mh_get_message
(
struct
_mh_data
*
mhd
,
size_t
msgno
)
{
size_t
n
;
struct
_mh_message
*
msg
;
for
(
n
=
1
,
msg
=
mhd
->
msg_head
;
msg
&&
n
<
msgno
;
n
++
,
msg
=
msg
->
next
)
;
return
msg
;
}
/* Find the message with the given sequence number */
static
struct
_mh_message
*
_mh_get_message_seq
(
struct
_mh_data
*
mhd
,
size_t
seq
)
{
struct
_mh_message
*
msg
;
for
(
msg
=
mhd
->
msg_head
;
msg
&&
msg
->
seq_number
<
seq
;
msg
=
msg
->
next
)
;
if
(
msg
)
return
msg
->
seq_number
==
seq
?
msg
:
NULL
;
return
NULL
;
}
static
int
_mh_attach_message
(
mailbox_t
mailbox
,
struct
_mh_message
*
mhm
,
message_t
*
pmsg
)
{
int
status
;
message_t
msg
;
/* Check if we already have it. */
if
(
mhm
->
message
)
{
if
(
pmsg
)
*
pmsg
=
mhm
->
message
;
return
0
;
}
/* Get an empty message struct. */
status
=
message_create
(
&
msg
,
mhm
);
if
(
status
!=
0
)
return
status
;
/* Set the header. */
{
header_t
header
=
NULL
;
status
=
header_create
(
&
header
,
NULL
,
0
,
msg
);
if
(
status
!=
0
)
{
message_destroy
(
&
msg
,
mhm
);
return
status
;
}
header_set_fill
(
header
,
mh_header_fill
,
msg
);
header_set_size
(
header
,
mh_header_size
,
msg
);
header_set_lines
(
header
,
mh_header_lines
,
msg
);
/*FIXME:
header_set_get_fvalue (header, mh_header_get_fvalue, msg);
*/
message_set_header
(
msg
,
header
,
mhm
);
}
/* Set the attribute. */
{
attribute_t
attribute
;
status
=
attribute_create
(
&
attribute
,
msg
);
if
(
status
!=
0
)
{
message_destroy
(
&
msg
,
mhm
);
return
status
;
}
attribute_set_get_flags
(
attribute
,
mh_get_attr_flags
,
msg
);
attribute_set_set_flags
(
attribute
,
mh_set_attr_flags
,
msg
);
attribute_set_unset_flags
(
attribute
,
mh_unset_attr_flags
,
msg
);
message_set_attribute
(
msg
,
attribute
,
mhm
);
}
/* Prepare the body. */
{
body_t
body
=
NULL
;
stream_t
stream
=
NULL
;
if
((
status
=
body_create
(
&
body
,
msg
))
!=
0
||
(
status
=
stream_create
(
&
stream
,
mailbox
->
flags
|
MU_STREAM_SEEKABLE
,
body
))
!=
0
)
{
body_destroy
(
&
body
,
msg
);
stream_destroy
(
&
stream
,
body
);
message_destroy
(
&
msg
,
mhm
);
return
status
;
}
stream_set_read
(
stream
,
mh_body_read
,
body
);
stream_set_readline
(
stream
,
mh_body_readline
,
body
);
stream_set_size
(
stream
,
mh_stream_size
,
body
);
body_set_stream
(
body
,
stream
,
msg
);
body_set_size
(
body
,
mh_body_size
,
msg
);
body_set_lines
(
body
,
mh_body_lines
,
msg
);
message_set_body
(
msg
,
body
,
mhm
);
}
/* Set the envelope. */
{
envelope_t
envelope
=
NULL
;
status
=
envelope_create
(
&
envelope
,
msg
);
if
(
status
!=
0
)
{
message_destroy
(
&
msg
,
mhm
);
return
status
;
}
envelope_set_sender
(
envelope
,
mh_envelope_sender
,
msg
);
envelope_set_date
(
envelope
,
mh_envelope_date
,
msg
);
message_set_envelope
(
msg
,
envelope
,
mhm
);
}
/* Set the UID. */
message_set_uid
(
msg
,
mh_message_uid
,
mhm
);
/* Attach the message to the mailbox mbox data. */
mhm
->
message
=
msg
;
message_set_mailbox
(
msg
,
mailbox
,
mhm
);
if
(
pmsg
)
*
pmsg
=
msg
;
return
0
;
}
static
int
mh_get_message
(
mailbox_t
mailbox
,
size_t
msgno
,
message_t
*
pmsg
)
{
int
status
;
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
mhm
;
/* Sanity checks. */
if
(
pmsg
==
NULL
||
mhd
==
NULL
)
return
EINVAL
;
/* If we did not start a scanning yet do it now. */
if
(
mhd
->
msg_count
==
0
)
{
status
=
mh_scan0
(
mailbox
,
1
,
NULL
,
0
);
if
(
status
!=
0
)
return
status
;
}
if
((
mhm
=
_mh_get_message
(
mhd
,
msgno
))
==
NULL
)
return
EINVAL
;
return
_mh_attach_message
(
mailbox
,
mhm
,
pmsg
);
}
static
size_t
_mh_next_seq
(
struct
_mh_data
*
mhd
)
{
return
(
mhd
->
msg_tail
?
mhd
->
msg_tail
->
seq_number
:
0
)
+
1
;
}
static
FILE
*
_mh_tempfile
(
struct
_mh_data
*
mhd
,
char
**
namep
)
{
int
fd
=
mu_tempfile
(
mhd
->
name
,
namep
);
if
(
fd
==
-
1
)
return
NULL
;
return
fdopen
(
fd
,
"w"
);
}
static
int
_mh_delim
(
char
*
str
)
{
if
(
str
[
0
]
==
'-'
)
{
for
(;
*
str
==
'-'
;
str
++
)
;
for
(;
*
str
==
' '
||
*
str
==
'\t'
;
str
++
)
;
}
return
str
[
0
]
==
'\n'
;
}
static
int
_mh_message_save
(
struct
_mh_data
*
mhd
,
struct
_mh_message
*
mhm
,
int
expunge
)
{
stream_t
stream
=
NULL
;
char
*
name
=
NULL
,
*
buf
=
NULL
,
*
msg_name
;
size_t
n
,
off
=
0
;
size_t
bsize
;
size_t
nlines
,
nbytes
;
size_t
new_body_start
,
new_header_lines
;
FILE
*
fp
;
message_t
msg
=
mhm
->
message
;
header_t
hdr
;
int
status
;
attribute_t
attr
;
body_t
body
;
char
buffer
[
512
];
envelope_t
env
=
NULL
;
fp
=
_mh_tempfile
(
mhm
->
mhd
,
&
name
);
if
(
!
fp
)
return
errno
;
message_size
(
msg
,
&
bsize
);
/* Try to allocate large buffer */
for
(;
bsize
>
1
;
bsize
/=
2
)
if
((
buf
=
malloc
(
bsize
)))
break
;
if
(
!
bsize
)
return
ENOMEM
;
/* Copy flags */
message_get_header
(
msg
,
&
hdr
);
header_get_stream
(
hdr
,
&
stream
);
off
=
0
;
nlines
=
nbytes
=
0
;
while
((
status
=
stream_readline
(
stream
,
buf
,
bsize
,
off
,
&
n
))
==
0
&&
n
!=
0
)
{
if
(
_mh_delim
(
buf
))
break
;
if
(
!
(
strncasecmp
(
buf
,
"status:"
,
7
)
==
0
||
strncasecmp
(
buf
,
"x-imapbase:"
,
11
)
==
0
||
strncasecmp
(
buf
,
"x-uid:"
,
6
)
==
0
||
strncasecmp
(
buf
,
MU_HEADER_ENV_DATE
":"
,
sizeof
(
MU_HEADER_ENV_DATE
))
==
0
||
strncasecmp
(
buf
,
MU_HEADER_ENV_SENDER
":"
,
sizeof
(
MU_HEADER_ENV_SENDER
))
==
0
))
{
nlines
++
;
nbytes
+=
fprintf
(
fp
,
"%s"
,
buf
);
}
off
+=
n
;
}
/* Add imapbase */
if
(
!
mhd
->
msg_head
||
(
mhd
->
msg_head
==
mhm
))
/*FIXME*/
{
nbytes
+=
fprintf
(
fp
,
"X-IMAPbase: %lu %u
\n
"
,
(
unsigned
long
)
mhd
->
uidvalidity
,
(
unsigned
)
_mh_next_seq
(
mhd
));
nlines
++
;
}
message_get_envelope
(
msg
,
&
env
);
if
(
envelope_date
(
env
,
buffer
,
sizeof
buffer
,
&
n
)
==
0
&&
n
>
0
)
{
/* NOTE: buffer is terminated with \n */
char
*
p
=
buffer
;
while
(
isspace
(
*
p
))
p
++
;
nbytes
+=
fprintf
(
fp
,
"%s: %s"
,
MU_HEADER_ENV_DATE
,
p
);
if
(
*
p
&&
p
[
strlen
(
p
)
-
1
]
!=
'\n'
)
nbytes
+=
fprintf
(
fp
,
"
\n
"
);
nlines
++
;
}
if
(
envelope_sender
(
env
,
buffer
,
sizeof
buffer
,
&
n
)
==
0
&&
n
>
0
)
{
fprintf
(
fp
,
"%s: %s
\n
"
,
MU_HEADER_ENV_SENDER
,
buffer
);
nlines
++
;
}
/* Add status */
message_get_attribute
(
msg
,
&
attr
);
attribute_to_string
(
attr
,
buf
,
bsize
,
&
n
);
if
(
n
)
{
nbytes
+=
fprintf
(
fp
,
"%s"
,
buf
);
nlines
++
;
}
nbytes
+=
fprintf
(
fp
,
"
\n
"
);
nlines
++
;
new_header_lines
=
nlines
;
new_body_start
=
nbytes
;
/* Copy message body */
message_get_body
(
msg
,
&
body
);
body_get_stream
(
body
,
&
stream
);
off
=
0
;
nlines
=
0
;
while
(
stream_read
(
stream
,
buf
,
bsize
,
off
,
&
n
)
==
0
&&
n
!=
0
)
{
char
*
p
;
for
(
p
=
buf
;
p
<
buf
+
n
;
p
++
)
if
(
*
p
==
'\n'
)
nlines
++
;
fwrite
(
buf
,
1
,
n
,
fp
);
off
+=
n
;
nbytes
+=
n
;
}
mhm
->
header_lines
=
new_header_lines
;
mhm
->
body_start
=
new_body_start
;
mhm
->
body_lines
=
nlines
;
mhm
->
body_end
=
nbytes
;
free
(
buf
);
fclose
(
fp
);
msg_name
=
_mh_message_name
(
mhm
,
mhm
->
deleted
);
rename
(
name
,
msg_name
);
free
(
name
);
free
(
msg_name
);
return
0
;
}
static
int
mh_append_message
(
mailbox_t
mailbox
,
message_t
msg
)
{
int
status
;
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
mhm
;
if
(
!
mailbox
||
!
msg
)
return
EINVAL
;
mhm
=
calloc
(
1
,
sizeof
(
*
mhm
));
if
(
!
mhm
)
return
ENOMEM
;
/* If we did not start a scanning yet do it now. */
if
(
mhd
->
msg_count
==
0
)
{
status
=
mh_scan0
(
mailbox
,
1
,
NULL
,
0
);
if
(
status
!=
0
)
return
status
;
}
mhm
->
mhd
=
mhd
;
mhm
->
seq_number
=
_mh_next_seq
(
mhd
);
mhm
->
message
=
msg
;
status
=
_mh_message_save
(
mhd
,
mhm
,
0
);
mhm
->
message
=
NULL
;
/* Insert and re-scan the message */
_mh_message_insert
(
mhd
,
mhm
);
return
status
;
}
static
int
mh_messages_count
(
mailbox_t
mailbox
,
size_t
*
pcount
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
if
(
mhd
==
NULL
)
return
EINVAL
;
if
(
!
mh_is_updated
(
mailbox
))
return
mh_scan0
(
mailbox
,
mhd
->
msg_count
,
pcount
,
0
);
if
(
pcount
)
*
pcount
=
mhd
->
msg_count
;
return
0
;
}
/* A "recent" message is the one not marked with MU_ATTRIBUTE_SEEN
('O' in the Status header), i.e. a message that is first seen
by the current session (see attributes.h) */
static
int
mh_messages_recent
(
mailbox_t
mailbox
,
size_t
*
pcount
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
mhm
;
size_t
count
;
/* If we did not start a scanning yet do it now. */
if
(
mhd
->
msg_count
==
0
)
{
int
status
=
mh_scan0
(
mailbox
,
1
,
NULL
,
0
);
if
(
status
!=
0
)
return
status
;
}
count
=
0
;
for
(
mhm
=
mhd
->
msg_head
;
mhm
;
mhm
=
mhm
->
next
)
{
if
(
MU_ATTRIBUTE_IS_UNSEEN
(
mhm
->
attr_flags
))
count
++
;
}
*
pcount
=
count
;
return
0
;
}
/* An "unseen" message is the one that has not been read yet */
static
int
mh_message_unseen
(
mailbox_t
mailbox
,
size_t
*
pmsgno
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
mhm
;
size_t
i
,
unseen
;
/* If we did not start a scanning yet do it now. */
if
(
mhd
->
msg_count
==
0
)
{
int
status
=
mh_scan0
(
mailbox
,
1
,
NULL
,
0
);
if
(
status
!=
0
)
return
status
;
}
for
(
unseen
=
i
=
1
,
mhm
=
mhd
->
msg_head
;
mhm
;
i
++
,
mhm
=
mhm
->
next
)
{
if
(
MU_ATTRIBUTE_IS_UNREAD
(
mhm
->
attr_flags
))
{
unseen
=
i
;
break
;
}
}
*
pmsgno
=
unseen
;
return
0
;
}
static
int
mh_expunge
(
mailbox_t
mailbox
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
mhm
;
if
(
mhd
==
NULL
)
return
EINVAL
;
if
(
mhd
->
msg_count
==
0
)
return
0
;
/* Find the first dirty(modified) message. */
for
(
mhm
=
mhd
->
msg_head
;
mhm
;
mhm
=
mhm
->
next
)
{
if
((
mhm
->
attr_flags
&
MU_ATTRIBUTE_MODIFIED
)
||
(
mhm
->
attr_flags
&
MU_ATTRIBUTE_DELETED
)
||
(
mhm
->
message
&&
message_is_modified
(
mhm
->
message
)))
break
;
}
if
(
!
mhm
)
return
0
;
/* Nothing changed, just return. */
while
(
mhm
)
{
struct
_mh_message
*
next
=
mhm
->
next
;
if
(
mhm
->
attr_flags
&
MU_ATTRIBUTE_DELETED
)
{
if
(
!
mhm
->
deleted
)
{
char
*
old_name
,
*
new_name
;
/* Rename original message */
old_name
=
_mh_message_name
(
mhm
,
0
);
new_name
=
_mh_message_name
(
mhm
,
1
);
rename
(
old_name
,
new_name
);
free
(
old_name
);
free
(
new_name
);
}
_mh_message_delete
(
mhd
,
mhm
);
}
else
if
((
mhm
->
attr_flags
&
MU_ATTRIBUTE_MODIFIED
)
||
(
mhm
->
message
&&
message_is_modified
(
mhm
->
message
)))
{
_mh_attach_message
(
mailbox
,
mhm
,
NULL
);
mhm
->
deleted
=
mhm
->
attr_flags
&
MU_ATTRIBUTE_DELETED
;
_mh_message_save
(
mhd
,
mhm
,
1
);
}
mhm
=
next
;
}
return
0
;
}
static
int
mh_save_attributes
(
mailbox_t
mailbox
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
struct
_mh_message
*
mhm
;
if
(
mhd
==
NULL
)
return
EINVAL
;
if
(
mhd
->
msg_count
==
0
)
return
0
;
/* Find the first dirty(modified) message. */
for
(
mhm
=
mhd
->
msg_head
;
mhm
;
mhm
=
mhm
->
next
)
{
if
((
mhm
->
attr_flags
&
MU_ATTRIBUTE_MODIFIED
)
||
(
mhm
->
message
&&
message_is_modified
(
mhm
->
message
)))
break
;
}
if
(
!
mhm
)
return
0
;
/* Nothing changed, just return. */
while
(
mhm
)
{
struct
_mh_message
*
next
=
mhm
->
next
;
if
((
mhm
->
attr_flags
&
MU_ATTRIBUTE_MODIFIED
)
||
(
mhm
->
message
&&
message_is_modified
(
mhm
->
message
)))
{
_mh_attach_message
(
mailbox
,
mhm
,
NULL
);
mhm
->
deleted
=
mhm
->
attr_flags
&
MU_ATTRIBUTE_DELETED
;
_mh_message_save
(
mhd
,
mhm
,
0
);
}
mhm
=
next
;
}
return
0
;
}
static
int
mh_uidvalidity
(
mailbox_t
mailbox
,
unsigned
long
*
puidvalidity
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
int
status
=
mh_messages_count
(
mailbox
,
NULL
);
if
(
status
!=
0
)
return
status
;
/* If we did not start a scanning yet do it now. */
if
(
mhd
->
msg_count
==
0
)
{
status
=
mh_scan0
(
mailbox
,
1
,
NULL
,
0
);
if
(
status
!=
0
)
return
status
;
}
if
(
puidvalidity
)
*
puidvalidity
=
mhd
->
uidvalidity
;
return
0
;
}
struct
_mh_message
{
struct
_amd_message
amd_message
;
size_t
seq_number
;
/* message sequence number */
};
static
int
mh_
uidnext
(
mailbox_t
mailbox
,
size_t
*
puidnext
)
mh_
message_cmp
(
struct
_amd_message
*
a
,
struct
_amd_message
*
b
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
int
status
=
mh_messages_count
(
mailbox
,
NULL
);
if
(
status
!=
0
)
return
status
;
/* If we did not start a scanning yet do it now. */
if
(
mhd
->
msg_count
==
0
)
{
status
=
mh_scan0
(
mailbox
,
1
,
NULL
,
0
);
if
(
status
!=
0
)
return
status
;
}
if
(
puidnext
)
*
puidnext
=
_mh_next_seq
(
mhd
);
struct
_mh_message
*
ma
=
(
struct
_mh_message
*
)
a
;
struct
_mh_message
*
mb
=
(
struct
_mh_message
*
)
b
;
if
(
ma
->
seq_number
<
mb
->
seq_number
)
return
-
1
;
else
if
(
ma
->
seq_number
>
mb
->
seq_number
)
return
1
;
return
0
;
}
/* FIXME: effectively the same as mbox_cleanup */
static
void
mh_cleanup
(
void
*
arg
)
{
mailbox_t
mailbox
=
arg
;
monitor_unlock
(
mailbox
->
monitor
);
locker_unlock
(
mailbox
->
locker
);
}
/* Insert message msg into the message list on the appropriate position */
static
void
_mh_message_insert
(
struct
_mh_data
*
mhd
,
struct
_mh_message
*
msg
)
static
size_t
_mh_next_seq
(
struct
_amd_data
*
amd
)
{
struct
_mh_message
*
p
;
struct
_mh_message
*
prev
;
size_t
n
=
msg
->
seq_number
;
for
(
p
=
mhd
->
msg_head
;
p
&&
p
->
seq_number
<
n
;
p
=
p
->
next
)
;
if
(
!
p
)
{
msg
->
next
=
NULL
;
msg
->
prev
=
mhd
->
msg_tail
;
mhd
->
msg_tail
=
msg
;
if
(
!
mhd
->
msg_head
)
mhd
->
msg_head
=
msg
;
}
else
{
msg
->
next
=
p
;
msg
->
prev
=
p
->
prev
;
p
->
prev
=
msg
;
}
if
((
prev
=
msg
->
prev
)
!=
NULL
)
prev
->
next
=
msg
;
else
mhd
->
msg_head
=
msg
;
msg
->
mhd
=
mhd
;
mhd
->
msg_count
++
;
struct
_mh_message
*
msg
=
(
struct
_mh_message
*
)
amd
->
msg_tail
;
return
(
msg
?
msg
->
seq_number
:
0
)
+
1
;
}
static
void
_mh_message_delete
(
struct
_mh_data
*
mhd
,
struct
_mh_message
*
msg
)
/* Return filename for the message.
NOTE: Allocates memory. */
static
char
*
_mh_message_name
(
struct
_amd_message
*
amsg
,
int
deleted
)
{
struct
_mh_message
*
p
;
struct
_mh_message
**
pp
=
mh_pool_lookup
(
msg
);
if
(
pp
)
*
pp
=
NULL
;
if
((
p
=
msg
->
next
)
!=
NULL
)
p
->
prev
=
msg
->
prev
;
else
mhd
->
msg_tail
=
msg
->
prev
;
if
((
p
=
msg
->
prev
)
!=
NULL
)
p
->
next
=
msg
->
next
;
struct
_mh_message
*
mhm
=
(
struct
_mh_message
*
)
amsg
;
char
*
filename
;
size_t
len
=
strlen
(
amsg
->
amd
->
name
)
+
32
;
filename
=
malloc
(
len
);
if
(
deleted
)
snprintf
(
filename
,
len
,
"%s/,%lu"
,
amsg
->
amd
->
name
,
(
unsigned
long
)
mhm
->
seq_number
);
else
mhd
->
msg_head
=
msg
->
next
;
message_destroy
(
&
msg
->
message
,
msg
);
free
(
msg
);
mhd
->
msg_count
--
;
snprintf
(
filename
,
len
,
"%s/%lu"
,
amsg
->
amd
->
name
,
(
unsigned
long
)
mhm
->
seq_number
);
return
filename
;
}
/* Scan given message and fill mh_message_t fields.
NOTE: the function assumes mhm->stream != NULL. */
static
int
mh_scan_message
(
struct
_mh_message
*
mhm
)
/* Find the message with the given sequence number */
static
struct
_mh_message
*
_mh_get_message_seq
(
struct
_amd_data
*
amd
,
size_t
seq
)
{
stream_t
stream
=
mhm
->
stream
;
char
buf
[
1024
];
off_t
off
=
0
;
size_t
n
;
int
status
;
int
in_header
=
1
;
size_t
hlines
=
0
;
size_t
blines
=
0
;
size_t
body_start
=
0
;
/* Check if the message was modified after the last scan */
if
(
mhm
->
mtime
)
{
struct
stat
st
;
char
*
msg_name
=
_mh_message_name
(
mhm
,
mhm
->
deleted
);
if
(
stat
(
msg_name
,
&
st
)
==
0
&&
st
.
st_mtime
==
mhm
->
mtime
)
{
/* Nothing to do */
free
(
msg_name
);
return
0
;
}
free
(
msg_name
);
}
while
((
status
=
stream_readline
(
stream
,
buf
,
sizeof
(
buf
),
off
,
&
n
)
==
0
)
&&
n
!=
0
)
{
if
(
in_header
)
{
if
(
buf
[
0
]
==
'\n'
)
{
in_header
=
0
;
body_start
=
off
+
1
;
}
if
(
buf
[
n
-
1
]
==
'\n'
)
hlines
++
;
struct
_mh_message
*
msg
;
/* Process particular attributes */
if
(
strncasecmp
(
buf
,
"status:"
,
7
)
==
0
)
{
int
deleted
=
mhm
->
attr_flags
&
MU_ATTRIBUTE_DELETED
;
string_to_flags
(
buf
,
&
mhm
->
attr_flags
);
mhm
->
attr_flags
|=
deleted
;
}
else
if
(
strncasecmp
(
buf
,
"x-imapbase:"
,
11
)
==
0
)
{
char
*
p
;
mhm
->
mhd
->
uidvalidity
=
strtoul
(
buf
+
11
,
&
p
,
10
);
/* second number is next uid. Ignored */
}
}
else
{
if
(
buf
[
n
-
1
]
==
'\n'
)
blines
++
;
}
off
+=
n
;
}
for
(
msg
=
(
struct
_mh_message
*
)
amd
->
msg_head
;
msg
&&
msg
->
seq_number
<
seq
;
msg
=
(
struct
_mh_message
*
)
msg
->
amd_message
.
next
)
;
if
(
!
body_start
)
body_start
=
off
;
mhm
->
header_lines
=
hlines
;
mhm
->
body_lines
=
blines
;
mhm
->
body_start
=
body_start
;
mhm
->
body_end
=
off
;
return
0
;
if
(
msg
)
return
msg
->
seq_number
==
seq
?
msg
:
NULL
;
return
NULL
;
}
/* Scan the mailbox */
...
...
@@ -1013,24 +128,24 @@ static int
mh_scan0
(
mailbox_t
mailbox
,
size_t
msgno
ARG_UNUSED
,
size_t
*
pcount
,
int
do_notify
)
{
struct
_
mh_data
*
mh
d
=
mailbox
->
data
;
struct
_
amd_data
*
am
d
=
mailbox
->
data
;
struct
_mh_message
*
msg
;
DIR
*
dir
;
struct
dirent
*
entry
;
int
status
=
0
;
struct
stat
st
;
if
(
mh
d
==
NULL
)
if
(
am
d
==
NULL
)
return
EINVAL
;
dir
=
opendir
(
mh
d
->
name
);
dir
=
opendir
(
am
d
->
name
);
if
(
!
dir
)
return
errno
;
monitor_wrlock
(
mailbox
->
monitor
);
#ifdef WITH_PTHREAD
pthread_cleanup_push
(
mh
_cleanup
,
(
void
*
)
mailbox
);
pthread_cleanup_push
(
amd
_cleanup
,
(
void
*
)
mailbox
);
#endif
locker_lock
(
mailbox
->
locker
);
...
...
@@ -1069,316 +184,69 @@ mh_scan0 (mailbox_t mailbox, size_t msgno ARG_UNUSED, size_t *pcount,
if
(
namep
[
0
])
continue
;
msg
=
_mh_get_message_seq
(
mh
d
,
num
);
msg
=
_mh_get_message_seq
(
am
d
,
num
);
if
(
!
msg
)
{
msg
=
calloc
(
1
,
sizeof
(
*
msg
));
msg
->
seq_number
=
num
;
msg
->
attr_flags
=
attr_flags
;
msg
->
deleted
=
attr_flags
&
MU_ATTRIBUTE_DELETED
;
_mh_message_insert
(
mhd
,
msg
);
msg
->
amd_message
.
attr_flags
=
attr_flags
;
msg
->
amd_message
.
deleted
=
attr_flags
&
MU_ATTRIBUTE_DELETED
;
_amd_message_insert
(
amd
,
(
struct
_amd_message
*
)
msg
);
}
else
{
msg
->
attr_flags
=
attr_flags
;
msg
->
a
md_message
.
a
ttr_flags
=
attr_flags
;
}
}
closedir
(
dir
);
if
(
do_notify
)
for
(
msg
=
mhd
->
msg_head
;
msg
;
msg
=
msg
->
next
)
{
DISPATCH_ADD_MSG
(
mailbox
,
mhd
);
struct
_amd_message
*
mp
;
for
(
mp
=
amd
->
msg_head
;
mp
;
mp
=
mp
->
next
)
{
DISPATCH_ADD_MSG
(
mailbox
,
amd
);
}
}
if
(
stat
(
mh
d
->
name
,
&
st
)
==
0
)
mh
d
->
mtime
=
st
.
st_mtime
;
if
(
stat
(
am
d
->
name
,
&
st
)
==
0
)
am
d
->
mtime
=
st
.
st_mtime
;
if
(
pcount
)
*
pcount
=
mh
d
->
msg_count
;
*
pcount
=
am
d
->
msg_count
;
/* Reset the uidvalidity. */
if
(
mh
d
->
msg_count
>
0
)
if
(
am
d
->
msg_count
>
0
)
{
if
(
mh
d
->
uidvalidity
==
0
)
if
(
am
d
->
uidvalidity
==
0
)
{
mh
d
->
uidvalidity
=
(
unsigned
long
)
time
(
NULL
);
/* FIXME
mhd->uidnext = mh
d->msg_count + 1;*/
am
d
->
uidvalidity
=
(
unsigned
long
)
time
(
NULL
);
/* FIXME
amd->uidnext = am
d->msg_count + 1;*/
/* Tell that we have been modified for expunging. */
if
(
mh
d
->
msg_head
)
if
(
am
d
->
msg_head
)
{
mh_message_stream_open
(
mh
d
->
msg_head
);
mh_message_stream_close
(
mh
d
->
msg_head
);
mh
d
->
msg_head
->
attr_flags
|=
MU_ATTRIBUTE_MODIFIED
;
amd_message_stream_open
(
am
d
->
msg_head
);
amd_message_stream_close
(
am
d
->
msg_head
);
am
d
->
msg_head
->
attr_flags
|=
MU_ATTRIBUTE_MODIFIED
;
}
}
}
/* Clean up the things */
mh_cleanup
(
mailbox
);
#ifdef WITH_PTHREAD
pthread_cleanup_pop
(
0
);
#endif
return
status
;
}
static
int
mh_scan
(
mailbox_t
mailbox
,
size_t
msgno
,
size_t
*
pcount
)
{
struct
_mh_data
*
mhd
=
mailbox
->
data
;
if
(
!
mh_is_updated
(
mailbox
))
return
mh_scan0
(
mailbox
,
msgno
,
pcount
,
1
);
if
(
pcount
)
*
pcount
=
mhd
->
msg_count
;
return
0
;
}
/* Is the internal representation of the mailbox up to date.
Return 1 if so, 0 otherwise. */
static
int
mh_is_updated
(
mailbox_t
mailbox
)
{
struct
stat
st
;
struct
_mh_data
*
mhd
=
mailbox
->
data
;
if
(
!
mhd
->
msg_head
)
return
0
;
if
(
stat
(
mhd
->
name
,
&
st
)
<
0
)
return
1
;
return
mhd
->
mtime
==
st
.
st_mtime
;
}
static
int
mh_get_size
(
mailbox_t
mailbox
ARG_UNUSED
,
off_t
*
psize
ARG_UNUSED
)
{
/*FIXME*/
return
ENOSYS
;
}
/* Return number of open streams residing in a message pool */
static
int
mh_pool_open_count
(
struct
_mh_data
*
mhd
)
{
int
cnt
=
mhd
->
pool_last
-
mhd
->
pool_first
;
if
(
cnt
<
0
)
cnt
+=
MAX_OPEN_STREAMS
;
return
cnt
;
}
/* Look up a _mh_message in the pool of open messages.
If the message is found in the pool, returns the address of
the pool slot occupied by it. Otherwise returns NULL. */
static
struct
_mh_message
**
mh_pool_lookup
(
struct
_mh_message
*
mhm
)
{
struct
_mh_data
*
mhd
=
mhm
->
mhd
;
int
i
;
for
(
i
=
mhd
->
pool_first
;
i
!=
mhd
->
pool_last
;
)
{
if
(
mhd
->
msg_pool
[
i
]
==
mhm
)
return
&
mhd
->
msg_pool
[
i
];
if
(
++
i
==
MAX_OPEN_STREAMS
)
i
=
0
;
}
return
NULL
;
}
/* Open a stream associated with the message mhm. If the stream is
already open, do nothing.
NOTE: We could have reused the NULL holes in the msg_pool, but
that hardly is worth the effort, since the holes appear only when
expunging. On the other hand this may be useful when MAX_OPEN_STREAMS
size is very big. "Premature optimization is the root of all evil" */
static
int
mh_pool_open
(
struct
_mh_message
*
mhm
)
{
struct
_mh_data
*
mhd
=
mhm
->
mhd
;
if
(
mh_pool_lookup
(
mhm
))
return
0
;
if
(
mh_pool_open_count
(
mhd
)
==
MAX_OPEN_STREAMS
-
1
)
{
mh_message_stream_close
(
mhd
->
msg_pool
[
mhd
->
pool_first
++
]);
mhd
->
pool_first
%=
MAX_OPEN_STREAMS
;
}
mh_message_stream_open
(
mhm
);
mhd
->
msg_pool
[
mhd
->
pool_last
++
]
=
mhm
;
mhd
->
pool_last
%=
MAX_OPEN_STREAMS
;
return
0
;
}
/* Attach a stream to a given message structure. The latter is supposed
to be already added to the open message pool. */
int
mh_message_stream_open
(
struct
_mh_message
*
mhm
)
{
struct
_mh_data
*
mhd
=
mhm
->
mhd
;
char
*
filename
=
NULL
;
int
status
;
int
flags
=
MU_STREAM_ALLOW_LINKS
;
filename
=
_mh_message_name
(
mhm
,
mhm
->
deleted
);
if
(
!
filename
)
return
ENOMEM
;
/* The message should be at least readable */
if
(
mhd
->
mailbox
->
flags
&
(
MU_STREAM_RDWR
|
MU_STREAM_WRITE
|
MU_STREAM_APPEND
))
flags
|=
MU_STREAM_RDWR
;
else
flags
|=
MU_STREAM_READ
;
status
=
file_stream_create
(
&
mhm
->
stream
,
filename
,
flags
);
free
(
filename
);
if
(
status
!=
0
)
return
status
;
status
=
stream_open
(
mhm
->
stream
);
if
(
status
!=
0
)
stream_destroy
(
&
mhm
->
stream
,
NULL
);
if
(
status
==
0
)
status
=
mh_scan_message
(
mhm
);
return
status
;
}
/* Close the stream associated with the given message. */
void
mh_message_stream_close
(
struct
_mh_message
*
mhm
)
{
if
(
mhm
)
{
stream_close
(
mhm
->
stream
);
mhm
->
stream
=
NULL
;
}
}
void
mh_check_message
(
struct
_mh_message
*
mhm
)
{
if
(
mhm
->
body_end
==
0
)
mh_pool_open
(
mhm
);
}
/* Reading functions */
static
int
mh_readstream
(
struct
_mh_message
*
mhm
,
char
*
buffer
,
size_t
buflen
,
off_t
off
,
size_t
*
pnread
,
int
isreadline
,
off_t
start
,
off_t
end
)
{
size_t
nread
=
0
;
int
status
=
0
;
off_t
ln
;
if
(
buffer
==
NULL
||
buflen
==
0
)
{
if
(
pnread
)
*
pnread
=
nread
;
return
0
;
}
monitor_rdlock
(
mhm
->
mhd
->
mailbox
->
monitor
);
#ifdef WITH_PTHREAD
/* read() is cancellation point since we're doing a potentially
long operation. Lets make sure we clean the state. */
pthread_cleanup_push
(
mh_cleanup
,
(
void
*
)
mhm
->
mhd
->
mailbox
);
#endif
ln
=
end
-
(
start
+
off
);
if
(
ln
>
0
)
{
/* Position the file pointer and the buffer. */
nread
=
((
size_t
)
ln
<
buflen
)
?
(
size_t
)
ln
:
buflen
;
if
(
isreadline
)
status
=
stream_readline
(
mhm
->
stream
,
buffer
,
buflen
,
start
+
off
,
&
nread
);
else
status
=
stream_read
(
mhm
->
stream
,
buffer
,
nread
,
start
+
off
,
&
nread
);
}
monitor_unlock
(
mhm
->
mhd
->
mailbox
->
monitor
);
amd_cleanup
(
mailbox
);
#ifdef WITH_PTHREAD
pthread_cleanup_pop
(
0
);
#endif
if
(
pnread
)
*
pnread
=
nread
;
return
status
;
}
static
int
mh_body_read
(
stream_t
is
,
char
*
buffer
,
size_t
buflen
,
off_t
off
,
size_t
*
pnread
)
{
body_t
body
=
stream_get_owner
(
is
);
message_t
msg
=
body_get_owner
(
body
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
mh_pool_open
(
mhm
);
return
mh_readstream
(
mhm
,
buffer
,
buflen
,
off
,
pnread
,
0
,
mhm
->
body_start
,
mhm
->
body_end
);
}
static
int
mh_body_readline
(
stream_t
is
,
char
*
buffer
,
size_t
buflen
,
off_t
off
,
size_t
*
pnread
)
{
body_t
body
=
stream_get_owner
(
is
);
message_t
msg
=
body_get_owner
(
body
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
mh_pool_open
(
mhm
);
return
mh_readstream
(
mhm
,
buffer
,
buflen
,
off
,
pnread
,
1
,
mhm
->
body_start
,
mhm
->
body_end
);
}
/* Return corresponding sizes */
static
int
mh_stream_size
(
stream_t
stream
,
off_t
*
psize
)
{
body_t
body
=
stream_get_owner
(
stream
);
return
mh_body_size
(
body
,
(
size_t
*
)
psize
);
}
static
int
mh_body_size
(
body_t
body
,
size_t
*
psize
)
{
message_t
msg
=
body_get_owner
(
body
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
mh_check_message
(
mhm
);
if
(
psize
)
*
psize
=
mhm
->
body_end
-
mhm
->
body_start
;
return
0
;
}
static
int
mh_body_lines
(
body_t
body
,
size_t
*
plines
)
{
message_t
msg
=
body_get_owner
(
body
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
mh_check_message
(
mhm
);
if
(
plines
)
*
plines
=
mhm
->
body_lines
;
return
0
;
}
/* Note: In this particular implementation the message sequence number
serves also as its UID. This allows to avoid many problems related
to keeping the uids in the headers of the messages. */
static
int
mh_message_uid
(
message_t
msg
,
size_t
*
puid
)
...
...
@@ -1389,153 +257,43 @@ mh_message_uid (message_t msg, size_t *puid)
return
0
;
}
/* Headers */
static
int
mh_header_fill
(
header_t
header
,
char
*
buffer
,
size_t
len
,
off_t
off
,
size_t
*
pnread
)
{
message_t
msg
=
header_get_owner
(
header
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
mh_pool_open
(
mhm
);
return
mh_readstream
(
mhm
,
buffer
,
len
,
off
,
pnread
,
0
,
0
,
mhm
->
body_start
);
}
static
int
mh_header_size
(
header_t
header
,
size_t
*
psize
)
{
message_t
msg
=
header_get_owner
(
header
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
mh_check_message
(
mhm
);
if
(
psize
)
*
psize
=
mhm
->
body_start
;
return
0
;
}
static
int
mh_header_lines
(
header_t
header
,
size_t
*
plines
)
{
message_t
msg
=
header_get_owner
(
header
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
mh_check_message
(
mhm
);
if
(
plines
)
*
plines
=
mhm
->
header_lines
;
return
0
;
}
/* Attributes */
static
int
mh_get_attr_flags
(
attribute_t
attr
,
int
*
pflags
)
{
message_t
msg
=
attribute_get_owner
(
attr
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
if
(
pflags
)
*
pflags
=
mhm
->
attr_flags
;
return
0
;
}
static
int
mh_set_attr_flags
(
attribute_t
attr
,
int
flags
)
{
message_t
msg
=
attribute_get_owner
(
attr
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
mhm
->
attr_flags
|=
flags
;
return
0
;
}
static
int
mh_unset_attr_flags
(
attribute_t
attr
,
int
flags
)
_mh_msg_init
(
struct
_amd_data
*
amd
,
struct
_amd_message
*
amm
)
{
message_t
msg
=
attribute_get_owner
(
attr
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
if
(
mhm
==
NULL
)
return
EINVAL
;
mhm
->
attr_flags
&=
~
flags
;
struct
_mh_message
*
mhm
=
(
struct
_mh_message
*
)
amm
;
mhm
->
seq_number
=
_mh_next_seq
(
amd
);
return
0
;
}
/* Envelope */
static
int
mh_envelope_date
(
envelope_t
envelope
,
char
*
buf
,
size_t
len
,
size_t
*
psize
)
{
message_t
msg
=
envelope_get_owner
(
envelope
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
header_t
hdr
=
NULL
;
char
*
from
;
int
status
;
if
(
mhm
==
NULL
)
return
EINVAL
;
if
((
status
=
message_get_header
(
msg
,
&
hdr
))
!=
0
)
return
status
;
if
(
header_aget_value
(
hdr
,
MU_HEADER_ENV_DATE
,
&
from
))
return
ENOSYS
;
/* Format: "sender date" */
if
(
buf
&&
len
>
0
)
{
len
--
;
/* Leave space for the null. */
strncpy
(
buf
,
from
,
len
);
if
(
strlen
(
from
)
<
len
)
{
len
=
strlen
(
buf
);
buf
[
len
++
]
=
'\n'
;
}
buf
[
len
]
=
'\0'
;
}
else
len
=
0
;
if
(
psize
)
*
psize
=
len
;
return
0
;
}
static
int
mh_envelope_sender
(
envelope_t
envelope
,
char
*
buf
,
size_t
len
,
size_t
*
psize
)
int
_mailbox_mh_init
(
mailbox_t
mailbox
)
{
message_t
msg
=
envelope_get_owner
(
envelope
);
struct
_mh_message
*
mhm
=
message_get_owner
(
msg
);
header_t
hdr
=
NULL
;
char
*
from
;
int
status
;
int
rc
;
struct
_amd_data
*
amd
;
if
(
mhm
==
NULL
)
return
EINVAL
;
rc
=
amd_init_mailbox
(
mailbox
,
sizeof
(
struct
_amd_data
),
&
amd
);
if
(
rc
)
return
rc
;
if
((
status
=
message_get_header
(
msg
,
&
hdr
))
!=
0
)
return
status
;
if
(
header_aget_value
(
hdr
,
MU_HEADER_ENV_SENDER
,
&
from
))
return
ENOSYS
;
amd
->
msg_size
=
sizeof
(
struct
_mh_message
);
amd
->
msg_free
=
NULL
;
amd
->
msg_init_delivery
=
_mh_msg_init
;
amd
->
msg_finish_delivery
=
NULL
;
amd
->
msg_file_name
=
_mh_message_name
;
amd
->
scan0
=
mh_scan0
;
amd
->
msg_cmp
=
mh_message_cmp
;
amd
->
message_uid
=
mh_message_uid
;
amd
->
next_uid
=
_mh_next_seq
;
if
(
buf
&&
len
>
0
)
/* Set our properties. */
{
int
slen
=
strlen
(
from
);
if
(
len
<
slen
+
1
)
slen
=
len
-
1
;
memcpy
(
buf
,
from
,
slen
);
buf
[
slen
]
=
0
;
property_t
property
=
NULL
;
mailbox_get_property
(
mailbox
,
&
property
);
property_set_value
(
property
,
"TYPE"
,
"MH"
,
1
);
}
else
len
=
0
;
if
(
psize
)
*
psize
=
len
;
return
0
;
}
...
...
Please
register
or
sign in
to post a comment