/*
* (POP3Lite) MailBox - 3lite POP3 Daemon (mailbox driver)
* Copyright (C) 2000, 2001 Gergely Nagy <8@free.bsd.hu>
*
* This file is part of POP3Lite.
*
* POP3LIte is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* POP3Lite 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <pop3lite.h>
#include <glib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "mailbox-upd.h"
#ifdef HAVE_LOCKFILE
# include <lockfile.h>
# include "mailbox-p.h"
#endif
static const char rcsid[]="$Id: mailbox-upd.c,v 1.10.2.2 2001/05/30 12:37:30 algernon Exp $";
int errno;
static char *UPD_read_next_message ( int fd, size_t size );
static gboolean UPD_need_update ( P3LControl *control );
CommandResponse *
mailbox_update ( P3LControl *control )
{
int mailboxfd;
struct stat stbuf;
GList *messages=NULL;
GList *sizes=NULL;
unsigned long i;
size_t size=0;
MailInfo *minfo;
char *buffer;
char *mailbox = P3L_GET_DATA ( "MAILBOX" );
#ifdef DEBUG
control->system->log ( control, LOG_DEBUG, "%s:%d: UPDATE state (%s)",
__FILE__, __LINE__, P3L_GET_DATA ( "USER" ) );
#endif
mailboxfd = GPOINTER_TO_INT ( g_hash_table_lookup ( control->data, "MAILBOXFD" ) );
/*
* If there's nothing to update, we don't check the mailbox
*/
if ( ! UPD_need_update ( control ) )
{
#ifdef HAVE_LOCKFILE
p3l_unregister_alarm ( mailbox_alarm_handler );
#endif
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_NOTICE, "User %s logged out",
(char *) g_hash_table_lookup ( control->data, "USER" ) );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_OK, "Good bye" );
}
if ( fstat ( mailboxfd, &stbuf ) < 0 )
{
#ifdef HAVE_LOCKFILE
p3l_unregister_alarm ( mailbox_alarm_handler );
#endif
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_ERR,
"fstat failed on mailbox '%s': %s", mailbox,
g_strerror ( errno ) );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "fstat failed" );
}
if ( !S_ISREG ( stbuf.st_mode ) )
{
#ifdef HAVE_LOCKFILE
p3l_unregister_alarm ( mailbox_alarm_handler );
#endif
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_ALERT,
"Mailbox is not a regular file: %s", mailbox );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "mailbox is not a regular file" );
}
if ( stbuf.st_size != (off_t) GPOINTER_TO_INT ( g_hash_table_lookup ( control->data, "MBSIZE" ) ) ||
stbuf.st_mtime != (time_t) g_hash_table_lookup ( control->data, "MBTIME" ) )
{
#ifdef HAVE_LOCKFILE
p3l_unregister_alarm ( mailbox_alarm_handler );
#endif
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_ERR,
"Mailbox content changed: %s", mailbox );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "mailbox content changed" );
}
lseek ( mailboxfd, 0, SEEK_SET );
for ( i = 0; i < g_list_length ( control->msg_info ); i++ )
{
minfo = g_list_nth_data ( control->msg_info, i );
size = (size_t) g_hash_table_lookup ( minfo->driver_data, "real_size" );
buffer = UPD_read_next_message ( mailboxfd, (ssize_t) size );
if ( minfo->deleted == FALSE )
{
messages = g_list_append ( messages, buffer );
sizes = g_list_append ( sizes, (gpointer) size );
}
}
#ifdef HAVE_LOCKFILE
p3l_unregister_alarm ( mailbox_alarm_handler );
#endif
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
if ( ( mailboxfd = open ( mailbox, O_RDWR | O_TRUNC ) ) < 0 )
{
control->system->log ( control, LOG_ERR,
"Can't open mailbox '%s': %s", mailbox,
g_strerror ( errno ) );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "can't open mailbox" );
}
if ( p3l_lock_fd ( mailboxfd, mailbox ) != 0 )
{
control->system->log ( control, LOG_WARNING,
"Can't lock mailbox '%s': %s", mailbox,
g_strerror ( errno ) );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "can't lock mailbox" );
}
if ( fstat ( mailboxfd, &stbuf ) < 0 )
{
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_ERR,
"fstat failed on mailbox '%s': %s", mailbox,
g_strerror ( errno ) );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "fstat failed" );
}
if ( !S_ISREG ( stbuf.st_mode ) )
{
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_ALERT,
"Mailbox is not a regular file: %s", mailbox );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_FATAL, "mailbox is not a regular file" );
}
#ifdef HAVE_LOCKFILE
p3l_register_alarm ( mailbox_alarm_handler, 60 );
#endif
for ( i = 0; i < g_list_length ( messages ); i++ )
{
char *buffer;
buffer = g_list_nth_data ( messages, i );
write ( mailboxfd, buffer, (size_t) g_list_nth_data ( sizes, i ) );
g_free ( buffer );
}
#ifdef HAVE_LOCKFILE
p3l_unregister_alarm ( mailbox_alarm_handler );
#endif
p3l_unlock_fd ( mailboxfd, mailbox );
close ( mailboxfd );
control->system->log ( control, LOG_NOTICE, "User %s logged out",
(char *) g_hash_table_lookup ( control->data, "USER" ) );
g_hash_table_remove ( control->data, "USER" );
return p3l_respond ( POP3_OK, "Good bye" );
}
/**
* UPD_read_next_message: read the next message from the mailbox
* @fd: file descriptor
* @size: message size
*
* This little function is responsible for retrieving the next message
* from a mailbox.
*
* Returns: a newly allocated buffer containing the message
**/
static char *
UPD_read_next_message ( int fd, size_t size )
{
char *buffer;
buffer = (char *) g_malloc ( size + 1 );
read ( fd, buffer, size );
return buffer;
}
/**
* UPD_need_update: determine if the mailbox needs an update
* @control: the main control struct
*
* Determines wheter the current mailbox needs an update, by
* checking if there are any deleted messages.
*
* Returns: TRUE if it needs, FALSE if it doesn't
**/
static gboolean
UPD_need_update ( P3LControl *control )
{
unsigned long i;
for ( i = 0; i < g_list_length ( control->msg_info ); i++ )
if ( ( (MailInfo *) g_list_nth_data ( control->msg_info, i ) )->deleted == TRUE )
return TRUE;
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1