Mercurial > noffle
diff protocol.c @ 0:04124a4423d4 noffle
[svn] Initial revision
author | enz |
---|---|
date | Tue, 04 Jan 2000 11:35:42 +0000 |
parents | |
children | d3fb34cb8198 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/protocol.c Tue Jan 04 11:35:42 2000 +0000 @@ -0,0 +1,278 @@ +/* + protocol.c + + $Id: protocol.c 3 2000-01-04 11:35:42Z enz $ +*/ + +#include <ctype.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include "common.h" +#include "dynamicstring.h" +#include "log.h" +#include "over.h" +#include "util.h" + +Bool +Prt_getLn( Str line, FILE *f ) +{ + size_t len; + + /* + We also accept lines ending with "\n" instead of "\r\n", some + clients wrongly send such lines. + */ + if ( ! fgets( line, MAXCHAR, f ) ) + { + Log_dbg( "Prt_getLine failed" ); + return FALSE; + } + len = strlen( line ); + if ( line[ len - 1 ] == '\n' ) + { + line[ len - 1 ] = '\0'; + if ( line[ len - 2 ] == '\r' ) + line[ len - 2 ] = '\0'; + } + Log_dbg( "[R] %s", line ); + return TRUE; +} + +Bool +Prt_getTxtLn( Str line, Bool *err, FILE *f ) +{ + Str buf; + + if ( ! Prt_getLn( buf, f ) ) + { + 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( "[S] .%s", line ); + return ( fprintf( f, ".%s\r\n", line ) == strlen( line ) + 3 ); + } + else + { + Log_dbg( "[S] %s", line ); + return ( fprintf( f, "%s\r\n", line ) == strlen( line ) + 2 ); + } +} + +Bool +Prt_putEndOfTxt( FILE *f ) +{ + Log_dbg( "[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 ) != strlen( line ) ) + return FALSE; + pLn = line; + } + else + *(pLn++) = *(pBuf++); + } + return TRUE; +} + +Bool +Prt_getField( Str resultField, Str resultValue, const char* line ) +{ + char *dst; + const char *p; + Str lineLower, t; + + Utl_cpyStr( lineLower, line ); + Utl_toLower( lineLower ); + p = Utl_stripWhiteSpace( 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; + } + return FALSE; +} + +Bool +Prt_searchHeader( const char *artTxt, const char *which, Str result ) +{ + const char *src, *p; + char *dst; + Str line, whichLower, field; + int len; + + 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, line ) + && strcmp( field, whichLower ) == 0 ) + return TRUE; + } + return FALSE; +} + +static Bool +getFQDN( Str result ) +{ + struct hostent *myHostEnt; + struct utsname myName; + + if ( uname( &myName ) >= 0 + && ( myHostEnt = gethostbyname( myName.nodename ) ) ) + { + Utl_cpyStr( result, myHostEnt->h_name ); + return TRUE; + } + return FALSE; +} + +static void +getDomain( Str domain, const char *from ) +{ + const char *addTopLevel, *p1, *p2, *p, *domainStart; + Str myDomain; + + if ( 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 ); +} + +Bool +Prt_isValidMsgId( const char *msgId ) +{ + Str head, domain; + int len, headLen; + const char *p; + + len = strlen( msgId ); + p = strstr( msgId, "@" ); + if ( msgId[ 0 ] != '<' || msgId[ len - 1 ] != '>' || p == NULL ) + return FALSE; + strcpy( domain, p + 1 ); + domain[ strlen( domain ) - 1 ] = '\0'; + headLen = p - msgId - 1; + Utl_cpyStrN( head, msgId + 1, headLen ); + head[ headLen ] = '\0'; + /* + To do: check for special characters in head and domain (non-printable + or '@', '<', '>'). Maybe compare domain with a config option + and replace it by the config option, if not equal. + */ + if ( strstr( domain, "." ) == NULL ) + return FALSE; + return TRUE; +} + +void +Prt_genMsgId( Str msgId, const char *from, const char *suffix ) +{ + Str domain, date; + time_t t; + + getDomain( domain, from ); + time( &t ); + strftime( date, MAXCHAR, "%Y%m%d%H%M%S", gmtime( &t ) ); + srand( time( NULL ) ); + snprintf( msgId, MAXCHAR, "<%s.%X.%s@%s>", date, rand(), suffix, domain ); + ASSERT( Prt_isValidMsgId( msgId ) ); +}