/* * (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 #endif #include #include #include #include #include #include #include #include #include #include #include "mailbox-upd.h" #ifdef HAVE_LOCKFILE # include # 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; }