/*
* POP3Lite - 3lite POP3 Daemon
* 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
*/
/*
* This file contains most of the functions mentioned in pop3lite.h
*/
#include "main.h"
#include <sys/param.h>
#include <pop3lite.h>
#include <ctype.h>
#include <glib.h>
#include <time.h>
#include <syslog.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_FLOCK
# include <sys/file.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_LOCKFILE
# include <lockfile.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 64
#endif
static const char rcsid[]="$Id: misc.c,v 1.18.2.6 2001/06/08 09:27:05 algernon Exp $";
static const char received_header[] =
"Received: by %s (mbox %s)\n (with pop3lite (%s) %.24s)";
/**
* p3l_received_header: return a pop3lite header
* @data: control->data
*
* constructcs a received: header
*
* returns: the header, which should be freed
**/
char *
p3l_received_header ( GHashTable *data )
{
time_t lasttime;
char *user;
char hostname[MAXHOSTNAMELEN];
#ifdef HAVE_GETHOSTNAME
gethostname ( hostname, sizeof ( hostname ) );
#else
strcpy ( (char *) hostname, "unknown" );
#endif
lasttime = time ( (time_t *) 0 );
user = g_hash_table_lookup ( data, "USER" );
return g_strdup_printf ( received_header, hostname,
user, VERSION, ctime ( &lasttime ) );
}
/**
* p3l_parse_buffer: replace From [...] with Received:
* @buffer: the mail text
* @data: control->data
* @buffer_size: size of the buffer
* @new_size: pointer where the new size will be placed
*
* Replaces the first line (From [,,,]) of the message with
* the POP3Lite-specific Received: header. (buffer will be
* freed!)
*
* Returns: the new buffer
**/
char *
p3l_parse_buffer ( char *buffer, GHashTable *data,
size_t buffer_size,
size_t *new_size )
{
char *banner, *buff, *xfrom;
size_t nsize, i = 0;
/*
* Prepare X-From_ field
*/
i = strchr ( buffer, '\n' ) - buffer;
xfrom = (char *) g_malloc ( i+10 );
memcpy ( xfrom, "\nX-From_: ", 10 );
memcpy ( xfrom + 10, buffer + strlen ( "From " ), i - strlen ( "From " ) );
xfrom[ i - strlen ( "From " ) + 10 ]='\0';
/*
* Get the banner
*/
banner = g_hash_table_lookup ( data, "BANNER" );
nsize = buffer_size + strlen ( banner ) - i + strlen ( xfrom );
/*
* Prepare the new buffer
*/
buff = g_malloc ( nsize );
memcpy ( buff, banner, strlen ( banner ) );
memcpy ( buff + strlen ( banner ), xfrom, strlen ( xfrom ) );
memcpy ( buff + strlen ( banner ) + strlen ( xfrom ), buffer + i, buffer_size - i );
g_free ( buffer);
if ( new_size != NULL )
*new_size = nsize;
return buff;
}
/**
* p3l_respond: generate a POP3Lite response
* code: response code see POP3Code above
* message: the actual message
*
* Generates a response suitable to be used as the
* return value of POP3 Command implementations.
*
* Returns: the POP3Lite response struct
**/
CommandResponse *
p3l_respond ( POP3Code code, const char *message )
{
CommandResponse *res;
res = (CommandResponse *) g_malloc ( sizeof ( CommandResponse ) );
res->code = code;
res->message = g_strdup ( message );
return res;
}
/**
* p3l_is_enabled: check if an option is enabled
* @option: the option string
*
* Parses @option, and returns a boolean indicating
* wheter it is enabled or not. (true, yes, on means
* enabled, everything else is disabled)
*
* Returns: a boolean
**/
gboolean
p3l_is_enabled ( const char *option )
{
char *tmp;
gboolean v_ret = FALSE;
tmp = g_strdup ( option );
if ( tmp == NULL )
return FALSE;
g_strup ( tmp );
if ( !strcmp ( tmp, "TRUE" ) || !strcmp ( tmp, "ON" ) ||
!strcmp ( tmp, "YES" ) )
v_ret = TRUE;
g_free ( tmp );
return v_ret;
}
/**
* bintohex: convert a binary string to hexadecimal
* @ptr: the binary sequence
* @size: length of the sequence
* @checkendian: wheter to check endianness, or not
*
* Converts a binary sequence to its hexadecimal
* representation.
*
* Returns: the hexadecimal representation.
**/
const char *
bintohex ( const void *ptr, size_t size, const int checkendian )
{
static char hex[33],*hp;
int inc = 1;
{
const int test = 1;
if ( checkendian && ! *(const char *)&test )
ptr = (const char *) ptr + size + ( inc = -1 );
}
for ( hp = hex; size-- ; ptr = (const char *) ptr + inc, hp += 2 )
sprintf ( hp, "%02x", *(unsigned char *) ptr );
return hex;
}
/**
* p3l_command_replace: replace a command
* @commands: the command table (control->{auth,trans}_commands
* @name: the command name
* @new_command: the new command
*
* Replaces a command in a given table.
*
* Returns: the old command.
**/
const gpointer
p3l_command_replace ( GHashTable *commands, const char *name, gpointer new_command )
{
gpointer backup;
backup = g_hash_table_lookup ( commands, name );
g_hash_table_insert ( commands, g_strdup ( name ), new_command );
return backup;
}
/**
* p3l_split_lines: split a buffer into lines
* @buffer: source
* @size: the buffer's size
*
* Splits the buffer into lines. This is NULL-aware, that means,
* that the strings are NOT null terminated, therefore, their
* size must be stored.
*
* Returns: a pointer to a P3LString array
**/
P3LString **
p3l_split_lines ( char *buffer, size_t size, size_t *lines )
{
P3LString **output;
size_t i, j = 0, line = 0;
*lines = 0;
/*
* In the first run, count the number of lines...
*/
for ( i = 0; i < size; i++ )
if ( buffer[i] == '\n' ) (*lines)++;
/*
* Allocate enough memory
*/
output = (P3LString **) g_malloc ( ( (*lines) + 1 ) * sizeof ( P3LString * ) );
/*
* Do the copying...
*/
i=0;
while ( i < size && size > 0 )
{
j=i;
while ( j < size - 1 && buffer[j] != '\n' )
j++;
output[line] = (P3LString *) g_malloc ( sizeof ( P3LString ) );
output[line]->length = j - i + 1;
output[line]->str = &buffer[i];
line++;
i = j + 1;
}
if ( i > 0 && buffer[i-1] != '\n' ) line--;
(*lines) = line;
output[line] = NULL;
return output;
}
/**
* p3l_lock_fd: lock a file
* @fd: file descriptor
*
* Locks a file.
*
* Returns: 0 on success, -1 otherwise
**/
int
p3l_lock_fd ( int fd, char *fn )
{
int retcode;
#ifdef HAVE_FCNTL_H
struct flock arg;
arg.l_type = F_WRLCK;
arg.l_whence = arg.l_start = arg.l_len = arg.l_pid = 0;
retcode = fcntl ( fd, F_SETLK, &arg );
#else
retcode = flock ( fd, LOCK_EX | LOCK_NB );
#endif
#ifdef HAVE_LOCKFILE
retcode = ( lockfile_create ( g_strdup_printf ( "%s.lock", fn ), 1, L_PID ) == 0 ) ? 0 : -1;
#endif
return retcode;
}
/**
* p3l_unlock_fd: unlock a file
* @fd: file descriptor
*
* Unlocks a file.
*
* Returns: 0 on success, -1 otherwise
**/
int
p3l_unlock_fd ( int fd, char *fn )
{
int retcode;
#ifdef HAVE_FCNTL_H
struct flock arg;
#endif
#ifdef HAVE_LOCKFILE
retcode = ( lockfile_remove ( g_strdup_printf ( "%s.lock", fn ) ) == 0 ) ? 0 : -1;
#endif
#ifdef HAVE_FCNTL_H
arg.l_type = F_UNLCK;
arg.l_whence = arg.l_start = arg.l_len = arg.l_pid = 0;
retcode = fcntl ( fd, F_SETLK, &arg );
#else
retcode = flock( fd, LOCK_UN );
#endif
return retcode;
}
/**
* p3l_read_fd: read the contents of an opened file
* @fd: file descriptor
* @size: variable to put filesize into
*
* Reads the contents of an already opened file.
*
* Returns: the contents, free-able
**/
gpointer
p3l_read_fd ( int fd, size_t *size )
{
char *buffer, *mailbox=NULL;
size_t mbsize=0;
ssize_t r;
buffer = (char *) g_malloc ( 10240 );
while ( ( r = read ( fd, buffer, 10240 ) ) > 0 )
{
mailbox = (char *) g_realloc ( mailbox, mbsize + r );
memcpy ( mailbox + mbsize, buffer, r );
mbsize += r;
}
g_free ( buffer );
if ( size != NULL )
*size = mbsize;
return (gpointer) mailbox;
}
/**
* p3l_read_file: read the contents of a file
* @fn: filename
* @size: variable to put filesize into
*
* Opens the file and reads its contents.
*
* Returns: the contents, free-able
**/
gpointer
p3l_read_file ( const char *filename, size_t *size )
{
gpointer buffer;
int fd;
if ( ( fd = open ( filename, O_RDONLY ) ) < 0 )
return NULL;
buffer = p3l_read_fd ( fd, size );
close ( fd );
return buffer;
}
/**
* p3l_get_peer_name: get the peer's hostname
*
* This one figures out the remote end's hostname.
*
* Returns: the hostname.
**/
char *
p3l_get_peer_name ( void )
{
struct sockaddr_in peer;
socklen_t peersize = sizeof peer;
char *hostname;
struct hostent *host;
if ( getpeername ( 0, (struct sockaddr *) &peer, &peersize ) < 0 )
return NULL;
if ( peer.sin_family != AF_INET )
return NULL;
hostname = inet_ntoa ( peer.sin_addr );
host = gethostbyaddr ( (char *) &peer.sin_addr.s_addr,
sizeof peer.sin_addr.s_addr, AF_INET );
if ( host != NULL )
hostname = host->h_name;
return hostname;
}
/**
* p3l_is_numeric: check if a string represents a number
* @str: the string to check
*
* Determines if a string represents a number or not.
*
* Returns: TRUE if it does, FALSE if not.
**/
gboolean
p3l_is_numeric ( const char* str )
{
int i, start = 0;
if ( str == NULL )
return FALSE;
if ( str[0] == '+' || str [1] == '-' )
start = 1;
for ( i = start; i < strlen ( str ); i++ )
if ( ! isdigit ( str[i] ) )
return FALSE;
return TRUE;
}
/**
* p3l_register_alarm: register an alarm hook
* @hook: the hook to run
* @interval: the interval (in seconds) to wait between calls
*
* Installs a new hook to be run on SIGALRM.
*
* Returns: nothing
**/
void
p3l_register_alarm ( p3l_module_hook hook, unsigned int interval )
{
HandlerInfo *hinfo;
unsigned int max_ticks;
max_ticks = interval / SIGALRM_INTERVAL;
hinfo = (HandlerInfo *) g_malloc ( sizeof ( HandlerInfo ) );
hinfo->counter = 0;
hinfo->tick_max = max_ticks;
hinfo->hook = hook;
alarm_handlers = g_list_append ( alarm_handlers, hinfo );
}
/**
* p3l_get_alarm_hooks: returns the registered SIGALRM hooks
*
* This function returns a GList of HandlerInfo structs of the
* registered SIGALRM hooks.
*
* Returns: the list
**/
GList *
p3l_get_alarm_hooks ( void )
{
return alarm_handlers;
}
/**
* p3l_unregister_alarm: unregister an alarm hook
* @hook: the hook to remove
*
* Removes an registered SIGALRM hook.
*
* Returns: nothing.
**/
void
p3l_unregister_alarm ( p3l_module_hook hook )
{
unsigned int i;
HandlerInfo *hinfo;
for ( i = 0; i < g_list_length ( alarm_handlers ); i++ )
{
hinfo = (HandlerInfo *) g_list_nth_data ( alarm_handlers, i );
if ( hinfo->hook == hook )
alarm_handlers = g_list_remove ( alarm_handlers, hinfo );
}
}
syntax highlighted by Code2HTML, v. 0.9.1