@ -137,16 +137,6 @@ typedef enum {
# define SAVE_TO_DISC /* multipart/message are saved in a temporary file */
# define FOLLOWURLS 5 / *
* Maximum number of URLs scanned in a message
* part . Helps to prevent Dialer . gen - 45 and
* Trojan . WinREG . Zapchast which are often
* dispatched by emails which point to it . If
* not defined , don ' t check any URLs
* It is also used to indicate the number of
* 301 / 302 redirects we wish to follow
*/
# include "htmlnorm.h"
# include "phishcheck.h"
@ -254,29 +244,6 @@ static bool newline_in_header(const char *line);
static blob * getHrefs ( message * m , tag_arguments_t * hrefs ) ;
static void hrefs_done ( blob * b , tag_arguments_t * hrefs ) ;
static void checkURLs ( message * m , mbox_ctx * mctx , mbox_status * rc , int is_html ) ;
static void do_checkURLs ( mbox_ctx * mctx , tag_arguments_t * hrefs ) ;
# if defined(FOLLOWURLS) && (FOLLOWURLS > 0)
struct arg {
char * url ;
const char * dir ;
char * filename ;
int depth ;
} ;
# define CONNECT_TIMEOUT 5 /* Allow 5 seconds to connect */
# ifdef CL_THREAD_SAFE
static void * getURL ( void * a ) ;
# else
static void * getURL ( struct arg * arg ) ;
# endif
static int nonblock_connect ( SOCKET sock , const struct sockaddr_in * sin , const char * hostname ) ;
static int connect_error ( SOCKET sock , const char * hostname ) ;
static int my_r_gethostbyname ( const char * hostname , struct hostent * hp , char * buf , size_t len ) ;
# define NONBLOCK_SELECT_MAX_FAILURES 3
# define NONBLOCK_MAX_ATTEMPTS 10
# endif
/* Maximum line length according to RFC2821 */
# define RFC2821LENGTH 1000
@ -2071,7 +2038,7 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re
*/
case TEXT :
/* text/plain has been preprocessed as no encoding */
if ( ( ( mctx - > ctx - > options & CL_SCAN_MAILURL ) & & ( subtype = = HTML ) ) | | doPhishingScan ) {
if ( doPhishingScan ) {
/*
* It would be better to save and scan the
* file and only checkURLs if it ' s found to be
@ -4055,14 +4022,12 @@ checkURLs(message *mainMessage, mbox_ctx *mctx, mbox_status *rc, int is_html)
hrefs . scanContents = mctx - > ctx - > engine - > dboptions & CL_DB_PHISHING_URLS & & ( DCONF_PHISHING & PHISHING_CONF_ENGINE ) ;
# if (!defined(FOLLOWURLS)) || (FOLLOWURLS <= 0)
if ( ! hrefs . scanContents )
/*
* Don ' t waste time extracting hrefs ( parsing html ) , nobody
* will need it
*/
return ;
# endif
hrefs . count = 0 ;
hrefs . tag = hrefs . value = NULL ;
@ -4082,663 +4047,10 @@ checkURLs(message *mainMessage, mbox_ctx *mctx, mbox_status *rc, int is_html)
cli_dbgmsg ( " PH:Phishing found \n " ) ;
}
}
if ( is_html & & ( mctx - > ctx - > options & CL_SCAN_MAILURL ) & & ( * rc ! = VIRUS ) )
do_checkURLs ( mctx , & hrefs ) ;
}
hrefs_done ( b , & hrefs ) ;
}
# if defined(FOLLOWURLS) && (FOLLOWURLS > 0)
static void
do_checkURLs ( mbox_ctx * mctx , tag_arguments_t * hrefs )
{
table_t * t ;
int i , n ;
const char * dir ;
# ifdef CL_THREAD_SAFE
pthread_t tid [ FOLLOWURLS ] ;
struct arg args [ FOLLOWURLS ] ;
# endif
t = tableCreate ( ) ;
if ( t = = NULL )
return ;
n = 0 ;
dir = mctx - > dir ;
/*
* Sort . exes higher up so that there ' s more chance they ' ll be
* downloaded and scanned
*/
for ( i = FOLLOWURLS ; ( i < hrefs - > count ) & & ( n < FOLLOWURLS ) ; i + + ) {
char * url = ( char * ) hrefs - > value [ i ] ;
char * ptr ;
if ( strncasecmp ( " http:// " , url , 7 ) ! = 0 )
continue ;
ptr = strrchr ( url , ' . ' ) ;
if ( ptr = = NULL )
continue ;
if ( strcasecmp ( ptr , " .exe " ) = = 0 ) {
/* FIXME: Could be swapping with another .exe */
cli_dbgmsg ( " swap %s %s \n " , hrefs - > value [ n ] , hrefs - > value [ i ] ) ;
ptr = ( char * ) hrefs - > value [ n ] ;
hrefs - > value [ n + + ] = ( unsigned char * ) url ;
hrefs - > value [ i ] = ( unsigned char * ) ptr ;
}
}
n = 0 ;
for ( i = 0 ; i < hrefs - > count ; i + + ) {
const char * url = ( const char * ) hrefs - > value [ i ] ;
/*
* TODO : If it ' s an image source , it ' d be nice to note beacons
* where width = " 0 " height = " 0 " , which needs support from
* the HTML normalise code
*/
if ( strncasecmp ( " http:// " , url , 7 ) = = 0 ) {
# ifndef CL_THREAD_SAFE
struct arg arg ;
# endif
char name [ NAME_MAX + 1 ] ;
if ( tableFind ( t , url ) = = 1 ) {
cli_dbgmsg ( " URL %s already downloaded \n " , url ) ;
continue ;
}
/*
* What about foreign character spoofing ?
*/
if ( strchr ( url , ' % ' ) & & strchr ( url , ' @ ' ) )
cli_dbgmsg ( " Possible URL spoofing attempt noticed, but not blocked (%s) \n " , url ) ;
if ( n = = FOLLOWURLS ) {
cli_dbgmsg ( " URL %s will not be scanned (FOLLOWURLS limit %d was reached) \n " ,
url , FOLLOWURLS ) ;
break ;
}
( void ) tableInsert ( t , url , 1 ) ;
cli_dbgmsg ( " Downloading URL %s to be scanned \n " , url ) ;
strncpy ( name , url , sizeof ( name ) - 1 ) ;
name [ sizeof ( name ) - 1 ] = ' \0 ' ;
sanitiseName ( name ) ; /* bug #538 */
# ifdef CL_THREAD_SAFE
args [ n ] . dir = dir ;
args [ n ] . url = cli_strdup ( url ) ;
args [ n ] . filename = cli_strdup ( name ) ;
args [ n ] . depth = 0 ;
if ( pthread_create ( & tid [ n ] , NULL , getURL , & args [ n ] ) ) {
cli_warnmsg ( " thread creation failed \n " ) ;
free ( args [ n ] . filename ) ;
free ( args [ n ] . url ) ;
break ;
}
# else
arg . url = cli_strdup ( url ) ;
arg . dir = dir ;
arg . filename = name ;
arg . depth = 0 ;
getURL ( & arg ) ;
free ( arg . url ) ;
# endif
+ + n ;
}
}
tableDestroy ( t ) ;
# ifdef CL_THREAD_SAFE
assert ( n < = FOLLOWURLS ) ;
cli_dbgmsg ( " checkURLs: waiting for %d thread(s) to finish \n " , n ) ;
while ( - - n > = 0 ) {
pthread_join ( tid [ n ] , NULL ) ;
free ( args [ n ] . filename ) ;
free ( args [ n ] . url ) ;
}
# endif
}
# else /*!FOLLOWURLS*/
static void
do_checkURLs ( mbox_ctx * mctx , tag_arguments_t * hrefs )
{
}
# endif
# if defined(FOLLOWURLS) && (FOLLOWURLS > 0)
/*
* FIXME : Often WMF exploits work by sending people an email directing them
* to a page which displays a picture containing the exploit . This is not
* currently found , since only the HTML on the referred page is downloaded .
* It would be useful to scan the HTML for references to pictures and
* download them for scanning . But that will hit performance so there is
* an issue here .
*/
/*
* Simple implementation of a subset of RFC1945 ( HTTP / 1.0 )
* TODO : HTTP / 1.1 ( RFC2068 )
*/
static void *
# ifdef CL_THREAD_SAFE
getURL ( void * a )
# else
getURL ( struct arg * arg )
# endif
{
FILE * fp ;
# ifdef CL_THREAD_SAFE
struct arg * arg = ( struct arg * ) a ;
# endif
const char * url = arg - > url ;
const char * dir = arg - > dir ;
const char * filename = arg - > filename ;
SOCKET sd ;
struct sockaddr_in server ;
# ifdef HAVE_IN_ADDR_T
in_addr_t ip ;
# else
unsigned int ip ;
# endif
in_port_t port ;
static in_port_t default_port ;
static int tcp ;
int doingsite , firstpacket ;
char * ptr ;
int via_proxy ;
const char * proxy ;
char buf [ BUFSIZ + 1 ] , site [ BUFSIZ ] , fout [ NAME_MAX + 1 ] ;
if ( strlen ( url ) > ( sizeof ( site ) - 1 ) ) {
cli_dbgmsg ( " Ignoring long URL \" %s \" \n " , url ) ;
return NULL ;
}
snprintf ( fout , sizeof ( fout ) - 1 , " %s/%s " , dir , filename ) ;
fp = fopen ( fout , " wb " ) ;
if ( fp = = NULL ) {
cli_errmsg ( " Can't open '%s' for writing \n " , fout ) ;
return NULL ;
}
cli_dbgmsg ( " Saving %s to %s \n " , url , fout ) ;
# ifndef C_BEOS
if ( tcp = = 0 ) {
const struct protoent * proto = getprotobyname ( " tcp " ) ;
if ( proto = = NULL ) {
cli_warnmsg ( " Unknown prototol tcp, check /etc/protocols \n " ) ;
fclose ( fp ) ;
return NULL ;
}
tcp = proto - > p_proto ;
# ifndef C_WINDOWS
endprotoent ( ) ;
# endif
}
# endif
if ( default_port = = 0 ) {
const struct servent * servent = getservbyname ( " http " , " tcp " ) ;
if ( servent )
default_port = ( in_port_t ) ntohs ( servent - > s_port ) ;
else
default_port = 80 ;
# if !defined(C_WINDOWS) && !defined(C_BEOS)
endservent ( ) ;
# endif
}
port = default_port ;
doingsite = 1 ;
ptr = site ;
proxy = getenv ( " http_proxy " ) ; /* FIXME: handle no_proxy */
via_proxy = ( proxy & & * proxy ) ;
if ( via_proxy ) {
if ( strncasecmp ( proxy , " http:// " , 7 ) ! = 0 ) {
cli_warnmsg ( " Unsupported proxy protocol (proxy = %s) \n " ,
proxy ) ;
fclose ( fp ) ;
return NULL ;
}
cli_dbgmsg ( " Getting %s via %s \n " , url , proxy ) ;
proxy + = 7 ;
while ( * proxy ) {
if ( doingsite & & ( * proxy = = ' : ' ) ) {
port = 0 ;
while ( isdigit ( * + + proxy ) ) {
port * = 10 ;
port + = * proxy - ' 0 ' ;
}
continue ;
}
if ( doingsite & & ( * proxy = = ' / ' ) ) {
proxy + + ;
break ;
}
* ptr + + = * proxy + + ;
}
} else {
cli_dbgmsg ( " Getting %s \n " , url ) ;
if ( strncasecmp ( url , " http:// " , 7 ) ! = 0 ) {
cli_dbgmsg ( " Unsupported protocol \n " ) ;
fclose ( fp ) ;
return NULL ;
}
url + = 7 ;
while ( * url ) {
if ( doingsite & & ( * url = = ' : ' ) ) {
port = 0 ;
while ( isdigit ( * + + url ) ) {
port * = 10 ;
port + = * url - ' 0 ' ;
}
continue ;
}
if ( doingsite & & ( * url = = ' / ' ) ) {
url + + ;
break ;
}
* ptr + + = * url + + ;
}
}
* ptr = ' \0 ' ;
memset ( ( char * ) & server , ' \0 ' , sizeof ( struct sockaddr_in ) ) ;
server . sin_family = AF_INET ;
server . sin_port = ( in_port_t ) htons ( port ) ;
ip = inet_addr ( site ) ;
# ifdef INADDR_NONE
if ( ip = = INADDR_NONE ) {
# else
if ( ip = = ( in_addr_t ) - 1 ) {
# endif
struct hostent h ;
if ( ( my_r_gethostbyname ( site , & h , buf , sizeof ( buf ) ) ! = 0 ) | |
( h . h_addr_list = = NULL ) | |
( h . h_addr = = NULL ) ) {
cli_dbgmsg ( " Unknown host %s \n " , site ) ;
fclose ( fp ) ;
return NULL ;
}
memcpy ( ( char * ) & ip , h . h_addr , sizeof ( ip ) ) ;
}
if ( ( sd = socket ( AF_INET , SOCK_STREAM , tcp ) ) < 0 ) {
fclose ( fp ) ;
return NULL ;
}
server . sin_addr . s_addr = ip ;
if ( nonblock_connect ( sd , & server , url ) < 0 ) {
closesocket ( sd ) ;
fclose ( fp ) ;
return NULL ;
}
/*
* TODO : consider HTTP / 1.1
*/
if ( via_proxy )
snprintf ( buf , sizeof ( buf ) - 1 ,
" GET %s HTTP/1.0 \r \n Host: %s \r \n User-Agent: ClamAV %s \r \n \r \n " ,
url , site , cl_retver ( ) ) ;
else
snprintf ( buf , sizeof ( buf ) - 1 ,
" GET /%s HTTP/1.0 \r \n Host: %s \r \n User-Agent: ClamAV %s \r \n \r \n " ,
url , site , cl_retver ( ) ) ;
/*cli_dbgmsg("%s", buf);*/
if ( send ( sd , buf , ( int ) strlen ( buf ) , 0 ) < 0 ) {
closesocket ( sd ) ;
fclose ( fp ) ;
return NULL ;
}
# ifdef SHUT_WR
shutdown ( sd , SHUT_WR ) ;
# else
shutdown ( sd , 1 ) ;
# endif
firstpacket = 1 ;
for ( ; ; ) {
fd_set set ;
struct timeval tv ;
int n ;
FD_ZERO ( & set ) ;
FD_SET ( sd , & set ) ;
tv . tv_sec = 30 ; /* FIXME: make this customisable */
tv . tv_usec = 0 ;
if ( select ( ( int ) sd + 1 , & set , NULL , NULL , & tv ) < 0 ) {
if ( errno = = EINTR )
continue ;
closesocket ( sd ) ;
fclose ( fp ) ;
return NULL ;
}
if ( ! FD_ISSET ( sd , & set ) ) {
fclose ( fp ) ;
closesocket ( sd ) ;
return NULL ;
}
n = recv ( sd , buf , sizeof ( buf ) - 1 , 0 ) ;
if ( n < 0 ) {
fclose ( fp ) ;
closesocket ( sd ) ;
return NULL ;
}
if ( n = = 0 )
break ;
/*
* FIXME : Handle header in more than one packet
*/
if ( firstpacket ) {
char * statusptr ;
buf [ n ] = ' \0 ' ;
statusptr = cli_strtok ( buf , 1 , " " ) ;
if ( statusptr ) {
int status = atoi ( statusptr ) ;
cli_dbgmsg ( " HTTP status %d \n " , status ) ;
free ( statusptr ) ;
if ( ( status = = 301 ) | | ( status = = 302 ) ) {
char * location ;
location = strstr ( buf , " \n Location: " ) ;
if ( location ) {
char * end ;
if ( cli_unlink ( fout ) ) return NULL ;
location + = 11 ;
end = location ;
while ( * end & & ( * end ! = ' \n ' ) )
end + + ;
* end = ' \0 ' ;
if ( arg - > depth > = FOLLOWURLS ) {
cli_dbgmsg ( " URL %s will not be followed to %s (FOLLOWURLS limit %d was reached) \n " ,
arg - > url , location , FOLLOWURLS ) ;
break ;
}
if ( strcmp ( location , arg - > url ) = = 0 ) {
cli_dbgmsg ( " URL %s redirects to itself \n " ,
location ) ;
break ;
}
fclose ( fp ) ;
closesocket ( sd ) ;
if ( strlen ( arg - > url ) < strlen ( location ) ) {
free ( arg - > url ) ;
arg - > url = cli_strdup ( location ) ;
} else
strcpy ( arg - > url , location ) ;
arg - > depth + + ;
cli_dbgmsg ( " Redirecting to %s \n " , location ) ;
return getURL ( arg ) ;
}
}
}
/*
* Don ' t write the HTTP header
*/
if ( ( ptr = strstr ( buf , " \r \n \r \n " ) ) ! = NULL ) {
ptr + = 4 ;
n - = ( int ) ( ptr - buf ) ;
} else if ( ( ptr = strstr ( buf , " \n \n " ) ) ! = NULL ) {
ptr + = 2 ;
n - = ( int ) ( ptr - buf ) ;
} else
ptr = buf ;
firstpacket = 0 ;
} else
ptr = buf ;
if ( n & & ( fwrite ( ptr , n , 1 , fp ) ! = 1 ) ) {
cli_warnmsg ( " Error writing %d bytes to %s \n " ,
n , fout ) ;
break ;
}
}
fclose ( fp ) ;
closesocket ( sd ) ;
return NULL ;
}
/*
* Have a copy here because r_gethostbyname is in shared not libclamav : - (
*/
static int
my_r_gethostbyname ( const char * hostname , struct hostent * hp , char * buf , size_t len )
{
struct hostent * hp2 ;
int ret = - 1 ;
# if !defined(HAVE_GETHOSTBYNAME_R_6) && !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_3)
# ifdef CL_THREAD_SAFE
static pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER ;
# endif
# endif
if ( ( hostname = = NULL ) | | ( hp = = NULL ) )
return - 1 ;
memset ( hp , 0 , sizeof ( struct hostent ) ) ;
# if defined(HAVE_GETHOSTBYNAME_R_6)
/* e.g. Linux */
if ( gethostbyname_r ( hostname , hp , buf , len , & hp2 , & ret ) < 0 )
return ret ;
# elif defined(HAVE_GETHOSTBYNAME_R_5)
/* e.g. BSD, Solaris, Cygwin */
/*
* Configure doesn ' t work on BeOS . We need - lnet to link , but configure
* doesn ' t add it , so you need to do something like
* LIBS = - lnet . / configure - - enable - cache - - disable - clamav
*/
if ( gethostbyname_r ( hostname , hp , buf , len , & ret ) = = NULL )
return ret ;
# elif defined(HAVE_GETHOSTBYNAME_R_3)
/* e.g. HP/UX, AIX */
if ( gethostbyname_r ( hostname , & hp , ( struct hostent_data * ) buf ) < 0 )
return h_errno ;
# else
/* Single thread the code e.g. VS2005 */
# ifdef CL_THREAD_SAFE
pthread_mutex_lock ( & hostent_mutex ) ;
# endif
if ( ( hp2 = gethostbyname ( hostname ) ) = = NULL ) {
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock ( & hostent_mutex ) ;
# endif
return h_errno ;
}
memcpy ( hp , hp2 , sizeof ( struct hostent ) ) ;
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock ( & hostent_mutex ) ;
# endif
# endif
return 0 ;
}
/*
* FIXME : There are lots of copies of this code : - (
*/
static int
nonblock_connect ( SOCKET sock , const struct sockaddr_in * sin , const char * hostname )
{
int select_failures ; /* Max. of unexpected select() failures */
int attempts ;
struct timeval timeout ; /* When we should time out */
int numfd ; /* Highest fdset fd plus 1 */
long flags ;
char err [ 128 ] ;
gettimeofday ( & timeout , 0 ) ; /* store when we started to connect */
if ( hostname = = NULL )
hostname = " remote " ; /* It's only used in debug messages */
# ifdef F_GETFL
flags = fcntl ( sock , F_GETFL , 0 ) ;
if ( flags = = - 1L )
cli_dbgmsg ( " getfl: %s \n " , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
else if ( fcntl ( sock , F_SETFL , ( long ) ( flags | O_NONBLOCK ) ) < 0 )
cli_dbgmsg ( " setfl: %s \n " , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
# else
flags = - 1L ;
# endif
if ( connect ( sock , ( const struct sockaddr * ) sin , sizeof ( struct sockaddr_in ) ) ! = 0 )
switch ( errno ) {
case EALREADY :
case EINPROGRESS :
cli_dbgmsg ( " %s: connect: %s \n " , hostname ,
cli_strerror ( errno , err , sizeof ( err ) ) ) ;
break ; /* wait for connection */
case EISCONN :
return 0 ; /* connected */
default :
cli_dbgmsg ( " %s: connect: %s \n " ,
hostname , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
# ifdef F_SETFL
if ( flags ! = - 1L )
if ( fcntl ( sock , F_SETFL , flags ) )
cli_dbgmsg ( " f_setfl: %s \n " , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
# endif
return - 1 ; /* failed */
}
else {
# ifdef F_SETFL
if ( flags ! = - 1L )
if ( fcntl ( sock , F_SETFL , flags ) )
cli_dbgmsg ( " f_setfl: %s \n " , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
# endif
return connect_error ( sock , hostname ) ;
}
numfd = ( int ) sock + 1 ;
select_failures = NONBLOCK_SELECT_MAX_FAILURES ;
attempts = 1 ;
timeout . tv_sec + = CONNECT_TIMEOUT ;
for ( ; ; ) {
int n , t ;
fd_set fds ;
struct timeval now , waittime ;
/* Force timeout if we ran out of time */
gettimeofday ( & now , 0 ) ;
t = ( now . tv_sec = = timeout . tv_sec ) ?
( now . tv_usec > timeout . tv_usec ) :
( now . tv_sec > timeout . tv_sec ) ;
if ( t ) {
cli_dbgmsg ( " %s: connect timeout (%d secs) \n " ,
hostname , CONNECT_TIMEOUT ) ;
break ;
}
/* Calculate how long to wait */
waittime . tv_sec = timeout . tv_sec - now . tv_sec ;
waittime . tv_usec = timeout . tv_usec - now . tv_usec ;
if ( waittime . tv_usec < 0 ) {
waittime . tv_sec - - ;
waittime . tv_usec + = 1000000 ;
}
/* Init fds with 'sock' as the only fd */
FD_ZERO ( & fds ) ;
FD_SET ( sock , & fds ) ;
n = select ( numfd , 0 , & fds , 0 , & waittime ) ;
if ( n < 0 ) {
cli_dbgmsg ( " %s: select attempt %d %s \n " ,
hostname , select_failures , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
if ( - - select_failures > = 0 )
continue ; /* not timed-out, try again */
break ; /* failed */
}
cli_dbgmsg ( " %s: select = %d \n " , hostname , n ) ;
if ( n ) {
# ifdef F_SETFL
if ( flags ! = - 1L )
if ( fcntl ( sock , F_SETFL , flags ) )
cli_dbgmsg ( " f_setfl: %s \n " , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
# endif
return connect_error ( sock , hostname ) ;
}
/* timeout */
if ( attempts + + = = NONBLOCK_MAX_ATTEMPTS ) {
cli_dbgmsg ( " timeout connecting to %s \n " , hostname ) ;
break ;
}
}
# ifdef F_SETFL
if ( flags ! = - 1L )
if ( fcntl ( sock , F_SETFL , flags ) )
cli_dbgmsg ( " f_setfl: %s \n " , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
# endif
return - 1 ; /* failed */
}
static int
connect_error ( SOCKET sock , const char * hostname )
{
char err [ 128 ] ;
# ifdef SO_ERROR
int optval ;
socklen_t optlen = sizeof ( optval ) ;
getsockopt ( sock , SOL_SOCKET , SO_ERROR , & optval , & optlen ) ;
if ( optval ) {
cli_dbgmsg ( " %s: %s \n " , hostname , cli_strerror ( optval , err , sizeof ( err ) ) ) ;
return - 1 ;
}
# endif
return 0 ;
}
# endif
# ifdef HAVE_BACKTRACE
static void
sigsegv ( int sig )
@ -5096,9 +4408,7 @@ do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, m
cli_dbgmsg ( " Treating inline as attachment \n " ) ;
} else {
const int is_html = ( tableFind ( mctx - > subtypeTable , cptr ) = = HTML ) ;
if ( ( mctx - > ctx - > options & CL_SCAN_MAILURL ) & & is_html )
checkURLs ( aMessage , mctx , rc , 1 ) ;
else if ( doPhishingScan )
if ( doPhishingScan )
checkURLs ( aMessage , mctx , rc , is_html ) ;
messageAddArgument ( aMessage ,
" filename=mixedtextportion " ) ;