Mercurial > noffle
view src/protocol.c @ 282:baa6408d1bbc noffle
[svn] * src/database.c,src/post.c,src/protocol.h,src/protocol.c: When posting,
check the article for those headers that are specified in section
5 of the IETF draft and ensure they only occur once.
* src/post.c: Clean up a conditional.
author | bears |
---|---|
date | Mon, 06 Jan 2003 18:16:18 +0000 |
parents | 3477050e8d10 |
children | 01755687c565 |
line wrap: on
line source
/* protocol.c $Id: protocol.c 414 2003-01-06 18:16:18Z bears $ */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <ctype.h> #include <pwd.h> #include <signal.h> #include <sys/types.h> #include <unistd.h> #include "common.h" #include "configfile.h" #include "dynamicstring.h" #include "log.h" #include "over.h" #include "util.h" #include "portable.h" #include "protocol.h" static void readAlarm( int sig ) { UNUSED( sig ); return; } Bool Prt_getLn( Str line, FILE *f, int timeoutSeconds ) { size_t len; char *ret; SignalHandler oldHandler = NULL; int line_too_long; if ( timeoutSeconds >= 0 ) { oldHandler = Utl_installSignalHandler( SIGALRM, readAlarm ); if ( oldHandler == SIG_ERR ) { Log_err( "Prt_getLn: signal failed." ); return FALSE; } if ( alarm( timeoutSeconds ) != 0 ) Log_err( "Prt_getLn: Alarm was already set." ); } /* We also accept lines ending with "\n" instead of "\r\n", some clients wrongly send such lines. */ ret = fgets( line, MAXCHAR, f ); if ( timeoutSeconds >= 0 ) { alarm( 0 ); Utl_installSignalHandler( SIGALRM, oldHandler ); } if ( ret == NULL ) return FALSE; len = strlen( line ); if ( len > 0 ) { if ( line[ len - 1 ] == '\n' ) { line[ len - 1 ] = '\0'; if ( len > 1 && line[ len - 2 ] == '\r' ) line[ len - 2 ] = '\0'; } else { /* line too long, skip the rest */ if( len == MAXCHAR ) { Log_err( "Line too long:" ); do { line_too_long = fgetc( f ); } while( line_too_long == EOF || line_too_long == '\n' ); } else /* EOF occured in line, skip line. */ { Log_err( "Ignoring incomplete line %s", line); return FALSE; } } } Log_dbg( LOG_DBG_PROTOCOL, "[R] %s", line ); return TRUE; } Bool Prt_getTxtLn( Str line, Bool *err, FILE *f, int timeoutSeconds ) { Str buf; if ( ! Prt_getLn( buf, f, timeoutSeconds ) ) { Log_err( "Cannot get text line" ); *err = TRUE; return FALSE; } *err = FALSE; if ( buf[ 0 ] == '.' ) { if ( buf[ 1 ] == 0 ) return FALSE; else strcpy( line, buf + 1 ); } else strcpy( line, buf ); return TRUE; } Bool Prt_putTxtLn( const char* line, FILE *f ) { if ( line[ 0 ] == '.' ) { Log_dbg( LOG_DBG_PROTOCOL, "[S] .%s", line ); return ( fprintf( f, ".%s\r\n", line ) == (int)strlen( line ) + 3 ); } else { Log_dbg( LOG_DBG_PROTOCOL, "[S] %s", line ); return ( fprintf( f, "%s\r\n", line ) == (int)strlen( line ) + 2 ); } } Bool Prt_putEndOfTxt( FILE *f ) { Log_dbg( LOG_DBG_PROTOCOL, "[S] ." ); return ( fprintf( f, ".\r\n" ) == 3 ); } /* Write text buffer of lines each ending with '\n'. Replace '\n' by "\r\n". */ Bool Prt_putTxtBuf( const char *buf, FILE *f ) { Str line; const char *pBuf; char *pLn; pBuf = buf; pLn = line; while ( *pBuf != '\0' ) { if ( *pBuf == '\n' ) { *pLn = '\0'; if ( ! Prt_putTxtLn( line, f ) ) return FALSE; pLn = line; ++pBuf; } else if ( pLn - line >= MAXCHAR - 1 ) { /* Put it out raw to prevent String overflow */ Log_err( "Writing VERY long line" ); *pLn = '\0'; if ( fprintf( f, "%s", line ) != (int)strlen( line ) ) return FALSE; pLn = line; } else *(pLn++) = *(pBuf++); } return TRUE; } Bool Prt_getField( Str resultField, Str resultValue, Bool* isContinuation, const char* line ) { char *dst; const char *p; Str lineLower, t; ASSERT( isContinuation ); *isContinuation = FALSE; Utl_cpyStr( lineLower, line ); Utl_toLower( lineLower ); p = Utl_stripWhiteSpace( lineLower ); if ( p == lineLower ) { dst = resultField; while ( ! isspace( *p ) && *p != ':' && *p != '\0' ) *(dst++) = *(p++); *dst = '\0'; while ( isspace( *p ) ) ++p; if ( *p == ':' ) { ++p; strcpy( t, line + ( p - lineLower ) ); p = Utl_stripWhiteSpace( t ); strcpy( resultValue, p ); return TRUE; } else return FALSE; /* Not a header line */ } else { /* * If the line starts with white space, it can be a header * continuation. */ if( ! isspace( *line ) ) return FALSE; Utl_cpyStr( resultValue, line ); *isContinuation = TRUE; return TRUE; } /* NOTREACHED */ } Bool Prt_searchHeader( const char *artTxt, const char *which, Str result ) { const char *src, *p; char *dst; Str line, whichLower, field; int len; Bool continuation; Utl_cpyStr( whichLower, which ); Utl_toLower( whichLower ); src = artTxt; while ( TRUE ) { dst = line; len = 0; while ( *src != '\n' && len < MAXCHAR ) { if ( *src == '\0' ) return FALSE; *(dst++) = *(src++); ++len; } if ( *src == '\n' ) ++src; *dst = '\0'; p = Utl_stripWhiteSpace( line ); if ( *p == '\0' ) break; if ( Prt_getField( field, result, &continuation, line ) && strcmp( field, whichLower ) == 0 ) return TRUE; } return FALSE; } static void getDomain( Str domain, const char *from ) { const char *addTopLevel, *p1, *p2, *p, *domainStart; Str myDomain; if ( Utl_getFQDN( myDomain ) ) { p = strstr( myDomain, "." ); if ( p != NULL ) domainStart = p + 1; else domainStart = myDomain; } else /* Take domain of From field */ { myDomain[ 0 ] = '\0'; p1 = strstr( from, "@" ); if ( p1 != NULL ) { p2 = strstr( p1, ">" ); if ( p2 != NULL ) Utl_cpyStrN( myDomain, p1 + 1, p2 - p1 - 1 ); } if ( myDomain[ 0 ] == '\0' ) Utl_cpyStr( myDomain, "unknown" ); domainStart = myDomain; } /* If domain contains no dot (and is probably invalid anyway), we add ".local", because some servers insist on domainnames with dot in message ID. */ addTopLevel = strstr( domainStart, "." ) == NULL ? ".local" : ""; snprintf( domain, MAXCHAR, "%s%s", myDomain, addTopLevel ); } /* See RFC 850, section 2.1.7 */ Bool Prt_isValidMsgId( const char *msgId ) { Str head, domain; int len, headLen; const char *p; const char * specials = "\t\r\n ()@<>"; /* hmm, check "\\\'\"[]" as well? */ len = strlen( msgId ); if ( len > 250 ) return FALSE; /* see draft-ietf-usefor-article-06.txt, ch 5.3 */ p = strchr( msgId, '@' ); if ( msgId[ 0 ] != '<' || msgId[ len - 1 ] != '>' || p == NULL ) return FALSE; Utl_cpyStr( domain, p + 1 ); domain[ strlen( domain ) - 1 ] = '\0'; headLen = p - msgId - 1; Utl_cpyStrN( head, msgId + 1, headLen ); head[ headLen ] = '\0'; for ( p = msgId ; *p != '\0' ; p++ ) { if ( ! isascii( *p ) ) return FALSE; } if ( strpbrk( head, specials ) ) return FALSE; if ( strpbrk( domain, specials ) ) return FALSE; return TRUE; } void Prt_genMsgId( Str msgId, const char *from, const char *suffix ) { Str domain, date; time_t t; static long count = 0; const char *pattern; getDomain( domain, from ); time( &t ); strftime( date, MAXCHAR, "%Y%m%d%H%M%S", gmtime( &t ) ); if ( strchr( domain, '@' ) ) pattern = "<%s.%X.%lx.%s%s>"; else pattern = "<%s.%X.%lx.%s@%s>"; snprintf( msgId, MAXCHAR, pattern , date, getpid(), count++ ,suffix, domain ); ASSERT( Prt_isValidMsgId( msgId ) ); } void Prt_genPathHdr( Str pathHdr, const char *from ) { getDomain( pathHdr, from ); Utl_catStr( pathHdr, "!not-for-mail" ); } Bool Prt_genFromHdr( Str fromHdr ) { Str name, domain; const char *nameval; struct passwd *pwd; /* First get the domain to use. If config empty, use FQDN */ Utl_cpyStr( domain, Cfg_fromDomain() ); if ( strlen( domain ) == 0 ) if ( ! Utl_getFQDN( domain ) ) Utl_catStr( domain, "unknown" ); /* Now get pwd for the username */ pwd = getpwuid( getuid() ); if ( pwd == NULL ) return FALSE; /* Now for their name - use env NAME if available */ nameval = getenv( "NAME" ); if ( nameval != NULL ) Utl_cpyStr( name, nameval ); else { char *p; /* Extract from GECOS field. Following the lead of the INN inews, ignore leading stuff like "23-" "stuff]-" or "stuff -" as well as trailing whitespace, or anything that comes after a comma or semicolon. */ nameval = pwd->pw_gecos; p = strchr( nameval, '-' ); if ( p != NULL && p > nameval && ( p[-1] == ']' || p[-1] == ' ' || isdigit( p[ -1 ] ) ) ) nameval = p; p = strrchr( nameval, ',' ); if ( p != NULL ) *p = '\0'; p = strchr( nameval, ';' ); if ( p != NULL ) *p = '\0'; Utl_cpyStr( name, nameval ); } /* OK, build From: contents */ /* deprecated. Utl_cpyStr( fromHdr, pwd->pw_name ); Utl_catStr( fromHdr, "@" ); Utl_catStr( fromHdr, domain ); Utl_catStr( fromHdr, " (" ); Utl_catStr( fromHdr, name ); Utl_catStr( fromHdr, ")" ); */ Utl_cpyStr( fromHdr, "\"" ); Utl_catStr( fromHdr, name ); Utl_catStr( fromHdr, "\" <" ); Utl_catStr( fromHdr, pwd->pw_name ); Utl_catStr( fromHdr, "@" ); Utl_catStr( fromHdr, domain ); Utl_catStr( fromHdr, ">" ); return TRUE; }