Add maildir support.

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@4798 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Johan Danielsson
1998-04-23 18:39:20 +00:00
parent 540beaa79e
commit 332e9f03d9
5 changed files with 290 additions and 38 deletions

220
appl/popper/maildir.c Normal file
View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) 1998 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Kungliga Tekniska
* H<>gskolan and its contributors.
*
* 4. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <popper.h>
#include <dirent.h>
RCSID("$Id$");
static int
scan_file(POP *p, MsgInfoList *mp)
{
char path[MAXDROPLEN];
FILE *f;
char buf[1024];
int eoh = 0;
snprintf(path, sizeof(path), "%s/%s/%s",
p->drop_name,
(mp->flags & NEW_FLAG) ? "new" : "old",
mp->name);
f = fopen(path, "r");
if(f == NULL) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG,
"Failed to open message file `%s': %s",
path, strerror(errno));
#endif
return pop_msg (p, POP_FAILURE,
"Failed to open message file `%s'", path);
}
while(fgets(buf, sizeof(buf), f)) {
if(buf[strlen(buf) - 1] == '\n')
mp->lines++;
mp->length += strlen(buf);
if(eoh)
continue;
if(strcmp(buf, "\n") == 0)
eoh = 1;
parse_header(mp, buf);
}
fclose(f);
return add_missing_headers(p, mp);
}
static int
scan_dir(POP *p, int new)
{
char tmp[MAXDROPLEN];
DIR *dir;
struct dirent *dent;
MsgInfoList *mp = p->mlp;
int n_mp = p->msg_count;
int e;
snprintf(tmp, sizeof(tmp), "%s/%s", p->drop_name, new ? "new" : "old");
mkdir(tmp, 0700);
dir = opendir(tmp);
while((dent = readdir(dir)) != NULL) {
if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
continue;
mp = realloc(mp, (n_mp + 1) * sizeof(*mp));
if(mp == NULL) {
p->msg_count = 0;
return pop_msg (p, POP_FAILURE,
"Can't build message list for '%s': Out of memory",
p->user);
}
memset(mp + n_mp, 0, sizeof(*mp));
mp[n_mp].name = strdup(dent->d_name);
if(mp[n_mp].name == NULL) {
p->msg_count = 0;
return pop_msg (p, POP_FAILURE,
"Can't build message list for '%s': Out of memory",
p->user);
}
mp[n_mp].number = n_mp + 1;
mp[n_mp].flags = 0;
if(new)
mp[n_mp].flags |= NEW_FLAG;
e = scan_file(p, &mp[n_mp]);
if(e != POP_SUCCESS)
return e;
p->drop_size += mp[n_mp].length;
n_mp++;
}
closedir(dir);
p->mlp = mp;
p->msg_count = n_mp;
return POP_SUCCESS;
}
int
pop_maildir_info(POP *p)
{
int e;
p->temp_drop[0] = '\0';
p->mlp = NULL;
p->msg_count = 0;
e = scan_dir(p, 0);
if(e != POP_SUCCESS) return e;
e = scan_dir(p, 1);
if(e != POP_SUCCESS) return e;
return POP_SUCCESS;
}
int
pop_maildir_update(POP *p)
{
int i;
char tmp1[MAXDROPLEN], tmp2[MAXDROPLEN];
for(i = 0; i < p->msg_count; i++) {
snprintf(tmp1, sizeof(tmp1), "%s/%s/%s", p->drop_name,
(p->mlp[i].flags & NEW_FLAG) ? "new" : "old",
p->mlp[i].name);
if(p->mlp[i].flags & DEL_FLAG) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Removing `%s'", tmp1);
#endif
if(unlink(tmp1) < 0) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Failed to remove `%s': %s",
tmp1, strerror(errno));
#endif
/* return failure? */
}
} else if((p->mlp[i].flags & NEW_FLAG) &&
(p->mlp[i].flags & RETR_FLAG)) {
snprintf(tmp2, sizeof(tmp2), "%s/old/%s", p->drop_name,
p->mlp[i].name);
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Linking `%s' to `%s'", tmp1, tmp2);
#endif
if(link(tmp1, tmp2) == 0) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Removing `%s'", tmp1);
#endif
if(unlink(tmp1) < 0) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Failed to remove `%s'", tmp1);
#endif
/* return failure? */
}
} else {
if(errno == EXDEV) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Trying to rename `%s' to `%s'",
tmp1, tmp2);
#endif
if(rename(tmp1, tmp2) < 0) {
#ifdef DEBUG
if(p->debug)
pop_log(p, POP_DEBUG, "Failed to rename `%s' to `%s'",
tmp1, tmp2);
#endif
}
}
}
}
}
return(pop_quit(p));
}
int
pop_maildir_open(POP *p, MsgInfoList *mp)
{
char tmp[MAXDROPLEN];
snprintf(tmp, sizeof(tmp), "%s/%s/%s", p->drop_name,
(mp->flags & NEW_FLAG) ? "new" : "old", mp->name);
if(p->drop)
fclose(p->drop);
p->drop = fopen(tmp, "r");
if(p->drop == NULL)
return pop_msg(p, POP_FAILURE, "Failed to open message file");
return POP_SUCCESS;
}

View File

@@ -107,6 +107,7 @@ pop_pass (POP *p)
{
struct passwd *pw;
int i;
struct stat st;
/* Make one string of all these parameters */
@@ -198,13 +199,17 @@ pop_pass (POP *p)
/* Build the name of the user's maildrop */
snprintf(p->drop_name, sizeof(p->drop_name), "%s/%s", POP_MAILDIR, p->user);
/* Make a temporary copy of the user's maildrop */
/* and set the group and user id */
if (pop_dropcopy(p,pw) != POP_SUCCESS) return (POP_FAILURE);
/* Get information about the maildrop */
if (pop_dropinfo(p) != POP_SUCCESS) return(POP_FAILURE);
if(stat(p->drop_name, &st) < 0 || !S_ISDIR(st.st_mode)){
/* Make a temporary copy of the user's maildrop */
/* and set the group and user id */
if (pop_dropcopy(p,pw) != POP_SUCCESS) return (POP_FAILURE);
/* Get information about the maildrop */
if (pop_dropinfo(p) != POP_SUCCESS) return(POP_FAILURE);
} else {
changeuser(p, pw);
if(pop_maildir_info(p) != POP_SUCCESS) return POP_FAILURE;
}
/* Initialize the last-message-accessed number */
p->last_msg = 0;

View File

@@ -68,7 +68,7 @@ pop_send(POP *p)
/* Is the message flagged for deletion? */
if (mp->flags & DEL_FLAG)
return (pop_msg (p,POP_FAILURE,
"Message %d has been deleted.",msg_num));
"Message %d has been deleted.",msg_num));
/* If this is a TOP command, get the number of lines to send */
if (strcmp(p->pop_command,"top") == 0) {
@@ -85,61 +85,71 @@ pop_send(POP *p)
/* Display the number of bytes in the message */
pop_msg(p, POP_SUCCESS, "%ld octets", mp->length);
if(IS_MAILDIR(p)){
int e = pop_maildir_open(p, mp);
if(e != POP_SUCCESS)
return e;
}
/* Position to the start of the message */
fseek(p->drop,mp->offset,0);
/* Skip the first line (the sendmail "From" line) */
fgets (buffer,MAXMSGLINELEN,p->drop);
return_path_sent = 0;
if(!IS_MAILDIR(p)) {
/* Skip the first line (the sendmail "From" line) */
fgets (buffer,MAXMSGLINELEN,p->drop);
#ifdef RETURN_PATH_HANDLING
return_path_sent = 0;
if (strncmp(buffer,"From ",5) == 0) {
return_path_linlen = strlen(buffer);
for (return_path_adr = buffer+5;
(*return_path_adr == ' ' || *return_path_adr == '\t') &&
return_path_adr < buffer + return_path_linlen;
return_path_adr++)
;
if (return_path_adr < buffer + return_path_linlen) {
if ((return_path_end = strchr(return_path_adr, ' ')) != NULL)
*return_path_end = '\0';
if (strlen(return_path_adr) != 0 && *return_path_adr != '\n') {
static char tmpbuf[MAXMSGLINELEN + 20];
strcpy(tmpbuf, "Return-Path: ");
strcat(tmpbuf, return_path_adr);
strcat(tmpbuf, "\n");
if (strlen(tmpbuf) < MAXMSGLINELEN) {
pop_sendline (p,tmpbuf);
if (hangup)
return (pop_msg (p,POP_FAILURE,"SIGHUP or SIGPIPE flagged"));
return_path_sent++;
if (strncmp(buffer,"From ",5) == 0) {
return_path_linlen = strlen(buffer);
for (return_path_adr = buffer+5;
(*return_path_adr == ' ' || *return_path_adr == '\t') &&
return_path_adr < buffer + return_path_linlen;
return_path_adr++)
;
if (return_path_adr < buffer + return_path_linlen) {
if ((return_path_end = strchr(return_path_adr, ' ')) != NULL)
*return_path_end = '\0';
if (strlen(return_path_adr) != 0 && *return_path_adr != '\n') {
static char tmpbuf[MAXMSGLINELEN + 20];
strcpy(tmpbuf, "Return-Path: ");
strcat(tmpbuf, return_path_adr);
strcat(tmpbuf, "\n");
if (strlen(tmpbuf) < MAXMSGLINELEN) {
pop_sendline (p,tmpbuf);
if (hangup)
return pop_msg (p, POP_FAILURE,
"SIGHUP or SIGPIPE flagged");
return_path_sent++;
}
}
}
}
}
#endif
}
/* Send the header of the message followed by a blank line */
while (fgets(buffer,MAXMSGLINELEN,p->drop)) {
#ifdef RETURN_PATH_HANDLING
/* Don't send existing Return-Path-header if already sent own */
if (strncasecmp(buffer,"Return-Path:", 12) != 0 ||
!return_path_sent)
if (!return_path_sent || strncasecmp(buffer, "Return-Path:", 12) != 0)
#endif
pop_sendline (p,buffer);
pop_sendline (p,buffer);
/* A single newline (blank line) signals the
end of the header. sendline() converts this to a NULL,
so that's what we look for. */
if (*buffer == 0) break;
if (hangup)
return (pop_msg (p,POP_FAILURE,"SIGHUP or SIGPIPE flagged"));
return (pop_msg (p,POP_FAILURE,"SIGHUP or SIGPIPE flagged"));
}
/* Send the message body */
{
int blank_line = 0;
while (fgets(buffer,MAXMSGLINELEN,p->drop)) {
while (fgets(buffer, MAXMSGLINELEN, p->drop)) {
/* Look for the start of the next message */
if (blank_line && strncmp(buffer,"From ",5) == 0) break;
if (!IS_MAILDIR(p) && blank_line && strncmp(buffer,"From ",5) == 0)
break;
blank_line = (strncmp(buffer, "\n", 1) == 0);
/* Decrement the lines sent (for a TOP command) */
if (msg_lines >= 0 && msg_lines-- == 0) break;

View File

@@ -42,6 +42,9 @@ pop_updt (POP *p)
}
#endif /* DEBUG */
if(IS_MAILDIR(p))
return pop_maildir_update(p);
if (p->msgs_deleted == p->msg_count) {
/* Truncate before close, to avoid race condition, DO NOT UNLINK!
Another process may have opened, and not yet tried to lock */

View File

@@ -191,6 +191,7 @@ typedef enum { /* POP processing states */
#define DEL_FLAG 1
#define RETR_FLAG 2
#define NEW_FLAG 4
typedef struct { /* Message information */
int number; /* Message number relative to
@@ -210,8 +211,11 @@ typedef struct { /* Message information */
char *from;
char *date;
#endif
char *name;
} MsgInfoList;
#define IS_MAILDIR(P) ((P)->temp_drop[0] == '\0')
typedef struct { /* POP parameter block */
int debug; /* Debugging requested */
char * myname; /* The name of this POP
@@ -327,3 +331,13 @@ int pop_msg(POP *p, int stat, char *format, ...)
__attribute__ ((format (printf, 3, 4)))
#endif
;
void pop_sendline(POP*, char*);
int pop_maildir_info (POP*);
int pop_maildir_open (POP*, MsgInfoList*);
int pop_maildir_update (POP*);
void changeuser(POP*, struct passwd*);
void parse_header(MsgInfoList*, char*);
int add_missing_headers(POP*, MsgInfoList*);