/* * 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 #include #include #include #include #include #include #include #include #ifdef HAVE_FLOCK # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_LOCKFILE # include #endif #include #include #include #include #include #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 ); } }