diff --git a/mermsemr/src/mailsend/Makefile b/mermsemr/src/mailsend/Makefile index 2f468d3..1133cf3 100644 --- a/mermsemr/src/mailsend/Makefile +++ b/mermsemr/src/mailsend/Makefile @@ -2,9 +2,30 @@ # Makefile automatically generated by genmake 1.0, May-03-00 # genmake 1.0 by muquit@muquit.com, http://www.muquit.com/ ## +srcdir = . + +top_srcdir = . CC= gcc -DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_YP_GET_DEFAULT_DOMAIN=1 -DHAVE_LIBNSL=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_OPENSSL=1 -DUNIX +DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_LIMITS_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_GETADDRINFO=1 -DUNIX PROGNAME= mailsend +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +DESTDIR = +prefix = /usr/local +exec_prefix = ${prefix} +datarootdir = ${prefix}/share +datadir = ${datarootdir} +bindir = ${exec_prefix}/bin +mandir = ${datarootdir}/man +man1dir = $(mandir)/man1 +BINDIR = $(DESTDIR)$(bindir) +MAN1DIR = $(DESTDIR)$(man1dir) + +#BINDIR= /usr/bin +MANPAGE= doc/mailsend.1.gz +#MANDIR= /usr/share/man/man1 MUTILS_INCLUDE= -I./libs/libmutils MSOCK_INCLUDE= -I./libs/libmsock @@ -14,38 +35,72 @@ MUTILS_LIB= ./libs/libmutils/libmutils.a MSOCK_LIB=./libs/libmsock/libmsock.a SLL_LIB= ./libs/libsll/libsll.a -OPENSSL_DIR=/usr/ -OPENSSL_INC=-I/usr/include -#OPENSSL_LIBS=-L/usr/lib -lssl -lcrypto -ldl +OPENSSL_DIR= +OPENSSL_INC= +OPENSSL_LIBS= -INCLUDES= -I. -I/usr/include/malloc $(MUTILS_INCLUDE) $(MSOCK_INCLUDE) $(SLL_INCLUDE) $(OPENSSL_INC) +STRIP=/usr/bin/strip + +INCLUDES= -I. $(MUTILS_INCLUDE) $(MSOCK_INCLUDE) $(SLL_INCLUDE) $(OPENSSL_INC) DEFINES= $(INCLUDES) $(DEFS) -DHAVE_STRING_H=1 -DHAVE_STDLIB_H=1 \ -DHAVE_MATH_H=1 CFLAGS= -g -O2 -Wall $(DEFINES) -LIBS=$(MSOCK_LIB) $(SLL_LIB) $(MUTILS_LIB) -L/usr/lib -lssl -lcrypto -ldl +LIBS=$(MSOCK_LIB) $(SLL_LIB) $(MUTILS_LIB) $(OPENSSL_LIBS) -lresolv -SRCS = main.c smtp.c utils.c setget.c -OBJS = main.o smtp.o utils.o setget.o +SRCS = main.c smtp.c utils.c setget.c examples.c +OBJS = main.o smtp.o utils.o setget.o examples.o .c.o: rm -f $@ $(CC) $(CFLAGS) -c $*.c -all: mlibs $(PROGNAME) +all: $(PROGNAME) -$(PROGNAME) : $(OBJS) + +$(PROGNAME) : mlibs $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $(PROGNAME) $(LIBS) - cp -f $(PROGNAME) ../modules/ -mlibs: +install: installdirs install-bin install-man + +install-bin: $(BINDIR) $(PROGNAME) + $(INSTALL_PROGRAM) $(PROGNAME) $(BINDIR)/$(PROGNAME) + +install-man: + $(INSTALL_DATA) $(MANPAGE) $(MAN1DIR) + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man1 + +deb: + @ruby ./mk_debian_package.rb + +help: + @echo "make - to compile" + @echo "make install - to install" + @echo "make docs - generate document" + @echo "make deb - create debian package" + +docs: + @ruby scripts/mk_doc.rb +ex: + @ruby scripts/mk_examples.rb > examples.c + +libmsock: libmutils (cd libs/libmsock && make) + +libmutils: (cd libs/libmutils && make) - (cd libs/libsll && make) + +libsll: + (cd libs/libsll && make) + +mlibs: libmsock libsll clean: - (cd libs/libmsock && make clean) - (cd libs/libmutils && make clean) - (cd libs/libsll && make clean) + +(cd libs/libmsock && make clean) + +(cd libs/libmutils && make clean) + +(cd libs/libsll && make clean) rm -f *.o *~ core $(PROGNAME) diff --git a/mermsemr/src/mailsend/libs/libmsock/Makefile b/mermsemr/src/mailsend/libs/libmsock/Makefile index b8612a5..c2163d4 100644 --- a/mermsemr/src/mailsend/libs/libmsock/Makefile +++ b/mermsemr/src/mailsend/libs/libmsock/Makefile @@ -3,16 +3,16 @@ # genmake 1.0 by ma_muquit@fccc.edu, RCS ## CC= gcc -DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_YP_GET_DEFAULT_DOMAIN=1 -DHAVE_LIBNSL=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_OPENSSL=1 +DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_LIMITS_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_GETADDRINFO=1 AR= ar cq RANLIB= ranlib LIBNAME= libmsock.a -OPENSSL_DIR=/usr/ -OPENSSL_INC=-I/usr//include -OPENSSL_LIBS=-L/usr//lib -lssl -lcrypto +OPENSSL_DIR= +OPENSSL_INC= +OPENSSL_LIBS= -INCLUDES= -I. -I/usr/include/malloc $(OPENSSL_INC) +INCLUDES= -I. $(OPENSSL_INC) DEFINES= $(INCLUDES) $(DEFS) -DSYS_UNIX=1 CFLAGS= -O $(DEFINES) diff --git a/mermsemr/src/mailsend/libs/libmsock/msock.c b/mermsemr/src/mailsend/libs/libmsock/msock.c old mode 100644 new mode 100755 index 84b0467..f1f07f5 --- a/mermsemr/src/mailsend/libs/libmsock/msock.c +++ b/mermsemr/src/mailsend/libs/libmsock/msock.c @@ -9,6 +9,29 @@ static SSL *s_ssl=NULL; static SOCKET s_sock; static int ssl_status=0; +static FILE *s_logfp = NULL; + +#ifdef WINNT +#undef UNICODE +#endif /* WINNT */ + +static int debug = 0; + +void msock_set_logfp(FILE *logfp) +{ + if (logfp != NULL) + { + s_logfp = logfp; + } + else + { + s_logfp = stderr; + } +} +void msock_set_debug(int d) +{ + debug = d; +} void msock_set_socket(SOCKET sfd) { @@ -63,7 +86,37 @@ struct in_addr *atoAddr(char *address) return ((struct in_addr *) NULL); } + #ifdef WINNT +void msock_print_winsock_error(void) +{ + int + error_code = WSAGetLastError(); + + LPSTR + error_string = NULL; + + if (s_logfp == NULL) + { + s_logfp = stderr; + } + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + error_code, + 0, + (LPSTR) &error_string, + 0, + 0); + (void) fprintf(s_logfp,"Winsock error[%d]: %s\n", + error_code, + error_string); + LocalFree(error_string); + return; +} + + /* returns 0 on success -1 on failure */ int initWinSock(void) { @@ -76,23 +129,149 @@ int initWinSock(void) int err; - version_requested=MAKEWORD(2,0); + version_requested=MAKEWORD(2,2); err=WSAStartup(version_requested,&wsa_data); if (err != 0) { - (void) fprintf(stderr," Unable to initialize winsock (%d)\n",err); + msock_print_error(); return(-1); } return(0); } + +/* +** Adapted from libevent2 +*/ +int msock_get_errno(SOCKET sock_fd) +{ + int + optval, + optvallen = sizeof(optval); + + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK && sock_fd >= 0) + { + if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, (void*)&optval, + &optvallen)) + return err; + if (optval) + return optval; + } + return err; +} #endif /* WINNT */ -/* returns SOCKET on success INVALID_SOCKET on failure */ -SOCKET clientSocket(char *address,int port) +void msock_print_error(void) +{ + if (s_logfp == NULL) + { + s_logfp = stderr; + } +#ifdef WINNT + msock_print_winsock_error(); +#else + (void) fprintf(s_logfp,"Socket Error: [%d]: %s\n", + errno, + strerror(errno)); +#endif /* WINNT */ +} + +#ifdef HAVE_GETADDRINFO +void msock_print_ipaddr(struct addrinfo *res) +{ +#ifdef WINNT + INT + iRetval; + struct sockaddr_in + *sockaddr_ipv4; + LPSOCKADDR + sockaddr_ip; + char + ipstringbuffer[46]; + DWORD + ipbufferlength = 46; +#else + struct sockaddr + *sa; + char + buf[1024]; +#endif /* WINNT */ + + if (res == NULL) return; + if (debug == 0) return; + +#ifdef WINNT + /* + ** Ref: http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx + */ + sockaddr_ip = (LPSOCKADDR) res->ai_addr; + ipbufferlength = 46; + iRetval = WSAAddressToString(sockaddr_ip, (DWORD) res->ai_addrlen, NULL, + ipstringbuffer, &ipbufferlength ); + if (iRetval) + { + (void) fprintf(stderr," WSAAddressToString failed with %u\n", + WSAGetLastError() ); + } + else + { + if (debug) + { + (void) fprintf(stderr," IP address: %s\n",ipstringbuffer); + } + } +#else + sa = (struct sockaddr *) res->ai_addr; + switch (sa->sa_family) + { + case AF_INET: + { + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), + buf,sizeof(buf) - 1); + if (debug) + { + (void) fprintf(stderr," IPv4 address: %s\n",buf); + } + break; + } + case AF_INET6: + { + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), + buf,sizeof(buf) - 1); + if (debug) + { + (void) fprintf(stderr," IPv6 address: %s\n",buf); + } + break; + } + default: + { + (void) fprintf(stderr,"Error: Uknown AF family\n"); + } + } +#endif /* WINNT */ +} +#else +void msock_print_ipaddr(void *res) +{ + ; +} +#endif /* HAVE_GETADDRINFO */ + + +/* +** It is assumed that the socket is a blocking socket. In order to +** timeout the connect(), socket is made non-blocking and changed +** back to blocking after a successful connect, because lot of other calls +** are blocking. Someday I might change everything to non-blocking. +** +** returns a blocking SOCKET on success INVALID_SOCKET on failure +*/ +SOCKET clientSocket(int use, char *address,int port, int connect_timeout) { SOCKET - s; + sock_fd; struct sockaddr_in sa; @@ -100,46 +279,205 @@ SOCKET clientSocket(char *address,int port) struct in_addr *addr; + struct timeval + tv; + + fd_set + fdset; + int + eno, rc; +#ifdef HAVE_GETADDRINFO + char + service[64]; + + struct addrinfo + hints, + *cur, + *res, + *ressave; +#endif /* HAVE_GETADDRINFO */ + #ifdef WINNT rc=initWinSock(); if (rc != 0) return(INVALID_SOCKET); #endif /* WINNT */ - - addr=atoAddr(address); - if (addr == NULL) + +#ifdef HAVE_GETADDRINFO + if (debug) { - (void) fprintf(stderr," Invalid address: %s\n",address); + (void) fprintf(stderr,"> libmsock: using getaddrinfo\n"); + } + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = PF_UNSPEC; + if (use == MSOCK_USE_IPV4) + { + hints.ai_family = PF_INET; + } + if (use == MSOCK_USE_IPV6) + { + hints.ai_family = PF_INET6; + } + (void) snprintf(service, sizeof(service) -1, "%d", port); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + rc = getaddrinfo(address, service, &hints, &res); + if (rc != 0) + { + (void) fprintf(stderr,"Error: Could not find host \"%s\"\n",address); + return(INVALID_SOCKET); + } + ressave = res; + rc = (-1); + for (cur=res; cur != NULL; cur = cur->ai_next) + { + if (debug) + { + switch (cur->ai_family) + { + case AF_UNSPEC: + { + if (debug) + { + (void) fprintf(stderr,"> AF_UNSPEC\n"); + } + break; + } + case AF_INET: + { + if (debug) + { + (void) fprintf(stderr,"> AF_INET IPv4\n"); + } + break; + } + case AF_INET6: + { + if (debug) + { + (void) fprintf(stderr,"> AF_INET6\n"); + } + break; + } + } + msock_print_ipaddr(cur); + } + sock_fd = socket(cur->ai_family, + cur->ai_socktype, + cur->ai_protocol); + if (sock_fd >= 0) + { + msock_make_socket_nonblocking(sock_fd); + /* + ** Try the current addrinfo + ** Patch by https://code.google.com/p/mailsend/issues/detail?id=34 + */ + rc = connect(sock_fd, cur->ai_addr, cur->ai_addrlen); + eno = msock_get_errno(sock_fd); + if (debug) + { + (void) fprintf(stderr,"> EINPROGRESS=%d,EWOULDBLOCK=%d\n", + EINPROGRESS,EWOULDBLOCK); + (void) fprintf(stderr,"> connect(): socket=%d,rc=%d, errno=%d\n", + sock_fd,rc,eno); + } + if (rc != 0) + { + if (eno == EINPROGRESS || + eno == EWOULDBLOCK) + { + /* + ** our socket is non blocking. + ** we need this to timout connection . + ** we'll make the socket blocking again at the end + */ + rc = 0; + if (debug) + { + (void) fprintf(stderr,"> Try socket %d\n",sock_fd); + } + break; + } + } + else + { + msock_close_socket(sock_fd); + } + } + } + freeaddrinfo(ressave); + if (rc != 0) + { + (void) fprintf(stderr,"Could not connect to %s:%d\n",address,port); return(INVALID_SOCKET); } +#else + addr=atoAddr(address); + if (addr == NULL) + { + (void) fprintf(stderr,"Error: Invalid address: %s\n",address); + return(INVALID_SOCKET); + } memset((char *) &sa,0,sizeof(sa)); sa.sin_family=AF_INET; sa.sin_port=htons(port); sa.sin_addr.s_addr=addr->s_addr; /* open the socket */ - s=socket(AF_INET,SOCK_STREAM,PF_UNSPEC); - if (s == INVALID_SOCKET) + sock_fd=socket(AF_INET,SOCK_STREAM,PF_UNSPEC); + if (sock_fd == INVALID_SOCKET) { (void) fprintf(stderr," Could not create socket\n"); return(INVALID_SOCKET); } - + + /* make the socket non-blocking */ + msock_make_socket_nonblocking(sock_fd); + rc=connect(sock_fd,(struct sockaddr *) &sa,sizeof(sa)); +#endif /* HAVE_GETADDRINFO */ /* connect */ - rc=connect(s,(struct sockaddr *) &sa,sizeof(sa)); - if (rc < 0) - return(INVALID_SOCKET); + if (rc != 0 ) + { + eno = msock_get_errno(sock_fd); + if (eno == ECONNREFUSED) + { + msock_print_error(); + msock_close_socket(sock_fd); + return(INVALID_SOCKET); + } + } + FD_ZERO(&fdset); + FD_SET(sock_fd, &fdset); - return(s); + tv.tv_sec = connect_timeout; + tv.tv_usec = 0; + + rc = select(sock_fd + 1, NULL, &fdset, NULL, &tv); + if (rc == -1) + { + (void) fprintf(stderr,"Fatal select() error\n"); + msock_close_socket(sock_fd); + return (INVALID_SOCKET); + } + if (rc == 0) + { + (void) fprintf(stderr,"Error: Connection to %s:%d timed out after %d seconds\n", + address, port, connect_timeout); + msock_close_socket(sock_fd); + return (INVALID_SOCKET); + } + + /* make the socket blocking again*/ + msock_make_socket_blocking(sock_fd); + return(sock_fd); } - /* ** this function writes a character string out to a socket. ** it returns -1 if the connection is closed while it is trying to @@ -201,12 +539,12 @@ int sockPuts(SOCKET sock,char *str) return (sockWrite(sock,str,strlen(str))); } -int sockGets(SOCKET sockfd,char *str,size_t count) +int sockGets(SOCKET sockfd,char *str,size_t count, int read_timeout) { int bytesRead; - int + size_t totalCount=0; char @@ -216,6 +554,34 @@ int sockGets(SOCKET sockfd,char *str,size_t count) char lastRead=0; +#if defined(SO_RCVTIMEO) + struct timeval + tv; +#ifdef WINNT + DWORD + dwTime = read_timeout * 1000; +#endif /* WINNT */ +#endif /* SO_RCVTIMEO*/ + +#if defined(SO_RCVTIMEO) + tv.tv_sec = read_timeout; + tv.tv_usec = 0; + if (debug) + { + (void) fprintf(stderr,"> Setting read timeout to: %d seconds\n", read_timeout); + } +#ifndef WINNT + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); +#else + if (debug) + { + (void) fprintf(stderr,"> Windows Setting read timeout to: %d seconds\n", read_timeout); + } + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&dwTime, sizeof(dwTime)); +#endif + +#endif /* SO_RCVTIMEO*/ + currentPosition=str; while (lastRead != 10) @@ -226,6 +592,8 @@ int sockGets(SOCKET sockfd,char *str,size_t count) /* ** the other side may have closed unexpectedly */ + msock_print_error(); + (void) fprintf(stderr,"Error: Connection is closed unexpectedly\n"); return (-1); } lastRead=buf[0]; @@ -249,7 +617,7 @@ int sockGetsSSL(SSL *ssl,char *str,size_t count) int bytesRead; - int + size_t totalCount=0; char @@ -268,6 +636,8 @@ int sockGetsSSL(SSL *ssl,char *str,size_t count) /* ** the other side may have closed unexpectedly */ + msock_print_error(); + (void) fprintf(stderr,"Error: Connection is closed unexpectedly\n"); return (-1); } lastRead=buf[0]; @@ -289,11 +659,11 @@ int sockGetsSSL(SSL *ssl,char *str,size_t count) /* must be called after msock_set_socket() */ /* must be called after msock_set_ssl() if SSL is on */ -int msock_gets(char *str,size_t count) +int msock_gets(char *str,size_t count, int read_timeout) { if (! msock_is_ssl_on()) { - return(sockGets(msock_get_socket(),str,count)); + return(sockGets(msock_get_socket(),str,count, read_timeout)); } else { @@ -335,3 +705,54 @@ void msock_close(void) msock_close_socket(msock_get_socket()); } +/* +** Make a socket non-blocking +*/ +void msock_make_socket_nonblocking(SOCKET sock_fd) +{ +#ifndef WINNT + int + flags; +#else + unsigned long + mode = 1L; +#endif /* WINNT */ + if (sock_fd == INVALID_SOCKET) + { + return; + } + +#ifdef WINNT + ioctlsocket(sock_fd, FIONBIO, &mode); +#else + /* Stevens: Page 411 */ + flags = fcntl(sock_fd, F_GETFL); + fcntl(sock_fd, F_SETFL, (flags | O_NONBLOCK)); +#endif /* WINNT */ +} + +/* +** Make a socket blocking +*/ +void msock_make_socket_blocking(SOCKET sock_fd) +{ +#ifndef WINNT + int + flags; +#else + unsigned long + mode = 0L; +#endif /* WINNT */ + if (sock_fd == INVALID_SOCKET) + { + return; + } + +#ifdef WINNT + ioctlsocket(sock_fd, FIONBIO, &mode); +#else + /* Stevens: Page 411 */ + flags = fcntl(sock_fd, F_GETFL); + fcntl(sock_fd, F_SETFL, (flags & ~O_NONBLOCK)); +#endif /* WINNT */ +} diff --git a/mermsemr/src/mailsend/libs/libmsock/msock.h b/mermsemr/src/mailsend/libs/libmsock/msock.h old mode 100644 new mode 100755 index c68158d..1af5418 --- a/mermsemr/src/mailsend/libs/libmsock/msock.h +++ b/mermsemr/src/mailsend/libs/libmsock/msock.h @@ -8,8 +8,13 @@ #include #include #include -#include - +/*#include */ +#include +/* http://support.microsoft.com/kb/955045 */ +/* for getaddrinfo in win2k */ +#include +#include +#define snprintf _snprintf #else #include @@ -53,8 +58,17 @@ #endif /* HAVE_OPENSSL */ -SOCKET clientSocket(char *,int); -int sockGets(SOCKET,char *,size_t); +#include "werrno.h" + +#define MSOCK_USE_IPV4 0x01 +#define MSOCK_USE_IPV6 0x02 +#define MSOCK_USE_AUTO 0x03 + +/** + * familty can be USE_IPV4, USE_IPV6 or USE_AUTO + */ +SOCKET clientSocket(int use, char *server_addr,int port, int connect_timeout); +int sockGets(SOCKET,char *,size_t, int read_timoeut); int sockPuts(SOCKET sock,char *str); void msock_set_socket(SOCKET sock); @@ -62,10 +76,22 @@ SOCKET msock_get_socket(void); void msock_turn_ssl_on(void); void msock_turn_ssl_off(void); int msock_is_ssl_on(void); -int msock_gets(char *buf,size_t bufsiz); +int msock_gets(char *buf,size_t bufsiz, int connect_timeout); int msock_puts(char *str); void msock_close_socket(SOCKET fd); void msock_close(void); +void msock_make_socket_nonblocking(SOCKET sock_fd); +void msock_make_socket_blocking(SOCKET sock_fd); +void msock_print_error(void); +void msock_set_logfp(FILE *logfp); +void msock_set_debug(int debug); + +#ifdef WINNT +int msock_get_errno(SOCKET sock_fd); +#else +#define msock_get_errno(sock_fd) (errno) +#endif /* WINNT */ + #ifdef HAVE_OPENSSL diff --git a/mermsemr/src/mailsend/libs/libmutils/Makefile b/mermsemr/src/mailsend/libs/libmutils/Makefile index 6c5e203..84a4eb1 100644 --- a/mermsemr/src/mailsend/libs/libmutils/Makefile +++ b/mermsemr/src/mailsend/libs/libmutils/Makefile @@ -1,23 +1,24 @@ -# -# ma_muquit@fccc.edu -# jul-29-199 -# +# jul-29-1999 CC= gcc -DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_YP_GET_DEFAULT_DOMAIN=1 -DHAVE_LIBNSL=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_OPENSSL=1 +DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_LIMITS_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_GETADDRINFO=1 AR= ar cq RANLIB= ranlib LIBNAME= libmutils.a -INCLUDES= -I. -I/usr/include/malloc +OPENSSL_DIR= +OPENSSL_INC= +OPENSSL_LIBS= -# replace -O with -g in order to debug +INCLUDES= -I. $(OPENSSL_INC) DEFINES= $(INCLUDES) $(DEFS) -DSYS_UNIX=1 CFLAGS= -O $(DEFINES) -SRCS = string.c mutils.c mime.c -OBJS = string.o mutils.o mime.o +SRCS = string.c mutils.c mutils_mime.c mutils_blob.c \ + mutils_error.c mutils_temp.c mutils_time.c +OBJS = string.o mutils.o mutils_mime.o mutils_blob.o \ + mutils_error.o mutils_temp.o mutils_time.o .c.o: rm -f $@ diff --git a/mermsemr/src/mailsend/libs/libmutils/README b/mermsemr/src/mailsend/libs/libmutils/README old mode 100644 new mode 100755 diff --git a/mermsemr/src/mailsend/libs/libmutils/md5test.c b/mermsemr/src/mailsend/libs/libmutils/md5test.c old mode 100644 new mode 100755 diff --git a/mermsemr/src/mailsend/libs/libmutils/mutils.c b/mermsemr/src/mailsend/libs/libmutils/mutils.c old mode 100644 new mode 100755 index ae06c13..26eef66 --- a/mermsemr/src/mailsend/libs/libmutils/mutils.c +++ b/mermsemr/src/mailsend/libs/libmutils/mutils.c @@ -6,6 +6,263 @@ static int lock_fd=(-1); +static const char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* taken from Parrot code */ +const char Parrot_utf8skip[256] = +{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* bogus */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* bogus */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* bogus */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* bogus */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* scripts */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* scripts */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* cjk etc. */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6 /* cjk etc. */ +}; + +#define UTF8_IS_START(c) ((c) >= 0xC2 && (c) <= 0xF4) +#define UTF8SKIP(c) Parrot_utf8skip[c] +#define UTF8_IS_CONTINUATION(c) (((c) & 0xC0) == 0x80) + + + + +void mutils_liberate_memory(void **memory) +{ + if (memory == NULL) + return; + + if (*memory) + free(*memory); + *memory=(void *) NULL; +} +void mutils_liberate(void **memory) +{ + if (memory == NULL) + return; + + if (*memory) + free(*memory); + *memory=(void *) NULL; +} +void mutils_free_zero(void *buf,int size) +{ + if (buf) + { + memset(buf,0,size); + mutils_liberate_memory(&buf); + } +} + +/** + * @brief same as mutils_acquire_memory + */ +void *mutils_acquire_memory(size_t size) +{ + void + *ptr; + + if (size == 0) + { + mutils_error("%s (%d) - allocation size is specified as 0\n",MUTILS_CFL); + return(NULL); + } + ptr=malloc(size); + if (ptr) + { + memset(ptr,0,size); + } + + return(ptr); +} + +/* +** changes the size of the memory and returns a pointer to the (possibly +** moved) block. The contents will be unchanged up to the lesser of the new +** and old sizes. +*/ +void mutils_reacquire_memory(void **memory,const size_t size) +{ + void + *allocation; + + if (memory == NULL) + return; + + if (*memory == (void *) NULL) + { + *memory=mutils_acquire_memory(size); + return; + } + allocation=realloc(*memory,size); + + if (allocation == (void *) NULL) + mutils_liberate_memory((void **) memory); + + *memory=allocation; +} + + +/* from my hod program, muquit, Nov-10-2000 */ +static void mutils_hex_or_oct_dump(FILE *fp,int base,unsigned char *buf,int length) +{ + int + ii, + i; + + unsigned char + hexbuf[16]; + + int + count=0; + + int + line = 0; + + int + c; + + unsigned char + *p=buf; + + + if (length <= 0) + return; + + *hexbuf='\0'; + + + (void) fprintf (fp, + (base == 16) ? "%11d" : "%11d",0); + + (void) fflush (fp); + + for (i=1; i= 32 && hexbuf[i] < 127) + (void) fprintf (fp,"%c", hexbuf[i]); + else + (void) fprintf (fp,"."); + } + count=0; + line++; + (void) fprintf (fp,"\n"); + } + } /* while c!= EOF*/ + (void) fflush (fp); + + /* + ** pad if necessary + */ + if (count < base) + { + int + j; + + for (j=count; j = 32 && hexbuf[i] < 127) + { + (void) fprintf (fp,"%c", hexbuf[i]); + } + else + (void) fprintf (fp,"."); + } + (void) fprintf (fp,"\n"); + (void) fflush (fp); + } /* count < base .. */ +} + +void mutils_hex_dump(FILE *fp,unsigned char *buf,int length) +{ + mutils_hex_or_oct_dump(fp,16,buf,length); +} + +void mutils_hex_print(FILE *fp,unsigned char *bytes,int len) +{ + int + i; + for (i=0; i < len; i++) + { + (void) fprintf(fp,"%02x ",bytes[i]); + if ((i % 16) == 15) + fprintf(fp, "\n"); + + } + (void) fprintf(fp,"\n"); +} + + + +void mutils_oct_dump(FILE *fp,unsigned char *buf,int length) +{ + mutils_hex_or_oct_dump(fp,8,buf,length); +} + + /* ** mutilsHowmanyCommas() @@ -224,9 +481,7 @@ int /* initialize */ *port=80; - *hostname='\0'; - *page='\0'; - *tmpbuf='\0'; + *hostname = *page = *tmpbuf = '\0'; tmpbuf_len=sizeof(tmpbuf); @@ -324,8 +579,7 @@ char *mutilsSpacesToChar(char *str,int c) { char *ibuf, - *obuf, - *nbuf; + *obuf; register int i, @@ -708,6 +962,7 @@ void mutilsStripTrailingSpace (char *str) ** make a temporary filename ** filename - returns */ +#if 0 int mutilsTmpFilename(char *filename) { #define TMP_DIR "/tmp" @@ -726,6 +981,7 @@ int mutilsTmpFilename(char *filename) return(mktemp(filename)); #endif /* ! HAVE_MKSTEMP */ } +#endif /* 0 */ /* @@ -767,9 +1023,7 @@ int mutilsTmpFilename(char *filename) * Development History: * 3/26/92, jps, first cut */ -char *mutilsBasename(path) -char - *path; +char *mutilsBasename(char *path) { char *cptr; @@ -788,6 +1042,80 @@ char } +/* +** Return the extension of a file in a path +** Parameters: +** path - path of a file +** Return Values: +** pointer to the extension +** Side Effects: +** none +** Comments: +** If that is /usr/local/file.pdf, pointer to +** pdf will be returned +** Development History: +** muquit@muquit.com Dec-15-2013 - needed to detect mime type based on extension +*/ +char *mutilsExtension(char *path) +{ + char + *base, + *cptr; + + base = mutilsBasename(path); + for (cptr = base + strlen(base); cptr >= base; --cptr) + { + switch (*cptr) + { + case '.': + { + return ++cptr; + } + } + } + return path; +} + +char *mutilsExtensionLower(char *path) +{ + char + *ext; + return (mutilsStrLower(mutilsExtension(path))); +} + + +/* +** Return the basename of a path +** Parameters: +** path - path in Unix or windows style +** +** Return Values: +** pointer to the basename on success +** pointer to the path on failure +** Side Effects: +** no memory is allocated, pointer is returned +** pointing to the basename +** Comments: +** If path is say /usr/local/foo, foo will be returned +** on success. if path is c:\foo\bar, pointer to bar +** will be returned. if path is blah, pointer ot +** blah will be returned +** Development History: +** muquit@muquit.com Dec-15-2013 +** didn't know I already had it +*/ +char *mutils_basename(const char *path) +{ + char + *bn = path; + bn = strrchr(path,'/'); + if (bn == NULL) + { + bn = strrchr(path,'\\'); + } + return (bn == NULL) ? path : ++bn; +} + /* ** mutilsDotLock() ** open a file for locking purpose. If the system is Unix, use @@ -985,9 +1313,6 @@ char *f, *p; - int - len; - if (file == NULL || *file == '\0') return (NULL); @@ -1142,15 +1467,41 @@ static void _fs_give (void **block) *block = NULL; } +/* +** +** Given the length of a plain text string, return the +** length +** +** Parameters: +** len - length of plain text string +** +** Side Effects: +** none +** +** Comments: +** taken from apache apr util library +** +** Return Values: +** length of base64 encoded string +** +** Development History: +** muquit@muquit.com Oct-12-2013 first cut +*/ +int mutils_base64_encode_len(int len) +{ + return ((len + 2) / 3 * 4) + 1; +} + /** + * @Deprecated * @brief encode content to base64 * @param src pointer to source * @param srcl Length of the source * @param len length of base64 encoded string (returns) * * @return Ponter to encoded strin gon success, NULL on failure. The -* caller is responsile to free the memory + * caller is responsile to free the memory * * Adapted from from c-client source */ @@ -1215,6 +1566,82 @@ unsigned char *mutils_encode_base64(void *src,unsigned long srcl,unsigned long * return (ret); /* return the resulting string */ } +/* +** Endode a string to base64 +** +** Parameters: +** string - plain text/binary string +** len - length of the plain text string +** +** Return Values: +** Pointer to null terminated base 64 string. Memory is allocated for +** the string +** NULL in case of error. +** Comments: +** reason not to use mutils_encode_base64(), it adds crlf after 60 +** characters, which broke smtp auth with longer base64 encoded string. +** +** The caller is responsible to free the memory of the returned string. +** +** Adapted from apache apr util library. Does not support EBCDIC. +** +** Side Effects: +** none +** +** Development History: +** muquit@muquit.com Oct-12-2013 first cut +*/ +char *mutils_encode_base64_noformat(const char *string, int len) +{ + int + encode_len, + i; + + char + *p, + *encoded = NULL; + + if (len == 0) + { + return NULL; + } + + encode_len = mutils_base64_encode_len(len); + encoded = (char *) malloc(encode_len); + MUTILS_CHECK_MALLOC(encoded); + memset(encoded, 0, encode_len); + p = encoded; + for (i = 0; i < len - 2; i += 3) + { + *p++ = basis_64[(string[i] >> 2) & 0x3F]; + *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; + *p++ = basis_64[string[i + 2] & 0x3F]; + } + if (i < len) + { + *p++ = basis_64[(string[i] >> 2) & 0x3F]; + if (i == (len - 1)) + { + *p++ = basis_64[((string[i] & 0x3) << 4)]; + *p++ = '='; + } + else + { + *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + *p++ = '\0'; + return encoded; +ExitProcessing: + return NULL; + + return strdup("fuck"); +} + /** * @brief converts base64 contents to binary @@ -1330,6 +1757,317 @@ void *mutils_decode_base64(unsigned char *src,unsigned long srcl,unsigned long * return ret; /* return the string */ } +unsigned char mutils_hex_char_to_bin(char x) +{ + if (x >= '0' && x <= '9') + return(x - '0'); + + x=toupper(x); + return((x - 'A') + 10); +} +/** + * convert a hex string to it's binary format. + * @param hex_string - The hex string to convert + * @param len - length of the hex string + * @param *olen - The length of the binary string - returns + * + * @return pointer to a unsigned char holding the binary version of the + * hex string. returns NULL on failure. The caller should check + * olen (> 0) before using the binary + * + * @note Memory is allocated for the retured unsigned char pointer + * The caller is responsible to free it + * + * The format of the hex string can be any of: + * 0xde:ad:be:ef:ca:fe + * de:ad:be:ef:ca:fe + * de-ad-be-ef-ca-fe + * 0xde-ad-be-ef-ca-fe + * de:ad-be_ef:ca:fe + * + * The converted binary value will be: de ad be ef ca fe + * + * It will only convert valid hex strings to binary, for example, if + * the string is like: de:gh:ad:ff:bb:kk:cc + * The binary value will contain: de ad ff bb cc + * Note, gh and kk are ignored + */ +unsigned char *mutils_hex_to_bin(char *hex_string,int len,int *olen) +{ + int + j=0; + int + bin_len=0, + n=0, + i; + + unsigned char + value, + *out, + space[4]; + + char + *cp=hex_string; + + if (! hex_string || ! len) + return(NULL); + + if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) + { + cp += 2; + n=2; + } + + /* + ** allocate half of hex_string as the length of binary. + ** we may be allocated more than needed as : - etc may be + ** part of the hex string + */ + bin_len=(len >> 1); + if (bin_len <= 0) + return(NULL); + + out=(unsigned char *) malloc(bin_len*sizeof(unsigned char)); + memset(out,0,bin_len); + for (i=n; i < len; i += 2) + { + if (hex_string[i] == '\n' || hex_string[i] == '\r' || + hex_string[i] == ' ' || hex_string[i] == '\t' || + hex_string[i] == ':' || + hex_string[i] == '-' || + hex_string[i] == '_') + { + i--; + continue; + } + if (isxdigit(hex_string[i]) && isxdigit(hex_string[i+1])) + { + value=(mutils_hex_char_to_bin (hex_string[i]) << 4) & 0xf0; + value |= (mutils_hex_char_to_bin(hex_string[i+1]) & 0x0f); + out[j++]=value; + } + } + *olen=j; + + return(out); +} + +/** + * @brief convert binary to hex + * @param input - binary data + * @param len - length of input data + * @param output - NULL terminated string equivalent in hex + * @return length of output string (not including NULL) on success, -1 + * on failure + * + * Note: *output points to a malloc'd space, caller is responsible to + * to free it + * adapted from net-snmp 5.0.6 code (tools.c) + */ +int mutils_binary_to_hex(unsigned char *input,int len,char **output) +{ + int + olen; + char + *s, + *op; + + unsigned char + *ip; + + olen=(len * 2) + 1; + s=(char *) calloc(1,olen); + if (s == NULL) + return (-1); + op=s; + + ip=input; + while ((ip - input) < len) + { + *op++ = MUTILS_VAL2_HEX((*ip >> 4) & 0xf); + *op++ = MUTILS_VAL2_HEX(*ip & 0xf); + ip++; + } + *op='\0'; + *output=s; + + return(olen); +} + +/** + * @brief convert binary to hex + * @param in binary data + * @param in_len length of input in bytes + * @param out output buffer to hold the converted hex data. in/out. The buffer is + * NULL terminated. + * @param out_len bytes of memroy pre allocated in out. out_len must be + * greater than in_len*2 + * @return length of converted hex buffer on success, -1 on failure + * + * Note: this function is similar to mutils_binary_to_hex(), only differece is + * that in this function, the caller passes the pre-allocated buffer. + */ +int mutils_binary_to_hex_buf(unsigned char *in,int in_len,char *out,int *out_len) +{ + char + *op; + + unsigned char + *ip; + + op=out; + ip=in; + if (*out_len < (in_len * 2) + 1) + { + *out_len=(-1); + (void) fprintf(stderr,"%s (%d) - outbuf must have atlease %d bytes of space pre-allocated\n", + MUTILS_CFL,((in_len * 2) + 1)); + return(-1); + } + + *out_len=(in_len * 2); + while ((ip - in) < in_len) + { + *op++ = MUTILS_VAL2_HEX((*ip >> 4) & 0xf); + *op++ = MUTILS_VAL2_HEX(*ip & 0xf); + ip++; + } + *op='\0'; + return(*out_len); +} + + +/* +** return MUTILS_TRUE if the file is binary. MUTILS_FALSE otherwise. +** return -1 on error +** The algorithm is adapted from Perl pp_fttext() +** 512 bytes of file is used. +** +** here is the algorithm (perldoc -I -B|more) + The "-T" and "-B" switches work as follows. The first block or + so of the file is examined for odd characters such as strange + control codes or characters with the high bit set. If too many + strange characters (>30%) are found, it's a "-B" file; + otherwise it's a "-T" file. Also, any file containing a zero + byte in the first block is considered a binary file +*/ +int mutils_file_is_binary(const char *file) +{ + struct stat + sbuf; + + FILE + *fp = NULL; + + char + *s, + buf[513]; + + size_t + len; + int + i, + sz, + n; + + int + odd = 0; + + float + x; + + sz = sizeof(buf) - 1; + if (stat(file, &sbuf) != 0) + { + (void) fprintf(stderr,"Could not stat file %s\n",file); + return(-1); + } + len = sbuf.st_size; + if (len > 512) + { + len = 512; + } + fp = fopen(file, "rb"); + if (fp == NULL) + { + (void) fprintf(stderr,"Error reading file: %s\n",file); + return(-1); + } + memset(buf, 0, sizeof(buf)); + n = fread(buf, 1, len, fp); + if (n != len) + { + (void) fprintf(stderr,"read error\n"); + return(-1); + } + + s = buf; + + if (len && len < sizeof(buf) && buf[len - 1] == 0x1a) + { + --len; + } + for (i=0; i < len; i++, s++) + { + if (!*s) + { + odd += len; + break; + } + else if (*s & 128) + { + if (UTF8_IS_START(*s)) + { + int ulen = UTF8SKIP(*s); + if (ulen < len - i) + { + int + j; + for (j = 1; j < ulen; j++) + { + if (!UTF8_IS_CONTINUATION(s[j])) + { + goto NotUtf8; + } + } + --ulen; + s += ulen; + i += ulen; + continue; + } + } +NotUtf8: + odd++; + } + else + { + if (*s < 32 && *s != '\n' && *s != '\r' && *s != '\b' && + *s != '\t' && *s != '\f' && *s != 27) + { + odd++; + } + } + } + x = ((odd * 1.0) / (len * 1.0)); + if (x < 0.30) + { + return MUTILS_FALSE; + } + else + { + return MUTILS_TRUE; + } + + +ExitProcessing: + if (fp) + { + (void) fclose(fp); + } + return(-1); +} + + #ifdef TEST diff --git a/mermsemr/src/mailsend/libs/libmutils/mutils.h b/mermsemr/src/mailsend/libs/libmutils/mutils.h old mode 100644 new mode 100755 index a8257e8..8782603 --- a/mermsemr/src/mailsend/libs/libmutils/mutils.h +++ b/mermsemr/src/mailsend/libs/libmutils/mutils.h @@ -33,7 +33,20 @@ #include #include #include +#include +#include /* for timeval */ #define ftruncate chsize + +#ifdef getcwd +#undef getcwd +#endif +#define getcwd _getcwd + +#ifdef snprintf +#undef snprintf +#endif +#define snprintf _snprintf + #endif #if HAVE_SYS_PARAM_H @@ -48,6 +61,8 @@ #include #endif +#include + #if HAVE_FCNTL_H #ifndef O_RDONLY /* prevent multiple inclusion on lame systems (from vile)*/ @@ -75,8 +90,62 @@ vile)*/ #endif #endif -#define MUTILS_CFL __FILE__,__LINE__ +#if APR_HAVE_LIMITS_H +#include +#else +#if APR_HAVE_SYS_SYSLIMITS_H +#include +#endif +#endif +#if defined(PATH_MAX) +#define MUTILS_PATH_MAX PATH_MAX +#elif defined(_POSIX_PATH_MAX) +#define MUTILS_PATH_MAX _POSIX_PATH_MAX +#else +#define MUTILS_PATH_MAX 4098 +#endif + +#if !defined(O_BINARY) +#define O_BINARY 0x00 +#endif + +#define MUTILS_TRUE 1 +#define MUTILS_FALSE 0 + + +typedef struct _MutilsBlob +{ + size_t + length; + + unsigned char + *data; + + size_t + offset, + size; +}MutilsBlob; + +#ifdef WINNT +typedef struct _MutilsTime +{ + FILETIME + absolute; +}MutilsTime; +#else +typedef struct _MutilsTime +{ + unsigned int + secs, + nsecs; +}MutilsTime; +#endif /* WINNT */ + + +#define MUTILS_CFL __FILE__,__LINE__ +#define MCFL __FILE__,__LINE__ +#define MJL __LINE__ #if __STDC__ || defined(sgi) || defined(_AIX) #undef _Declare @@ -88,7 +157,6 @@ vile)*/ #define MUTILS_MAX_TOKEN_LEN 1024 - #define MUTILS_CHECK_MALLOC(p) \ do \ { \ @@ -99,9 +167,42 @@ do \ }\ }while(0) +/* from net-snmp 5.0.6 tools.h */ +#define MUTILS_FREE(s) if (s) { free((void *)s); s=NULL;} +#define MUTILS_TOUPPER(c) (c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c) +#define MUTILS_TOLOWER(c) (c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c) + +#define MUTILS_VAL2_HEX(s) ( (s) + (((s) >= 10) ? ('a'-10) : '0') ) +#define MUTILS_HEX2_VAL(s) \ + ((isalpha(s) ? (MUTILS_TOLOWER(s)-'a'+10) : (MUTILS_TOLOWER(s)-'0')) & 0xf) + +#define MUTILS_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MUTILS_MIN(a,b) ((a) > (b) ? (b) : (a)) +/* from net-snmp 5.0.6 tools.h */ + + /* function prototypes */ +typedef void (*mutils_error_func) (char *fmt,va_list args); +typedef void (*mutils_hexdump_func) (unsigned char *bytes,int bytes_len); +void mutils_error (char *fmt,...); +void mutils_info (char *fmt,...); +void mutils_warn (char *fmt,...); +void mutils_debug(char *fmt,...); +void mutils_set_debug(int debug); +void mutils_set_error_hook(mutils_error_func new_func); +void mutils_set_info_hook(mutils_error_func new_func); +void mutils_set_debug_hook(mutils_error_func new_func); +void mutils_set_warn_hook(mutils_error_func new_func); +void mutils_set_hexdump_hook(mutils_hexdump_func new_func); +void mutils_set_hexprint_hook(mutils_hexdump_func new_func); + +void mutils_reset_error_hook(void); +void mutils_reset_info_hook(void); +void mutils_reset_warn_hook(void); +void mutils_reset_debug_hook(void); + void mutilsBase64Encode (FILE *ifp,FILE *ofp); void mutilsGenerateMIMEBoundary(char *boundary,int len); int mutilsParseURL (char *url,char *hostname, @@ -127,8 +228,10 @@ char *mutilsStristr (char *s,char *t); int mutilsIsinname (char *string,char *mask); char *mutilsGetTime (void); char mutilsChopNL (char *str); -int mutilsTmpFilename (char *filename); +/*int mutilsTmpFilename (char *filename);*/ char *mutilsBasename (char *path); +char *mutilsExtension (char *file_path); +char *mutilsExtensionLower (char *file_path); int mutilsWhich (char *name); void mutilsSetLock (int fd); void mutilsDotLock (char *filepath,char *errbuf); @@ -141,8 +244,64 @@ char *mutilsGetDirname (char *file); char *mutilsSpacesToChar (char *str,int c); char **mutilsTokenize(char *str,int delim,int *ntokens); void mutilsFreeTokens(char **tokens,int ntokens); +int mutils_base64_encode_len(int len); unsigned char *mutils_encode_base64(void *src,unsigned long srcl,unsigned long *len); +char *mutils_encode_base64_noformat(const char *src, int src_len); void *mutils_decode_base64(unsigned char *src,unsigned long srcl,unsigned long *len); +int mutils_make_encrypted_key(const char *plain,unsigned char *cipher,int clen); +int mutils_decrypt_key(unsigned char *cipher,int clen,char *plain,int plain_buf_len); +char *mutils_decrypt_hex(char *hex,int hex_len,char *pbuf,int pbuf_len); +void mutils_hex_dump(FILE *fp,unsigned char *buf,int length); +void mutils_hex_print(FILE *fp,unsigned char *bytes,int len); +unsigned char *mutils_get_master_key24(void); +unsigned char *mutils_get_iv8(void); + +unsigned char mutils_hex_char_to_bin(char x); +unsigned char *mutils_hex_to_bin(char *hex_string,int len,int *olen); +int mutils_binary_to_hex(unsigned char *input,int len,char **output); +int mutils_binary_to_hex_buf(unsigned char *in,int in_len,char *out,int *out_len); + +void *mutils_acquire_memory(size_t size); +void mutils_liberate_memory(void **memory); +void mutils_reacquire_memory(void **memory,const size_t size); +void mutils_attach_blob(MutilsBlob *blob_info,void *blob,size_t length); +void mutils_rewind_blob(MutilsBlob *blob); +MutilsBlob *mutils_clone_blobinfo(MutilsBlob *blob_info); +MutilsBlob *mutils_allocate_blob(int data_len); +MutilsBlob *mutils_file_to_blob(char *filename); +MutilsBlob *mutils_data_to_blob(unsigned char *data,int data_len); +void mutils_detach_blob(MutilsBlob *blob_info); +void mutils_destroy_blob(MutilsBlob *blob); +void mutils_msb_order_long(char *p,const size_t length); +void mutils_msb_order_short(char *p,const size_t length); + +int mutils_read_blob(MutilsBlob *blob_info,const size_t length, + void *data); +int mutils_read_blob_byte(MutilsBlob *blob); +unsigned long mutils_read_blob_lsb_long(MutilsBlob *blob_info); +unsigned short mutils_read_blob_lsb_short(MutilsBlob *blob); +unsigned long mutils_read_blob_msb_long(MutilsBlob *blob,int *err_no); +unsigned short mutils_read_blob_msb_short(MutilsBlob *blob,int *err_no); +char *mutils_read_blob_string(MutilsBlob *blob,char *string,int slen); +int mutils_size_blob(MutilsBlob *blob); +int mutils_tell_blob(MutilsBlob *blob); + +int mutils_write_blob(MutilsBlob *blob,const size_t length,const void *data); +size_t mutils_write_blob_byte(MutilsBlob *blob_info,const long value); +int mutils_write_blob_lsb_long(MutilsBlob *blob,const unsigned long value); +int mutils_write_blob_lsb_short(MutilsBlob *blob,const unsigned long value); +int mutils_write_blob_msb_long(MutilsBlob *blob,const unsigned long value); +int mutils_write_blob_msb_short(MutilsBlob *blob,const unsigned long value); +size_t mutils_write_blob_string(MutilsBlob *blob_info,const char *string); +char *mutils_getcwd(char *buf,int buflen); +FILE *mutils_get_tempfileFP(char *tempfile_path,int buflen); +char *mutils_basename(const char *path); +int mutils_file_is_binary(const char *file); + +/* time */ +int mutils_time_now(MutilsTime *mt); +void mutils_time_fmt(MutilsTime *mt,char *buf,int bufsiz); + #endif /* MUTILS_H */ diff --git a/mermsemr/src/mailsend/libs/libmutils/string.c b/mermsemr/src/mailsend/libs/libmutils/string.c old mode 100644 new mode 100755 index a45e4dc..7f665fd --- a/mermsemr/src/mailsend/libs/libmutils/string.c +++ b/mermsemr/src/mailsend/libs/libmutils/string.c @@ -348,7 +348,7 @@ void mutilsSafeStrcat(char *dst,char *src,int length,int ssc_size, exit(0); } - if (strlen(src) >= ssc_size - ssc_length) + if ((int) strlen(src) >= ssc_size - ssc_length) { /* StringImage("buffer overflow detected! aborting"); @@ -506,5 +506,5 @@ char *mutilsStrLower(char *str) *s=tolower(*s); } - return (s); + return (str); } diff --git a/mermsemr/src/mailsend/libs/libmutils/test.c b/mermsemr/src/mailsend/libs/libmutils/test.c old mode 100644 new mode 100755 diff --git a/mermsemr/src/mailsend/libs/libmutils/testb64.c b/mermsemr/src/mailsend/libs/libmutils/testb64.c old mode 100644 new mode 100755 diff --git a/mermsemr/src/mailsend/libs/libsll/Makefile b/mermsemr/src/mailsend/libs/libsll/Makefile index c799e27..4039534 100644 --- a/mermsemr/src/mailsend/libs/libsll/Makefile +++ b/mermsemr/src/mailsend/libs/libsll/Makefile @@ -4,12 +4,12 @@ # Aug-07-1998 # CC= gcc -DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_YP_GET_DEFAULT_DOMAIN=1 -DHAVE_LIBNSL=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_OPENSSL=1 +DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_STRINGS_H=1 -DHAVE_MEMORY_H=1 -DHAVE_MALLOC_H=1 -DHAVE_UNISTD_H=1 -DHAVE_CTYPE_H=1 -DHAVE_STDINT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_STDLIB_H=1 -DHAVE_FCNTL_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_LIMITS_H=1 -DHAVE_FLOCK=1 -DHAVE_SOCKET=1 -DHAVE_HTONL=1 -DHAVE_GETHOSTNAME=1 -DHAVE_GETHOSTBYADDR=1 -DHAVE_RES_SEARCH=1 -DHAVE_LIBRESOLV=1 -DHAVE_INET_ATON=1 -DHAVE_DN_SKIPNAME=1 -DHAVE_MKSTEMP=1 -DHAVE_GETADDRINFO=1 AR= ar cq RANLIB= ranlib LIBNAME= libsll.a -INCLUDES= -I. -I/usr/include/malloc +INCLUDES= -I. # replace -O with -g in order to debug diff --git a/mermsemr/src/mailsend/libs/libsll/sll.c b/mermsemr/src/mailsend/libs/libsll/sll.c old mode 100644 new mode 100755 diff --git a/mermsemr/src/mailsend/libs/libsll/sll.h b/mermsemr/src/mailsend/libs/libsll/sll.h old mode 100644 new mode 100755 diff --git a/mermsemr/src/mailsend/mailsend.h b/mermsemr/src/mailsend/mailsend.h old mode 100644 new mode 100755 index 1beb394..ff1724c --- a/mermsemr/src/mailsend/mailsend.h +++ b/mermsemr/src/mailsend/mailsend.h @@ -8,6 +8,7 @@ #include + #include "mutils.h" #include "msock.h" #include "sll.h" @@ -28,6 +29,7 @@ #endif /* HAVE_OPENSSL */ + /* ** header for mailsend - a simple mail sender via SMTP ** $Id: mailsend.h,v 1.3 2002/06/22 21:17:29 muquit Exp $ @@ -39,27 +41,28 @@ #define MFL __FILE__,__LINE__ -#define MAILSEND_VERSION "@(#) mailsend v1.15b5" +#define MAILSEND_VERSION "@(#) mailsend v1.20b2" #define MAILSEND_PROG "mailsend" #define MAILSEND_AUTHOR "muquit@muquit.com" #define MAILSEND_URL "http://www.muquit.com/" -#define NO_SPAM_STATEMENT "GNU GPL. It is illegal to use this software for Spamming" +#define NO_SPAM_STATEMENT "BSD. It is illegal to use this software for Spamming" -#define MAILSEND_SMTP_PORT 587 // 25 +#define MAILSEND_SMTP_PORT 25 #define MAILSEND_DEF_SUB "" - #define A_SPACE ' ' #define A_DASH '-' #define EMPTY_OK 0x01 #define EMPTY_NOT_OK 0x02 -#define ATTACHMENT_SEP ',' #define FILE_TYPE_DOS 0x00000001 #define FILE_TYPE_UNIX 0x00000002 #define FILE_TYPE_BINARY 0x00000004 +#define DEFAULT_CONNECT_TIMEOUT 5 /* seconds */ +#define DEFAULT_READ_TIMEOUT 5 /* seconds */ + #ifdef EXTERN #undef EXTERN @@ -67,7 +70,7 @@ #ifndef __MAIN__ #define EXTERN extern -#else +#else #define EXTERN #endif /* __MAIN__ */ @@ -111,10 +114,45 @@ do \ }\ }while(0) +#define RETURN_IF_NOT_ZERO(rc) \ +do \ +{ \ + if (rc != 0) \ + { \ + return(rc); \ + } \ +}while(0) + +#define CHECK_WRITE_STATUS(n) \ +do \ +{ \ + if (n <= 0) \ + { \ + goto ExitProcessing; \ + } \ +}while(0) + + #define ERR_STR strerror(errno) +#define CONTENT_DISPOSITION_INLINE 0x01 +#define CONTENT_DISPOSITION_ATTACHMENT 0x02 + +/* only suport base64 at this time */ +/* as of Jul-01-2013 */ +#define ENCODE_7BIT 0x01 /* default for text/plain */ +#define ENCODE_8BIT 0x02 +#define ENCODE_BASE64 0x03 +#define ENCODE_QUOTED_PRINTABLE 0x04 +#define ENCODE_NONE 0x05 + +#define DEFAULT_CHARSET "utf-8" + EXTERN int g_verbose; +EXTERN int g_connect_timeout; +EXTERN int g_read_timeout; EXTERN int g_wait_for_cr; +EXTERN int g_do_ssl; EXTERN int g_do_starttls; EXTERN int g_quiet; EXTERN int g_do_auth; @@ -126,12 +164,25 @@ EXTERN char g_charset[33]; EXTERN char g_username[64]; EXTERN char g_userpass[64]; EXTERN char g_from_name[64]; +EXTERN char g_content_transfer_encoding[32]; +EXTERN FILE *g_log_fp; +EXTERN char g_log_file[MUTILS_PATH_MAX]; +EXTERN int g_show_attachment_in_log; +EXTERN int g_use_protocol; +EXTERN char g_content_type[64]; +EXTERN char g_attach_sep[4]; +EXTERN char g_attach_name[64]; +EXTERN char g_content_disposition[32]; +EXTERN char g_content_id[64]; +EXTERN char g_mime_type[64]; +EXTERN int g_force; + typedef struct _Address { /* - ** label holds strings like "To" "Cc" "Bcc". + ** label holds strings like "To" "Cc" "Bcc". ** The address is the email address. */ @@ -144,11 +195,31 @@ typedef struct _Attachment { char *file_path, - *file_name; + *file_name, + *attachment_name, + *content_id; + + char + *oneline_msg; + char *mime_type; + char *content_disposition; + + char + *content_transfer_encoding, + *charset; + + int + attach_separator; + + FILE + *fp_read; + + char + mime_tmpfile[MUTILS_PATH_MAX]; }Attachment; /* the mail sturct */ @@ -180,34 +251,58 @@ typedef struct _Mailsendrc }Mailsendrc; /* function prototypes */ -char *xStrdup(char *string); +char *xStrdup(const char *string); int addAddressToList(char *a,char *label); TheMail *initTheMail(void); Address *newAddress(void); Sll *getAddressList(void); void printAddressList(void); void print_server_caps(void); +void print_one_lines(void); char *check_server_cap(char *what); -int read_smtp_line(); -void show_smtp_info(char *smtp_server,int port,char *domain); +int read_smtp_line(void); +int read_smtp_multi_lines(void); +int show_smtp_info(char *smtp_server,int port,char *domain); int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, char *smtp_server,int smtp_port,char *helo_domain, char *attach_file,char *txt_msg_file,char *the_msg, - int is_mime,char *rrr,char *rt,int add_dateh); + int is_mime,char *rrr,char *rt,int add_dateh,char* return_path_addr); TheMail *newTheMail(void); void errorMsg(char *format,...); void showVerbose(char *format,...); void print_info(char *format,...); +void write_log(char *format,...); +void open_log(const char *log_file); +void close_log(void); +void exit_ok(void); +void exit_error(void); +void log_info(const char *fmt, ...); +void log_debug(const char *fmt, ...); +void log_error(const char *fmt, ...); +void log_fatal(const char *fmt, ...); int addAddressesFromFileToList(char *adress_list_file); int validateMusts(char *from,char *to,char *smtp_server, char *helo_domain); char *askFor(char *buf,int buflen,char *label,int loop); int isInConsole(int fd); +int add_one_line_to_list(char *line); +int add_msg_body_files_to_list(char *file_path); +int add_embed_image_to_attachment_list(const char *image_file); +int add_customer_header_to_list(char *line); int add_attachment_to_list(char *file_path_mime); +int add_oneline_to_attachment_list(char *one_line_msg); +int add_msg_body_to_attachment_list(const char *msg_body_file); int add_server_cap_to_list(char *capability); -Sll *get_attachment_list(); -Sll *get_server_caps_list(); -void print_attachemtn_list(); +Sll *get_one_line_list(void); +Sll *get_custom_header_list(void); +Sll *get_attachment_list(void); +Sll *get_oneline_attachment_list(void); +Sll *get_msg_body_attachment_list(void); +Sll *get_embed_image_attachment_list(void); +Sll *get_server_caps_list(void); +Sll *get_msg_body_files_list(void); +void print_attachment_list(void); +void print_oneline_attachment_list(void); char *fix_to(char *to); int isInteractive(void); int get_filepath_mimetype(char *str,char *filename,int fn_size, @@ -219,8 +314,25 @@ int do_tls(int sfd); void initialize_openssl(char *cipher); char *encode_cram_md5(char *challenge,char *user,char *pass); int guess_file_type(char *path,unsigned int *flag); +void generate_encrypted_password(const char *plaintext); +void print_copyright(void); +int get_encoding_type(const char *type); +int get_content_disposition(const char *disposition); +Attachment *allocate_attachment(void); +int write_to_socket(char *str); +int print_content_type_header(const char *boundary); +int send_attachment(Attachment *a, const char *boundary); +int process_attachments(const char *boundary); +int process_oneline_messages(const char *boundary); +int process_embeded_images(const char *boundary); +int encode2base64andwrite2socket(const char *str); +int include_msg_body(void); +int include_image(void); +void show_examples(void); +char *get_mime_type(char *path); #ifdef HAVE_OPENSSL void print_cert_info(SSL *ssl); +void show_mime_types(void); #endif /* HAVE_OPENSSL */ #endif /* ! MAIL_SEND_H */ diff --git a/mermsemr/src/mailsend/main.c b/mermsemr/src/mailsend/main.c old mode 100644 new mode 100755 index c0c97cb..d275e6a --- a/mermsemr/src/mailsend/main.c +++ b/mermsemr/src/mailsend/main.c @@ -15,9 +15,7 @@ #define __MAIN__ 1 #include "mailsend.h" -//#include "../cgi.h" -//extern C_Cfg *cfg; /* exits after writing the usage */ static void usage(void) @@ -28,120 +26,172 @@ static void usage(void) static char *options[]= { -" -smtp hostname/IP* - of the SMTP server", -" -port SMTP port - SMTP port", -" -d domain - domain name for SMTP HELO/EHLO", -" -t to,to..* - email address/es of the reciepient/s", -" -cc cc,cc.. - Carbon copy address/es", -" +cc - don't ask for Carbon Copy", -" -bc bcc,bcc.. - Blind carbon copy address/es", -" +bc - don't ask for Blind carbon copy", -" +D - don't add Date header", -" -f address* - email address of the sender", -" -sub subject - subject", -" -l file - a file containing the email addresses", -" -attach file,mime_type,[i/a] (i=inline,a=attachment)", -" - attach this file as attachment or inline", -" -cs character set - for text/plain attachments (default is us-ascii)", -" -M \"one line msg\" - attach this one line text message", -" -name \"Full Name\" - add name in the From header", -" -v - verbose mode", -" -V - show version info", -" -w - wait for a CR after sending the mail", -" -rt email_address - add Reply-To header", -" -rrr email_address - request read receipts to this address", -" -starttls - Check for STARTTLS and if server supports, do it", -" -auth - Try CRAM-MD5,LOGIN,PLAIN in that order", -" -auth-cram-md5 - use AUTH CRAM-MD5 authentication", -" -auth-plain - use AUTH PLAIN authentication", -" -auth-login - use AUTH LOGIN authentication", -" -user username - username for ESMTP authentication", -" -pass password - password for ESMTP authentication", -" -example - show examples", -" -ehlo - force EHLO", -" -info - show SMTP server information", -" -help - shows this help", -" -q - quiet", +" -copyright - show copyright information", +" -4 - Force to use IPv4 address of SMTP server", +" -6 - Force to use IPv6 address of SMTP server", +" -smtp hostname/IP* - Hostname/IP address of the SMTP server", +" -port SMTP port - SMTP port", +" -domain domain - domain name for SMTP HELO/EHLO", +" -t to,to..* - email address/es of the recipient/s", +" -cc cc,cc.. - carbon copy address/es", +" +cc - do not ask for Carbon Copy", +" -ct seconds - Connect timeout. Default is 5 seconds", +#if defined(SO_RCVTIMEO) +" -read-timeout seconds - Read timeout. Default is 5 seconds", +#endif /* SO_RCVTIMEO */ +" -bc bcc,bcc.. - blind carbon copy address/es", +" +bc - do not ask for Blind carbon copy", +" +D - do not add Date header", +" -f address* - email address of the sender", +" -sub subject - subject", +" -list_address file - a file containing a list of email addresses", +" -log file - write log messages to this file", +" -cs character set - for text/plain attachments (default is us-ascii)", +" -separator character - separator used with -attach. Default is comma (,)", +" If used must be specified before -attach", +" -enc-type type - encoding type. base64, 8bit, 7bit etc.", +" Default is base64. Special type is \"none\"", +" -aname name - name of the attachment. Default is filename", +" -content-id id - content-id in the attachment", +" -mime-type type - MIME type", +" -dispostion val - \"attachment\" or \"inline\". Default is \"attachment\"", +" -attach file,mime_type,[i/a] (i=inline,a=attachment)", +" - attach this file as attachment or inline", +" -show-attach - show attachment in verbose mode, default is no", +" -show-mime-types - show the compiled in MIME types", +" -M \"one line msg\" - attach this one line text message", +" -content-type type - Content type. Default: multipart/mixed", +" -msg-body path - Path of the file to include as body of mail", +" -embed-image image - Path of image to embed in HTML", +" -H \"header\" - Add custom Header", +" -name \"Full Name\" - add name in the From header", +" -v - verbose mode", +" -V - show version info", +" -w - wait for a CR after sending the mail", +" -rt email_address - add Reply-To header", +" -rrr email_address - request read receipts to this address", +" -rp - return-path address", +" -ssl - SMTP over SSL", +" -starttls - use STARTTLS if the server supports it", +" -auth - try CRAM-MD5,LOGIN,PLAIN in that order", +" -auth-cram-md5 - use AUTH CRAM-MD5 authentication", +" -auth-plain - use AUTH PLAIN authentication", +" -auth-login - use AUTH LOGIN authentication", +" -user username - username for ESMTP authentication", +" -pass password - password for ESMTP authentication", +" -example - show examples", +" -ehlo - force EHLO", +" -info - show SMTP server information", +" -help - shows this help", +" -q - quiet", (char *) NULL }; (void) printf("\n"); - (void) printf("Version: %.1024s\n\n",MAILSEND_VERSION); - (void) printf("Copyright: %.1024s\n\n",NO_SPAM_STATEMENT); + (void) printf(" Version: %.1024s\n\n",MAILSEND_VERSION); + (void) printf(" Copyright: %.1024s\n\n",NO_SPAM_STATEMENT); #ifdef HAVE_OPENSSL - (void) fprintf(stdout,"(Compiled with %s)\n", + (void) fprintf(stdout," (Compiled with OpenSSL version: %s)\n", SSLeay_version(SSLEAY_VERSION)); #else - (void) fprintf(stdout,"(Not compiled with OpenSSL)\n"); + (void) fprintf(stdout," (Not compiled with OpenSSL)\n"); #endif /* HAVE_OPENSSL */ - (void) printf("usage: mailsend [options]\n"); - (void) printf("Where the options are:\n"); + (void) printf(" usage: mailsend [options]\n"); + (void) printf(" Where the options are:\n"); for (p=options; *p != NULL; p++) (void) printf("%s\n",*p); - (void) fprintf(stdout,"\nThe options with * must the specified\n"); - - exit(0); + (void) fprintf(stdout,"\n The options with * must be specified\n"); + (void) fprintf(stdout, +" Environment variables:\n" +" SMTP_USER_PASS for plain text password (-pass)\n"); } -static void show_examples(void) +#if 0 +static void show_examplesX(void) { - (void) fprintf(stdout,"Example (Note: type without newline):\n"); -(void) fprintf(stderr, -"Show server info:\n" -" mailsend -info -smtp smtp.gmail.com\n\n"); + (void) fprintf(stdout," Example (Note: type without newline):\n"); +(void) fprintf(stdout, +" Show server info\n" +" ================\n" +" mailsend -v -info -port 587 -smtp smtp.gmail.com\n" +" mailsend -v -info -ssl -port 465 -smtp smtp.gmail.com\n" +" mailsend -v -info -smtp smtp.example.com -ct 2\n\n"); +(void) fprintf(stdout, +" STARTTLS + AUTHENTICATION\n" +" =========================\n"); +(void) fprintf(stdout, +" mailsend -to user@gmail.com -from user@gmail.com\n" +" -starttls -port 587 -auth\n" +" -smtp smtp.gmail.com\n" +" -sub test +cc +bc -v\n" +" -user you -pass \"your_password\"\n"); +(void) fprintf(stdout, +" Note: Password can be set by env var SMTP_USER_PASS instead of -pass\n\n"); + +(void) fprintf(stdout, +" SSL + AUTHENTICATION\n" +" ====================\n"); +(void) fprintf(stdout, +" mailsend -to user@gmail.com -from user@gmail.com\n" +" -ssl -port 465 -auth\n" +" -smtp smtp.gmail.com\n" +" -sub test +cc +bc -v\n" +" -user you -pass \"your_password\"\n\n"); +(void) fprintf(stdout, +" As -auth is specified, CRAM-MD5, LOGIN, PLAIN will be tried in that order.\n" +" Use -auth-cram-md5, -auth-plan, -auth-login for specific auth mechanism.\n\n" +" Note: Password can be set by env var SMTP_USER_PASS instead of -pass\n\n"); + +(void) fprintf(stdout, +" Attachments\n" +" ===========\n"); +(void) fprintf(stdout, +" mailsend -f user@example.com -smtp 10.100.30.1\n" +" -t user@example.com -sub test -attach \"file.txt,text/plain\"\n" +" -attach \"/usr/file.gif,image/gif\" -attach \"file.jpeg,image/jpg\"\n\n"); + +(void) fprintf(stdout, +" The name of the attachment will be file.gif and file.jpeg.\n" +" If you want the name to be different, add the fourth argument with -attach.\n" +" Note: you MUST have to give the attachment type in this case\n\n"); + +(void) fprintf(stdout, +" mailsend -f user@example.com -smtp 10.100.30.1\n" +" -t user@example.com -sub test -attach \"file.txt,text/plain\"\n" +" -attach \"/usr/file.gif,image/gif,a,bar.gif\" -attach \"file.jpeg,image/jpg\"\n\n"); + + +(void) fprintf(stdout, +" mailsend -f user@example.com -smtp 192.168.0.2\n" +" -t user@example.com -sub test +cc +bc\n" +" -attach \"c:\\file.gif,image/gif\" -M \"Sending a GIF file\"\n\n"); + +(void) fprintf(stdout, +" mailsend -f user@example.com -smtp 192.168.0.2\n" +" -t user@example.com -sub test +cc +bc -cs \"ISO-8859-1\"\n" +" -attach \"file2.txt,text/plain\"\n\n"); + +(void) fprintf(stdout, +" Inline Attachment\n" +" =================\n"); (void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp 10.100.30.1\n" -" -t muquit@muquit.com -sub test -a \"file.txt,text/plain\"\n" -" -a \"/usr/file.gif,image/gif\" -a \"file.jpeg,image/jpg\"\n\n"); - -(void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp 192.168.0.2\n" -" -t muquit@muquit.com -sub test +cc +bc\n" -" -a \"c:\\file.gif,image/gif\" -M \"Sending a GIF file\"\n\n"); - -(void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp 192.168.0.2\n" -" -t muquit@muquit.com -sub test +cc +bc -cs \"ISO-8859-1\"\n" -" -a \"file2.txt,text/plain\"\n\n"); - - (void) fprintf(stdout,"Change content disposition to inline:\n"); - (void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp 10.100.30.1\n" -" -t muquit@muquit.com -sub test -a \"nf.jpg,image/jpeg,i\"\n" -" -M \"content disposition is inline\"\n\n"); - - (void) fprintf(stdout,"STARTTLS+AUTH PLAIN:\n"); -(void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp smtp.gmail.com\n" -" -sub test -from muquit@muquit.com +cc +bc -v -starttls -auth-plain\n" -" -user you -pass 'secert'\n\n"); - -(void) fprintf(stdout,"STARTTLS+AUTH CRAM-MD5:\n"); -(void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp 1.2.3.4\n" -" -sub test -from muquit@muquit.com +cc +bc -v -starttls -auth-cram-md5\n" -" -user you -pass 'secert'\n\n"); - -(void) fprintf(stdout,"STARTTLS+AUTH LOGIN:\n"); -(void) fprintf(stdout, -" mailsend -f muquit@example.com -d example.com -smtp 1.2.3.4\n" -" -sub test -from muquit@muquit.com +cc +bc -v -starttls -auth-login\n" -" -user you -pass 'secert'\n"); -(void) fprintf(stdout, -"(Password can be set by env var SMTP_USER_PASS instead of -pass)\n\n"); -(void) fprintf(stdout, -"Note: I suggest you always use STARTTLS if your server supports it\n"); - +" mailsend -f user@example.com -d example.com -smtp 10.100.30.1\n" +" -t user@example.com -sub test -attach \"nf.jpg,image/jpeg,i\"\n" +" -M \"body line1: content disposition is inline\"\n" +" -M \"body line2: this is line2 of the body\"\n\n"); } +#endif /* if 0 */ int main(int argc,char **argv) { char *x, + *y, buf[BUFSIZ], + encrypted_pass[128], /* 80 bytes actually */ *cipher=NULL, *option; @@ -150,9 +200,9 @@ int main(int argc,char **argv) is_mime=0, add_dateh=1, port=(-1), - rc, - no_cc=0, - no_bcc=0, + rc = (-1), + no_cc=1, + no_bcc=1, i; char @@ -160,8 +210,9 @@ int main(int argc,char **argv) *helo_domain=NULL, *smtp_server=NULL, *attach_file=NULL, - *msg_body_file=NULL, + *msg_body_file=NULL, /* back in 1.17b15 */ *the_msg=NULL, + *custom_header=NULL, *to=NULL, *save_to=NULL, *save_cc=NULL, @@ -171,9 +222,12 @@ int main(int argc,char **argv) *cc=NULL, *bcc=NULL, *rt=NULL, - *rrr=NULL; + *rrr=NULL, + *return_path_addr=NULL; g_verbose=0; + g_connect_timeout = DEFAULT_CONNECT_TIMEOUT; /* 5 secs */ + g_read_timeout = DEFAULT_READ_TIMEOUT; /* 5 secs */ g_quiet=0; g_wait_for_cr=0; g_do_auth=0; @@ -181,22 +235,46 @@ int main(int argc,char **argv) g_auth_plain=0; g_auth_cram_md5=0; g_auth_login=0; + g_do_ssl=0; g_do_starttls=0; + g_log_fp = NULL; + g_show_attachment_in_log = 0; + g_use_protocol = MSOCK_USE_AUTO; /* detect IPv4 or IPv6 */ + g_force = MUTILS_FALSE; + + memset(g_log_file,0,sizeof(g_log_file)); memset(g_username,0,sizeof(g_username)); memset(g_userpass,0,sizeof(g_userpass)); + memset(encrypted_pass, 0, sizeof(encrypted_pass)); memset(g_from_name,0,sizeof(g_from_name)); + memset(g_content_type,0,sizeof(g_content_type)); + memset(g_attach_sep, 0, sizeof(g_attach_sep)); + memset(g_attach_name, 0, sizeof(g_attach_name)); + memset(g_content_transfer_encoding, 0, sizeof(g_content_transfer_encoding)); + memset(g_mime_type, 0, sizeof(g_mime_type)); + memset(g_content_id, 0, sizeof(g_content_id)); + + /* (void) strcpy(g_content_transfer_encoding,"base64"); */ /* no default */ + (void) strcpy(g_content_disposition,"attachment"); + (void) strcpy(g_attach_sep,","); + (void) strcpy(g_charset,DEFAULT_CHARSET); + /* + No default for mime_type, we will detect from file extensinon + if no mime type is specified with -mime-type + */ + /* + (void) strcpy(g_mime_type,"text/plain"); + */ - (void) strcpy(g_charset,"us-ascii"); for (i=1; i < argc; i++) { option=argv[i]; switch (*(option+1)) { - case 'a': { - if (strncmp("attach",option+1,2) == 0) + if (strncmp("attach",option+1,6) == 0) { if (*option == '-') { @@ -204,12 +282,27 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing file to attach"); - return (1); + rc = 1; + goto ExitProcessing; } attach_file=argv[i]; add_attachment_to_list(attach_file); } } + else if (strncmp("aname",option+1,5) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing attachment name"); + rc = 1; + goto ExitProcessing; + } + mutilsSafeStrcpy(g_attach_name,argv[i],sizeof(g_attach_name)-1); + } + } else if (strncmp("auth-plain",option+1, strlen("auth-plain"))==0) { @@ -239,17 +332,18 @@ int main(int argc,char **argv) { if (*option == '-') { + g_auth_plain=1; g_auth_login=1; g_auth_cram_md5=1; g_auth_login=1; g_do_auth=1; } } - else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; } @@ -264,7 +358,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing BCc address/es"); - return (1); + rc = 1; + goto ExitProcessing; } bcc=argv[i]; save_bcc=mutilsStrdup(bcc); @@ -281,11 +376,38 @@ int main(int argc,char **argv) else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; } + case '4': + { + if (strncmp("4", option + 1,1) == 0) + { + if (*option == '-') + { + g_use_protocol = MSOCK_USE_IPV4; + } + } + break; + } + + case '6': + { + if (strncmp("6", option + 1,1) == 0) + { + if (*option == '-') + { + g_use_protocol = MSOCK_USE_IPV6; + } + } + + break; + } + + case 'c': { @@ -297,7 +419,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing Cc address/es"); - return (1); + rc = 1; + goto ExitProcessing; } cc=argv[i]; save_cc=mutilsStrdup(cc); @@ -319,16 +442,92 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing character set"); - return (1); + rc = 1; + goto ExitProcessing; } mutilsSafeStrcpy(g_charset,argv[i],sizeof(g_charset)-1); } } + else if (strncmp("ct", option + 1, 2) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing connect timeout with -ct"); + rc = 1; + goto ExitProcessing; + } + g_connect_timeout = atoi(argv[i]); + } + } + else if (strncmp("content-type", option+1, 12)==0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing content-type value"); + rc = 1; + goto ExitProcessing; + } + mutilsSafeStrcpy(g_content_type,argv[i],sizeof(g_content_type)-1); + } + } + else if (strncmp("content-disposition", option + 1, 12) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing content-dispostion value"); + rc = 1; + goto ExitProcessing; + } + if ((strcmp(argv[i],"inline") == 0) || strcmp(argv[i], "attachment") == 0) + { + mutilsSafeStrcpy(g_content_disposition,argv[i], + sizeof(g_content_disposition)-1); + } + else + { + errorMsg("Invalid value for -content-disposition"); + rc = 1; + goto ExitProcessing; + } + } + } + else if (strncmp("content-id", option + 1, 10) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing content-id value"); + rc = 1; + goto ExitProcessing; + } + + mutilsSafeStrcpy(g_content_id,argv[i],sizeof(g_content_id)-1); + } + + } + else if (strncmp("copyright", option + 1, 5) == 0) + { + print_copyright(); + rc = 0; + goto ExitProcessing; + } else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; } @@ -348,7 +547,7 @@ int main(int argc,char **argv) case 'd': { - if (strncmp("domain",option+1,1) == 0) + if (strncmp("domain",option+1,6) == 0) { if (*option == '-') { @@ -356,28 +555,89 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing domain name"); - return (1); + rc = 1; + goto ExitProcessing; } helo_domain=argv[i]; } } + else if (strncmp("disposition", option + 1, 6) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing content dispostion value"); + rc = 1; + goto ExitProcessing; + } + if ((strcmp(argv[i],"inline") == 0) || strcmp(argv[i], "attachment") == 0) + { + mutilsSafeStrcpy(g_content_disposition,argv[i],sizeof(g_content_disposition)-1); + } + else + { + errorMsg("Invalid value for -disposition"); + rc = 1; + goto ExitProcessing; + } + } + } + break; } case 'e': { - if (*option == '-') + if (strncmp("example",option+1,2) == 0) { - if (strncmp("example",option+1,3) == 0) + if (*option == '-') { show_examples(); - return(1); + rc = 1; + goto ExitProcessing; } - if (strncmp("ehlo",option+1,4) == 0) + } + else if (strncmp("ehlo",option+1,4) == 0) + { + if (*option == '-') { g_esmtp=1; } } + else if (strncmp("enc-type",option+1,5) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing encoding type"); + rc = 1; + goto ExitProcessing; + } + mutilsSafeStrcpy(g_content_transfer_encoding, + argv[i], + sizeof(g_content_transfer_encoding)-1); + } + } + else if (strncmp("embed-image", option + 1, 7) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing image for -embded-image"); + rc = 1; + goto ExitProcessing; + } + add_embed_image_to_attachment_list(argv[i]); + /* TODO */ + } + + } break; } @@ -391,7 +651,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing From address/es"); - return (1); + rc = 1; + goto ExitProcessing; } from=argv[i]; } @@ -399,11 +660,25 @@ int main(int argc,char **argv) break; } + case 'x': + { + if (strncmp("xforce",option+1,1) == 0) + { + if (*option == '-') + { + g_force = MUTILS_TRUE; + } + } + break; + } + case 'h': { if (strncmp("help",option+1,1) == 0) { usage(); + rc = 0; + goto ExitProcessing; } /* won't be here */ break; @@ -420,23 +695,51 @@ int main(int argc,char **argv) case 'l': { - if (strncmp("list_address",option+1,1) == 0) + if (strncmp("list_address",option+1,3) == 0) { if (*option == '-') { i++; if (i == argc) { - errorMsg("Missing address list file"); - return (1); + errorMsg("Missing address list file"); + rc = 1; + goto ExitProcessing; } address_file=argv[i]; } } + + if (strncmp("log",option+1,3) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing address log file"); + rc = 1; + goto ExitProcessing; + } + g_log_fp = fopen(argv[i], "a"); + if (g_log_fp == NULL) + { + errorMsg("Could not open log file %s for writing (%s)", + argv[i], + strerror(errno)); + rc = 1; + goto ExitProcessing; + } + /* + ** tell msock lib to write error message to log file + */ + msock_set_logfp(g_log_fp); + mutilsSafeStrcpy(g_log_file,argv[i],sizeof(g_log_file)-1); + } + } break; } - case 'p': { if (strncmp("port",option+1,2) == 0) @@ -447,7 +750,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing SMTP Port with -port"); - return (1); + rc = 1; + goto ExitProcessing; } port=atoi(argv[i]); } @@ -460,7 +764,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing password with -pass"); - return (1); + rc = 1; + goto ExitProcessing; } (void) snprintf(g_userpass,sizeof(g_userpass)-1, "%s",argv[i]); @@ -470,36 +775,39 @@ int main(int argc,char **argv) else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; } - /* -gone- - case 'm': + case 'H': { - if (strncmp("msgbody",option+1,1) == 0) + if (strncmp("Header",option+1,1) == 0) { if (*option == '-') { i++; if (i == argc) { - errorMsg("Missing message body file"); - return (1); + errorMsg("Missing custom header"); + rc = 1; + goto ExitProcessing; } - msg_body_file=argv[i]; + custom_header=argv[i]; + add_customer_header_to_list(custom_header); } } else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; } - */ + case 'M': { @@ -511,20 +819,63 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing text message"); - return (1); + rc = 1; + goto ExitProcessing; } - the_msg=argv[i]; + the_msg=xStrdup(argv[i]); + add_oneline_to_attachment_list(the_msg); } } else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; } + case 'm': + { + if (strncmp("mime-type",option+1,9) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing mime type"); + rc = 1; + goto ExitProcessing; + } + mutilsSafeStrcpy(g_mime_type,argv[i],sizeof(g_mime_type)-1); + } + } + else if (strncmp("msg-body",option+1,5) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing path of message body file"); + rc = 1; + goto ExitProcessing; + } + msg_body_file = argv[i]; + add_msg_body_to_attachment_list(argv[i]); + } + } + else + { + errorMsg("Unknown flag: %s\n",option); + rc = 1; + goto ExitProcessing; + } + break; + } + case 'n': { if (strncmp("name",option+1,3) == 0) @@ -535,7 +886,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing Name with -n"); - return (1); + rc = 1; + goto ExitProcessing; } (void) snprintf(g_from_name,sizeof(g_from_name)-1, "%s",argv[i]); @@ -544,7 +896,8 @@ int main(int argc,char **argv) else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; @@ -560,7 +913,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing smtp server"); - return (1); + rc = 1; + goto ExitProcessing; } smtp_server=argv[i]; } @@ -573,25 +927,70 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing subject with -sub"); - return (1); + rc = 1; + goto ExitProcessing; } sub=argv[i]; } } + else if (strncmp("ssl", option + 1, 3) == 0) + { +#ifdef HAVE_OPENSSL + g_do_ssl=1; +#else + (void) fprintf(stderr,"Error: '-ssl' not available, not compiled with OpenSSL\n"); + rc = 1; + goto ExitProcessing; +#endif /* HAVE_OPENSSL */ + + } else if (strncmp("starttls",option+1,3) == 0) { #ifdef HAVE_OPENSSL g_do_starttls=1; #else - (void) fprintf(stderr,"Warning: '-starttls' not available, only avaible if compiled with OpenSSL\n"); - + (void) fprintf(stderr,"Error: '-starttls' not available, not compiled with OpenSSL\n"); + rc = 1; + goto ExitProcessing; + #endif /* HAVE_OPENSSL */ } + else if (strncmp("show-attach", option + 1, 9) == 0) + { + g_show_attachment_in_log = 1; + } + else if (strncmp("show-mime-types",option+1,9) == 0) + { + show_mime_types(); + rc = 0; + goto ExitProcessing; + } + else if (strncmp("separator", option + 1, 4) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + errorMsg("Missing separator"); + rc = 1; + goto ExitProcessing; + } + (void) snprintf(g_attach_sep,sizeof(g_attach_sep)-1,"%s",argv[i]); + if (strlen(g_attach_sep) != 1) + { + errorMsg("Invalid separator character specified"); + rc = 1; + goto ExitProcessing; + } + } + } else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; @@ -607,7 +1006,8 @@ int main(int argc,char **argv) if (i == argc) { errorMsg("Missing smtp server"); - return (1); + rc = 1; + goto ExitProcessing; } (void) snprintf(g_username,sizeof(g_username)-1, "%s",argv[i]); @@ -616,7 +1016,8 @@ int main(int argc,char **argv) else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; @@ -631,6 +1032,7 @@ int main(int argc,char **argv) if (*option == '-') { g_verbose=1; + msock_set_debug(g_verbose); } } break; @@ -647,18 +1049,19 @@ int main(int argc,char **argv) } break; } - + case 'V': { (void) fprintf(stderr,"mailsend Version: %.1024s\n",MAILSEND_VERSION); #ifdef HAVE_OPENSSL - (void) fprintf(stderr,"Compiled with %s\n", + (void) fprintf(stderr,"Compiled with OpenSSL: %s\n", SSLeay_version(SSLEAY_VERSION)); #else (void) fprintf(stderr,"Not Compiled OpenSSL, some auth methods will be unavailable\n"); #endif /* ! HAVE_OPENSSL */ - exit(0); + rc = 0; + goto ExitProcessing; break; } @@ -672,14 +1075,16 @@ int main(int argc,char **argv) if (i == argc) { (void) fprintf(stderr,"Error: missing to addresses\n"); - return (1); + rc = 1; + goto ExitProcessing; } to=argv[i]; save_to=mutilsStrdup(to); if (save_to == NULL) { errorMsg("memory allocation problem for -to"); - return(-1); + rc = 1; + goto ExitProcessing; } save_to=fix_to(save_to); to=fix_to(to); @@ -704,13 +1109,15 @@ int main(int argc,char **argv) if (i == argc) { (void) fprintf(stderr,"Error: missing to addresses for -rrr\n"); - return (1); + rc = 1; + goto ExitProcessing; } rrr=mutilsStrdup(argv[i]); if (rrr == NULL) { errorMsg("memory allocation problem for -rrr"); - return(1); + rc = 1; + goto ExitProcessing; } } } @@ -722,20 +1129,51 @@ int main(int argc,char **argv) if (i == argc) { (void) fprintf(stderr,"Error: missing to addresses for -rt\n"); - return (1); + rc = 1; + goto ExitProcessing; } rt=mutilsStrdup(argv[i]); if (rt == NULL) { errorMsg("memory allocation problem for -rt"); - return(1); + rc = 1; + goto ExitProcessing; } } } + else if (strncmp("rp",option+1,2) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + (void) fprintf(stderr,"Error: missing return-path address for -rp\n"); + rc = 1; + goto ExitProcessing; + } + return_path_addr=argv[i]; + } + } + else if (strncmp("read-timeout",option+1,12) == 0) + { + if (*option == '-') + { + i++; + if (i == argc) + { + (void) fprintf(stderr,"Error: missing to addresses for -read_timeout\n"); + rc = 1; + goto ExitProcessing; + } + g_read_timeout = atoi(argv[i]); + } + } else { errorMsg("Unknown flag: %s\n",option); - return(1); + rc = 1; + goto ExitProcessing; } break; @@ -758,13 +1196,39 @@ int main(int argc,char **argv) { (void) fprintf(stderr,"Error: Unrecognized option: %s\n", option); - return (1); + rc = 1; + goto ExitProcessing; } } } + x=getenv("SMTP_USER_PASS"); + y=NULL; + if (x && y) + { + (void) fprintf(stderr,"SMTP_USER_PASS and SMTP_USER_PASS_ENC can not be set. Exiting..\n"); + rc = 1; + goto ExitProcessing; + } + if (x) + { + if (*g_userpass == '\0') + { + (void) snprintf(g_userpass,sizeof(g_userpass)-1,"%s",x); + } + } + +#ifdef HAVE_OPENSSL + if (g_do_ssl && g_do_starttls) + { + (void) fprintf(stderr,"Options -ssl and -starttls are mutually exclusive\n"); + rc = 1; + goto ExitProcessing; + } +#endif /* HAVE_OPENSSL */ + initialize_openssl(cipher); if (port == -1) @@ -778,15 +1242,20 @@ int main(int argc,char **argv) { if (helo_domain == NULL) helo_domain="localhost"; - show_smtp_info(smtp_server,port,helo_domain); - return(1); + rc = show_smtp_info(smtp_server,port,helo_domain); + if (rc < 0) + rc = 1; + goto ExitProcessing; } - print_attachemtn_list(); + /* + print_attachment_list(); + print_oneline_attachment_list(); + */ /* - ** attaching a file or a one line message will make the mail a + ** attaching a file or a one line message will make the mail a ** MIME mail */ if (attach_file || the_msg || msg_body_file) @@ -822,15 +1291,6 @@ int main(int argc,char **argv) from=xStrdup(x); } - x=getenv("SMTP_USER_PASS"); - if (x) - { - if (*g_userpass == '\0') - { - (void) snprintf(g_userpass,sizeof(g_userpass)-1,"%s",x); - } - } - /* if address file specified, add the addresses to the list as well */ if (address_file != NULL) { @@ -840,10 +1300,10 @@ int main(int argc,char **argv) /* ** The To address must be speicifed, even if the file with the list of - ** addresses is specified. The specified To will be shown in the + ** addresses is specified. The specified To will be shown in the ** envelope. None of the To, Cc and Bcc from the address list file will ** be shown anywhre.. that's how I like it. I hate long To, Cc or Bcc. - ** muquit@muquit.com, Thu Mar 29 11:56:45 EST 2001 + ** muquit@muquit.com, Thu Mar 29 11:56:45 EST 2001 */ if (save_to == NULL) @@ -864,7 +1324,7 @@ int main(int argc,char **argv) /* ** if msg file specified, dont ask for unneeded things, as it could ** be used from other programs, and it will wait for input - ** muquit@muquit.com Tue Apr 10 18:02:12 EST 2001 + ** muquit@muquit.com Tue Apr 10 18:02:12 EST 2001 */ #ifdef WINNT @@ -902,28 +1362,70 @@ int main(int argc,char **argv) if (x) sub=xStrdup(x); } + + if (g_do_ssl || g_do_starttls) + { + if (*g_username == '\0') + { + memset(buf,0,sizeof(buf)); + x=askFor(buf,sizeof(buf)-1,"Auth user: ",EMPTY_NOT_OK); + if (x) + { + (void) snprintf(g_username,sizeof(g_username)-1,"%s",x); + } + } + + if (*g_userpass == '\0') + { + (void) fprintf(stderr,"\nPlease specify auth password with -pass\n"); + (void) fprintf(stderr,"Or by environment variable SMTP_USER_PASS\n"); + rc = 1; + goto ExitProcessing; + } + } } - - - /* TODO: read from default file or registry */ rc=validateMusts(from,save_to,smtp_server,helo_domain); - if (rc == -1) - return (1); /* exit */ + if (rc != 0) + { + rc = 1; + goto ExitProcessing; + } #ifdef UNIX signal(SIGPIPE,SIG_IGN); #endif /* UNIX */ +#if 0 + { + MutilsTime + mt; + char + timebuf[64]; + mutils_time_now(&mt); + mutils_time_fmt(&mt, timebuf, sizeof(timebuf)); + (void) fprintf(stderr,"timebuf: %s\n",timebuf); + return 1; + } +#endif /* 0 */ + + write_log("mailsend v%s\n",MAILSEND_VERSION); rc=send_the_mail(from,save_to,save_cc,save_bcc,sub,smtp_server,port, - helo_domain,attach_file,msg_body_file,the_msg,is_mime,rrr,rt,add_dateh); + helo_domain,attach_file,msg_body_file,the_msg,is_mime,rrr,rt,add_dateh,return_path_addr); if (rc == 0) { if (isInteractive()) { - (void) printf("Mail sent successfully\n"); - (void) fflush(stdout); + if (!g_quiet) + { + (void) printf("Mail sent successfully\n"); + (void) fflush(stdout); + } + } + if (!g_quiet) + { + write_log("Mail sent successfully\n"); } } else @@ -932,6 +1434,7 @@ int main(int argc,char **argv) { (void) printf("Could not send mail\n"); } + write_log("Could not send mail\n"); } if (isInteractive()) @@ -939,10 +1442,16 @@ int main(int argc,char **argv) if (g_wait_for_cr) { printf("\nPress Enter to Exit: "); - fgets(buf,sizeof(buf)-1,stdin); + x=fgets(buf,sizeof(buf)-1,stdin); } } + if (rc != 0) + { + rc = 1; + } +ExitProcessing: + close_log(); return (rc); } diff --git a/mermsemr/src/mailsend/setget.c b/mermsemr/src/mailsend/setget.c old mode 100644 new mode 100755 index 8fc92a8..15fdb1c --- a/mermsemr/src/mailsend/setget.c +++ b/mermsemr/src/mailsend/setget.c @@ -13,7 +13,12 @@ #include "mailsend.h" static Sll + *one_line_head = NULL, + *custom_headers_head = NULL, *attachment_head=NULL, + *oneline_attachment_head = NULL, + *msg_body_attachment_head = NULL, + *embed_image_attachment_head = NULL, *server_caps=NULL, *addr_head=NULL; @@ -31,9 +36,21 @@ void print_server_caps(void) } } +void print_one_lines(void) +{ + Sll + *l; + for (l = one_line_head; l; l = l->next) + { + (void) fprintf(stdout,"LINE: '%s'\n",(char *) l->data); + (void) fflush(stdout); + } +} + void printAddressList2(Sll *list) { +/* Sll *l; @@ -44,9 +61,37 @@ void printAddressList2(Sll *list) { addr=(Address *) l->data; } +*/ } -void print_attachemtn_list() +void print_oneline_attachment_list(void) +{ + Sll + *l; + + Attachment + *a; + + if (!g_verbose) + { + return; + } + for (l=oneline_attachment_head; l; l=l->next) + { + a=(Attachment *) l->data; + (void) fprintf(stderr,"Message: %s\n",a->oneline_msg); + (void) fprintf(stderr,"Mime type: %s\n",a->mime_type); + (void) fprintf(stderr,"Disposition: %s\n",a->content_disposition); + if (a->content_transfer_encoding) + (void) fprintf(stderr,"Encoding type: %s\n",a->content_transfer_encoding); + else + (void) fprintf(stderr,"Encoding type: none\n"); + (void) fprintf(stderr,"\n"); + } +} + + +void print_attachment_list(void) { Sll *l; @@ -57,13 +102,19 @@ void print_attachemtn_list() for (l=attachment_head; l; l=l->next) { a=(Attachment *) l->data; - /* (void) fprintf(stderr,"File path: %s\n",a->file_path); (void) fprintf(stderr,"File name: %s\n",a->file_name); + if (a->attachment_name) + (void) fprintf(stderr,"Attachment name: %s\n",a->attachment_name); (void) fprintf(stderr,"Mime type: %s\n",a->mime_type); (void) fprintf(stderr,"Disposition: %s\n",a->content_disposition); + if (a->content_id) + (void) fprintf(stderr,"Content-ID: %s\n",a->content_id); + if (a->content_transfer_encoding) + (void) fprintf(stderr,"Encoding type: %s\n",a->content_transfer_encoding); + else + (void) fprintf(stderr,"Encoding type: none\n"); (void) fprintf(stderr,"\n"); - */ } } @@ -133,6 +184,56 @@ int add_server_cap_to_list(char *cap) return(0); } +/* +** Add each line entered with -H to list of lines +** they represent custom headers in the mail. +** For example X-Priority etc. can be added that way +*/ +int add_customer_header_to_list(char *line) +{ + Sll + *nl = NULL; + + char + *l; + + if (line == NULL || *line == '\0') + { + return (-1); + } + l = strdup(line); + CHECK_MALLOC(l); + nl = allocateNode((void *) l); + CHECK_MALLOC(nl); + appendNode(&custom_headers_head, &nl); + + return(0); +} + +/* +** Add each line entered with -M to a list of lines +** return 0 on success, -1 otherwise +*/ +int add_one_line_to_list(char *line) +{ + Sll + *nl = NULL; + + char + *l; + + if (line == NULL || *line == '\0') + { + return (-1); + } + l = strdup(line); + CHECK_MALLOC(l); + nl = allocateNode((void *) l); + CHECK_MALLOC(nl); + appendNode(&one_line_head, &nl); + + return(0); +} /** @@ -141,6 +242,8 @@ int add_server_cap_to_list(char *cap) int add_attachment_to_list(char *file_path_mime) { int + rc, + separator, ntokens; Sll @@ -150,7 +253,7 @@ int add_attachment_to_list(char *file_path_mime) **tokens=NULL, *file_path=NULL, *file_name=NULL, - *mime_type=NULL, + *mime_type, *content_disposition="attachment"; Attachment @@ -160,13 +263,17 @@ int add_attachment_to_list(char *file_path_mime) return(-1); /* Tokenize the string "file,mime_type,something" */ - tokens=mutilsTokenize(file_path_mime,',',&ntokens); + separator = *g_attach_sep; + showVerbose("Separator: %c\n",separator); + tokens=mutilsTokenize(file_path_mime,separator,&ntokens); if (tokens == NULL) { errorMsg("Could not parse attachment string: \"%s\"",file_path_mime); - exit(1); + exit_error(); } + showVerbose("ntokens: %d\n",ntokens); + /* get the file name out */ file_path=tokens[0]; if ((file_name=strrchr(file_path,'/')) || @@ -179,9 +286,7 @@ int add_attachment_to_list(char *file_path_mime) file_name=file_path; } - a=(Attachment *) malloc(sizeof(Attachment)); - CHECK_MALLOC(a); - + a = allocate_attachment(); a->file_path=xStrdup(file_path); a->file_name=xStrdup(file_name); @@ -190,9 +295,11 @@ int add_attachment_to_list(char *file_path_mime) case 1: /* Only File_path/name given */ { + /* mime_type="application/octet-stream"; a->mime_type=xStrdup(mime_type); a->content_disposition=xStrdup("attachment"); + */ break; } @@ -200,75 +307,228 @@ int add_attachment_to_list(char *file_path_mime) { mime_type=tokens[1]; a->mime_type=xStrdup(mime_type); - a->content_disposition=xStrdup("attachment"); break; } - case 3: + case 3: /* filepath/name, mime_type, disposition given */ + case 4: /* filepath/name, mime_type, disposition, attchment name given */ + case 5: /* content-id */ + case 6: /* encoding type */ { mime_type=tokens[1]; a->mime_type=xStrdup(mime_type); content_disposition=tokens[2]; if (*content_disposition == 'a') + { a->content_disposition=xStrdup("attachment"); + } else if (*content_disposition == 'i') + { a->content_disposition=xStrdup("inline"); + } else + { a->content_disposition=xStrdup("attachment"); + } + + if (ntokens == 4) + { + a->attachment_name = xStrdup(tokens[3]); + } + if (ntokens == 5) + { + a->attachment_name = xStrdup(tokens[3]); + if (strncmp(tokens[4],"none",4) != 0) + a->content_id = xStrdup(tokens[4]); + } + if (ntokens == 6) + { + a->attachment_name = xStrdup(tokens[3]); + if (strncmp(tokens[4],"none",4) != 0) + a->content_id = xStrdup(tokens[4]); + a->content_transfer_encoding = xStrdup(tokens[5]); + } break; } - + default: { errorMsg("Invalid string specified with -a \"%s\"",file_path_mime); - exit(1); + exit_error(); break; } } + + rc = mutils_file_is_binary(a->file_path); + if (rc == -1) + { + errorMsg("Could not determine file type of %s",a->file_path); + } + if (rc == MUTILS_TRUE) + { + mime_type = get_mime_type(a->file_path); + if (*g_mime_type != '\0') + { + if ((mutilsStrcasecmp(g_mime_type,"text/html") == 0) || + (mutilsStrcasecmp(g_mime_type,"text/plain") == 0)) + { + a->charset = xStrdup("none"); + a->mime_type = xStrdup(mime_type); + a->content_transfer_encoding = xStrdup("base64"); + } + } + } + + + if (a->mime_type == NULL) + { + if (*g_mime_type != '\0') + { + a->mime_type = xStrdup(g_mime_type); + } + else + { + a->mime_type = xStrdup(get_mime_type(a->file_path)); + } + } + if (a->content_transfer_encoding == NULL) + { + if (*g_content_transfer_encoding == '\0') + { + a->content_transfer_encoding = xStrdup("base64"); + } + } + + if (a->content_id == NULL) + { + if (*g_content_id != '\0') + { + a->content_id = xStrdup(g_content_id); + } + } + + if (a->attachment_name == NULL) + { + a->attachment_name = xStrdup(file_name); + } + na=allocateNode((void *) a); CHECK_MALLOC(na); appendNode(&attachment_head,&na); - /* - print_attachemtn_list(); - */ -#if 0 - if ((mime_type=strchr(file_path_mime,ATTACHMENT_SEP))) - { - *mime_type++='\0'; - } - else - { - mime_type="application/octet-stream"; - } - - - /* get the file name out */ - if ((file_name=strrchr(file_path_mime,'/')) || (file_name=strrchr(file_path_mime,'\\'))) - { - file_name++; - } - else - { - file_name=file_path_mime; - } - - a=(Attachment *) malloc(sizeof(Attachment)); - CHECK_MALLOC(a); - - a->file_path=xStrdup(file_path_mime); - a->file_name=xStrdup(file_name); - a->mime_type=xStrdup(mime_type); - na=allocateNode((void *) a); - CHECK_MALLOC(na); - - appendNode(&attachment_head,&na); -#endif /* 0 */ - + /*print_attachemtn_list();*/ return(0); } +int add_embed_image_to_attachment_list(const char *image_file) +{ + Sll + *na=NULL; + + Attachment + *a=NULL; + + if (image_file == NULL || *image_file == '\0') + { + return(-1); + } + a=allocate_attachment(); /* defaults will be set */ + + a->file_path = xStrdup(image_file); + if (a->charset) + { + (void) free((char *) a->charset); + a->charset = xStrdup("none"); + } + + if (a->mime_type == NULL) + { + if (*g_mime_type != '\0') + { + a->mime_type = xStrdup(g_mime_type); + } + else + { + a->mime_type = xStrdup(get_mime_type(a->file_path)); + } + } + + if (a->content_transfer_encoding == NULL) + { + if (*g_content_transfer_encoding == '\0') + { + a->content_transfer_encoding = xStrdup("base64"); + } + } + + + na=allocateNode((void *) a); + CHECK_MALLOC(na); + appendNode(&embed_image_attachment_head,&na); + return(0); + +} + +int add_msg_body_to_attachment_list(const char *msg_body_file) +{ + Sll + *na=NULL; + + Attachment + *a=NULL; + + if (msg_body_file == NULL || *msg_body_file == '\0') + { + return(-1); + } + a=allocate_attachment(); /* defaults will be set */ + + a->file_path = xStrdup(msg_body_file); + + na=allocateNode((void *) a); + CHECK_MALLOC(na); + appendNode(&msg_body_attachment_head,&na); + return(0); +} + + +/* +** create a list of Attachment for one line messages +** it uses -mime-type and -enc-type, so these two flags +** must specified first before -M +*/ +int add_oneline_to_attachment_list(char *oneline_msg) +{ + Sll + *na=NULL; + + Attachment + *a=NULL; + + if (oneline_msg == NULL || *oneline_msg == '\0') + { + return(-1); + } + a=allocate_attachment(); /* defaults will be set */ + + a->oneline_msg=xStrdup(oneline_msg); + a->content_disposition=xStrdup("inline"); + if (*g_mime_type == '\0') + { + a->mime_type = xStrdup("text/plain"); + } + + if (a->content_transfer_encoding == NULL) + { + a->content_transfer_encoding = xStrdup("none"); + } + na=allocateNode((void *) a); + CHECK_MALLOC(na); + + appendNode(&oneline_attachment_head,&na); + return(0); +} @@ -421,7 +681,7 @@ int addAddressesFromFileToList(char *address_file) if (addr == NULL) { errorMsg("addAddressToList: malloc problem for newAddress()"); - return (-1); + goto ExitProcessing; } /* fill with data */ showVerbose("Label: %s\n",label); @@ -434,7 +694,7 @@ int addAddressesFromFileToList(char *address_file) { errorMsg("addAddressToList: malloc problem with allocateNode()"); (void) free ((char *) addr); - return (-1); + goto ExitProcessing; } appendNode(&addr_head,&list); } @@ -443,6 +703,10 @@ int addAddressesFromFileToList(char *address_file) (void) fclose(fp); return (0); +ExitProcessing: + if (fp != (FILE *) NULL) + (void) fclose(fp); + return (-1); } @@ -451,15 +715,66 @@ Sll *getAddressList(void) return (addr_head); } +Sll *get_one_line_list(void) +{ + return (one_line_head); +} + +Sll *get_custom_header_list(void) +{ + return (custom_headers_head); +} + Sll *get_attachment_list(void) { return(attachment_head); } +Sll *get_oneline_attachment_list(void) +{ + return(oneline_attachment_head); +} Sll *get_server_cap_list(void) { return(server_caps); } +Sll *get_msg_body_attachment_list(void) +{ + return(msg_body_attachment_head); +} + +Sll *get_embed_image_attachment_list(void) +{ + return (embed_image_attachment_head); +} + +Attachment *allocate_attachment(void) +{ + Attachment + *a; + a = (Attachment *) malloc(sizeof(Attachment)); + CHECK_MALLOC(a); + memset(a,0,sizeof(Attachment)); + + a->charset = xStrdup(g_charset); /* default is "utf-8" */ + if (*g_mime_type != '\0') + { + a->mime_type = xStrdup(g_mime_type); + } + + if (*g_content_transfer_encoding != '\0') + a->content_transfer_encoding = xStrdup(g_content_transfer_encoding); + + a->attach_separator = *g_attach_sep; + a->content_disposition = xStrdup(g_content_disposition); + if (*g_attach_name != '\0') + { + a->attachment_name = xStrdup(g_attach_name); + } + + return(a); +} + /* just a debug routine */ diff --git a/mermsemr/src/mailsend/smtp.c b/mermsemr/src/mailsend/smtp.c old mode 100644 new mode 100755 index d04c20b..f9145d3 --- a/mermsemr/src/mailsend/smtp.c +++ b/mermsemr/src/mailsend/smtp.c @@ -15,6 +15,7 @@ #include "mailsend.h" static char buf[BUFSIZ]; +static int bufsz = sizeof(buf) - 1; static int break_out=0; static char smtp_line[BUFSIZ]; @@ -40,7 +41,20 @@ static SOCKET smtpConnect(char *smtp_server,int port) SOCKET sfd; - sfd=clientSocket(smtp_server,port); + if (g_use_protocol == MSOCK_USE_IPV4) + { + showVerbose("Forcing to use IPv4 address of SMTP server\n"); + } + else if (g_use_protocol == MSOCK_USE_IPV6) + { + showVerbose("Forcing to use IPv6 address of SMTP server\n"); + } + else + { + showVerbose("Will detect IPv4 or IPv6 automatically\n"); + } + + sfd=clientSocket(g_use_protocol, smtp_server,port, g_connect_timeout); if (sfd == INVALID_SOCKET) { errorMsg("Could not connect to SMTP server \"%s\" at port %d", @@ -54,6 +68,35 @@ static SOCKET smtpConnect(char *smtp_server,int port) return (sfd); } +int read_smtp_multi_lines(void) +{ + int + rc, + lcnt = 0; + if (smtp_sep == A_DASH) + { + for (;;) + { + rc=read_smtp_line(); + if (rc < 0) + break; + lcnt++; + if (lcnt >= 100) + { + errorMsg("Too many lines from server\n"); + rc=(-1); + goto ExitProcessing; + } + if (smtp_sep != A_DASH) + break; + } + } + smtp_sep = A_SPACE; + return(0); +ExitProcessing: + return(1); +} + /* * sfd socket * @@ -78,10 +121,10 @@ int read_smtp_line(void) memset(lbuf,0,sizeof(lbuf)); /* read a line */ - n=msock_gets(lbuf,sizeof(lbuf)-1); + n=msock_gets(lbuf,sizeof(lbuf)-1, g_read_timeout); if (n < 3 ) { - //errorMsg("Error reading SMTP line, read %d bytes",n); + /*errorMsg("Error reading SMTP line, read %d bytes",n);*/ return(-1); } showVerbose("[S] %s\n",lbuf); @@ -158,7 +201,8 @@ int smtp_start_tls(int sfd) rc=(-1); } #else - errorMsg("Not Compiled with OpenSSL, could not do STARTTLS"); + errorMsg("Not Compiled with OpenSSL, will not try STARTTLS"); + rc=(-1); #endif /*HAVE_OPENSSL */ return(rc); } @@ -197,6 +241,7 @@ static int say_helo(char *helo_domain) break; } } + smtp_sep = A_SPACE; return(rc); } @@ -222,11 +267,9 @@ static int smtp_MAIL_FROM(char *from) /* SMTP: quit */ static int smtp_QUIT(void) { - int - rc; showVerbose("[C] QUIT\r\n"); msock_puts("QUIT\r\n"); - rc=read_smtp_line(); + read_smtp_line(); /* ** google does not seem to write anything back in response to QUIT ** command. I'll ignore it anyway @@ -325,13 +368,30 @@ static int smtp_DATA(void) } /* SMTP: EOM */ +/* return 0 on success, -1 on failure */ int smtpEom(int sfd) { + int + rc; + msock_puts("\r\n.\r\n"); showVerbose("\r\n[C] .\r\n"); - return (read_smtp_line()); + /* + ** Bug# 1 + ** we want to see smtp code 250 now + ** if mail is too big, it can mail with 552 message too large + */ + rc = read_smtp_line(); + if (smtp_code != 250) + { + read_smtp_multi_lines(); + errorMsg("Expected smtp code 250, got %d\n",smtp_code); + rc = (-1); + } + + return(rc); } void doCleanup(void) @@ -353,7 +413,7 @@ static BOOL WINAPI CntrlHandler(DWORD CtrlEvent) { break_out=1; (void) fprintf(stderr,"\nNot sending mail. Exiting.......\n"); - exit(1); /* XXXXXXXXXXXXXXXXXXXXXX */ + exit_error(); break; } } @@ -362,6 +422,645 @@ static BOOL WINAPI CntrlHandler(DWORD CtrlEvent) } #endif /* WINNT */ +int write_to_socket(char *str) +{ + int + n; + if (str == NULL) + { + return (-1); + } + n = msock_puts(str); + /*showVerbose("%d bytes: %s\n",n, str);*/ + return(n); +} + +/* +** return 0 on success +*/ +int encode2base64andwrite2socket(const char *str) +{ + FILE + *tfp1 = NULL, + *tfp2 = NULL; + char + mbuf[1000], + oneline_tempfile1[MUTILS_PATH_MAX], + oneline_tempfile2[MUTILS_PATH_MAX]; + + memset(oneline_tempfile1, 0, sizeof(oneline_tempfile1)); + /* write the text to a tmp file */ + tfp1 = mutils_get_tempfileFP(oneline_tempfile1, + sizeof(oneline_tempfile1)-1); + if (tfp1 == NULL) + { + errorMsg("%s (%d) - Could not open temp file1 for writing (%s)", + MFL, + ERR_STR); + return (-1); + } + (void) fprintf(tfp1,"%s",str); + (void) fclose(tfp1); + + /* open another tmp file to write the base64 of the first tmp file to */ + memset(oneline_tempfile2, 0, sizeof(oneline_tempfile2)); + tfp2 = mutils_get_tempfileFP(oneline_tempfile2, + sizeof(oneline_tempfile2)-1); + showVerbose("Oneline temp file2: * %s\n",oneline_tempfile2); + if (tfp2 == NULL) + { + errorMsg("%s (%d) - Could not open temp file2 for writing (%s)", + MFL, + ERR_STR); + return (-1); + } + + tfp1 = fopen(oneline_tempfile1,"rb"); + if (tfp1 == NULL) + { + errorMsg("%s (%d) - Could not open temp file for reading (%s)", + MFL, + ERR_STR); + return(-1); + } + + mutilsBase64Encode(tfp1,tfp2); + (void) fclose(tfp1); + (void) fclose(tfp2); + + /* open the file with base64 and write the content to socket */ + tfp2 = fopen(oneline_tempfile2,"r"); + if (tfp2 == NULL) + { + errorMsg("%s (%d) - Could not open temp file for reading (%s)", + MFL, + ERR_STR); + return(-1); + } + while(fgets(mbuf, sizeof(mbuf)-1, tfp2)) + { + write_to_socket(mbuf); + if (g_show_attachment_in_log) + { + showVerbose("[C] %s",mbuf); + } + } + (void) fclose(tfp2); + unlink(oneline_tempfile1); + unlink(oneline_tempfile2); + + return(0); +} + +/* +** send one line messages, each one is an inline attachment +** return 0 if mail is sent, -1 otherwise +*/ +int process_oneline_messages(const char *boundary) +{ + Attachment + *a = NULL; + Sll + *l, + *oneline_attachment_list; + + oneline_attachment_list = get_oneline_attachment_list(); + if (oneline_attachment_list == NULL) + { + return(0); + } + print_oneline_attachment_list(); + + for (l = oneline_attachment_list; l; l = l->next) + { + a = (Attachment *) l->data; + (void) snprintf(buf, bufsz, "\r\n--%s\r\n",boundary); + write_to_socket(buf); + + if (strcmp(a->charset,"none") != 0) + { + (void) snprintf(buf, bufsz, "Content-Type: %s; charset=%s\r\n", + a->mime_type, + a->charset); + } + else + { + (void) snprintf(buf, bufsz, "Content-Type: %s\r\n",a->mime_type); + } + write_to_socket(buf); + + (void) strcpy(buf,"Content-Disposition: inline\r\n"); + write_to_socket(buf); + + /* add encoding type if needed */ + if (strncmp(a->content_transfer_encoding,"none",4) != 0) + { + (void) snprintf(buf, bufsz, "Content-Transfer-Encoding: %s\r\n\r\n", + a->content_transfer_encoding); + write_to_socket(buf); + } + + + if (strncmp(a->content_transfer_encoding,"base64",6) == 0) + { + /* encode the mssage to base 64 and write to socket */ + encode2base64andwrite2socket(a->oneline_msg); + } + else + { + /* + ** no encoding type, so last \r\n was no added, we must + ** add it or some mailer will thing the mail is invalid + */ + if (strncmp(a->content_transfer_encoding,"none",4) == 0) + { + write_to_socket("\r\n"); + } + write_to_socket(a->oneline_msg); + if (g_show_attachment_in_log) + { + showVerbose("[C] %s\n",a->oneline_msg); + + } + } + write_to_socket("\r\n"); + } + return(0); +} + +/* +** include the content of the file as body of the message +** No encoding will be done. +*/ +int include_msg_body(void) +{ + Sll + *l, + *msg_body_attachment_head; + + FILE + *fp = NULL; + + Attachment + *a; + + msg_body_attachment_head = get_msg_body_attachment_list(); + if (msg_body_attachment_head == NULL) + { + return(-1); + } + + l = msg_body_attachment_head; + a = (Attachment *) l->data; + + (void) snprintf(buf,bufsz,"MIME-Version: 1.0\r\n"); + write_to_socket(buf); + + if (strcmp(a->charset,"none") != 0) + { + (void) snprintf(buf,bufsz,"Content-Type: %s; charset=%s\r\n\r\n", + a->mime_type, + a->charset); + } + else + { + (void) snprintf(buf,bufsz,"Content-Type: %s\r\n\r\n",a->mime_type); + } + write_to_socket(buf); + + fp=fopen(a->file_path,"r"); + if (fp == (FILE *) NULL) + { + errorMsg("Could not open message body file: %s",a->file_path); + return (-1); + } + + while (fgets(buf,bufsz,fp)) + { + write_to_socket(buf); + if (g_show_attachment_in_log) + { + showVerbose("[C] %s",buf); + } + } + (void) fclose(fp); + + (void) snprintf(buf,bufsz,"\r\n\r\n"); + msock_puts(buf); + showVerbose(buf); + return(0); +} + +int include_image(void) +{ + return(0); +} + +static void cleanup_attachment(Attachment *a) +{ + if (a == NULL) + return; + if (a->fp_read) + { + (void) fclose(a->fp_read); + } + if (*a->mime_tmpfile != '\0') + { + unlink(a->mime_tmpfile); + } +} + + +/* +** return the attachment with fp_read member open. +** If encoding type requires some kind of encoding, +** mime_tmpfile will contain the file which holds the +** encoded content. The caller must close the file pointer +** and unlik the tmp_filename +** return NULL on error +*/ +static Attachment *get_encoded_attachment(Attachment *a) +{ + FILE + *fp_read = NULL, + *tfp_write = NULL; + int + tempfile_opened = 0; + + if (strncmp(a->content_transfer_encoding, "base64", 6) == 0) + { + tfp_write = mutils_get_tempfileFP(a->mime_tmpfile,sizeof(a->mime_tmpfile)-1); + if (tfp_write == NULL) + { + errorMsg("%s (%d) - Could not create temp file for MIME (%s)", + MFL, + ERR_STR); + return(NULL); + } + tempfile_opened = 1; + showVerbose("%s (%d) - MIME temp file: %s created successfully, FILE pointer=%x\n", + MFL, + a->mime_tmpfile, + tfp_write); + + /* open the file to attach */ + fp_read = fopen(a->file_path,"rb"); + if (fp_read == (FILE *) NULL) + { + errorMsg("%s (%d) - Could not open file for %s reading (%s)", + MFL, + a->file_path, + ERR_STR); + goto ExitProcessing; + } + + showVerbose("%s (%d) - Writing Content to FILE pointer: %x\n", + MFL, + tfp_write); + /* write base64 content to tmp file */ + mutilsBase64Encode(fp_read,tfp_write); + (void) fclose(fp_read); + fp_read = NULL; + + (void) fclose(tfp_write); + tfp_write = NULL; + a->fp_read = fopen(a->mime_tmpfile, "r"); + if (a->fp_read == (FILE *) NULL) + { + errorMsg("%s (%d) - Could not open file for %s reading (%s)", + MFL, + a->file_path, + ERR_STR); + goto ExitProcessing; + } + if (tempfile_opened) + { + unlink(a->mime_tmpfile); + } + return(a); + } + /* no tmp file */ + memset(a->mime_tmpfile, 0, sizeof(a->mime_tmpfile)); + + /* open the attachment. caller must close it */ + a->fp_read = fopen(a->file_path, "r"); + if (a->fp_read == (FILE *) NULL) + { + errorMsg("%s (%d) - Could not open file for %s reading (%s)", + MFL, + a->file_path, + ERR_STR); + return (NULL); + } + return(a); + +ExitProcessing: + if (tempfile_opened) + { + unlink(a->mime_tmpfile); + } + return(NULL); +} + +/* +** write MIME headers, encode attachment if needed +** and write to socket +** returns 0 on success -1 on failure +*/ +int send_attachment(Attachment *a, const char *boundary) +{ + Attachment + *encoded_attachment; + + encoded_attachment = get_encoded_attachment(a); + if (encoded_attachment == NULL) + { + errorMsg("%s (%d) - Could not encode attachment %s", + MFL, + a->file_path); + return(-1); + } + + (void) snprintf(buf, bufsz,"\r\n--%s\r\n",boundary); + write_to_socket(buf); + + if (a->charset && strncmp(a->charset,"none", 4) != 0) + { + (void) snprintf(buf, bufsz, "Content-Type: %s; charset=%s\r\n", + a->mime_type, + a->charset); + } + else + { + if (a->attachment_name) + { + (void) snprintf(buf, bufsz, "Content-Type: %s; name=\"%s\"\r\n", + a->mime_type, + a->attachment_name); + } + else + { + (void) snprintf(buf, bufsz, "Content-Type: %s\r\n",a->mime_type); + } + } + write_to_socket(buf); + + if (a->content_id == NULL) + { + if (strncmp(a->content_disposition, "inline", 6) == 0) + { + (void) snprintf(buf, bufsz, "Content-Disposition: %s\r\n",a->content_disposition); + } + else + { + if (a->attachment_name) + { + (void) snprintf(buf, bufsz, "Content-Disposition: %s; filename=\"%s\"\r\n", + a->content_disposition, + a->attachment_name); + + } + else if (a->file_name) + { + (void) snprintf(buf, bufsz, "Content-Disposition: %s; filename=\"%s\"\r\n", + a->content_disposition, + a->file_name); + } + else + { + (void) snprintf(buf, bufsz, "Content-Disposition: %s\r\n",a->content_disposition); + } + } + write_to_socket(buf); + } + + if (a->content_id) + { + (void) snprintf(buf, bufsz, "Content-ID: <%s>\r\n",a->content_id); + write_to_socket(buf); + (void) snprintf(buf, bufsz, "X-Attachment-Id: %s\r\n",a->content_id); + write_to_socket(buf); + } + + if (strncmp(a->content_transfer_encoding,"none",4) != 0) + { + (void) snprintf(buf, bufsz, "Content-Transfer-Encoding: %s\r\n\r\n", + a->content_transfer_encoding); + write_to_socket(buf); + } + else + { + write_to_socket("\r\n"); + } + + /* our FILE pointer is already open and read to read from */ + while (fgets(buf, bufsz, a->fp_read)) + { + write_to_socket(buf); + } + /* close file, remove tmp file if needed */ + cleanup_attachment(a); + return(0); +} + +int process_attachments(const char *boundary) +{ + Attachment + *a; + + Sll + *attachment_list, + *al; + + int + rc; + + attachment_list = get_attachment_list(); + if (attachment_list == NULL) + { + return(0); + } + + for (al=attachment_list; al; al=al->next) + { + a=(Attachment *) al->data; + if (a == NULL) + continue; + + rc = send_attachment(a, boundary); + if (rc == -1) + { + errorMsg("%s (%d) - failed to send attachment %s\n", + MFL, + a->file_path); + return(-1); + } + } + + (void) snprintf(buf,sizeof(buf)-1,"\r\n--%s--\r\n",boundary); + msock_puts(buf); + showVerbose(buf); + + return(0); +} + +/* +** Print multipart/mixed or multipart/related header +** if mixed and embedded images are specified, make +** to use multipart/alternative for the embedded images. +*/ +int print_content_type_header(const char *boundary) +{ + Sll + *oneline_attachment_list, + *attachment_list, + *embed_image_list; + + (void) snprintf(buf, bufsz,"MIME-Version: 1.0\r\n"); + write_to_socket(buf); + + if (*g_content_type!='\0') + { + (void) snprintf(buf,sizeof(buf)-1,"Content-Type: %s; boundary=\"%s\"\r\n", + g_content_type, + boundary); + write_to_socket(buf); + return(0); + } + + oneline_attachment_list = get_oneline_attachment_list(); + attachment_list = get_attachment_list(); + embed_image_list = get_embed_image_attachment_list(); + if (oneline_attachment_list || attachment_list) + { + (void) snprintf(buf,sizeof(buf)-1, + "Content-Type: multipart/mixed; boundary=\"%s\"\r\n", boundary); + write_to_socket(buf); + return(0); + } + if (embed_image_list) + { + (void) snprintf(buf,sizeof(buf)-1, + "Content-Type: multipart/related; boundary=\"%s\"\r\n", boundary); + write_to_socket(buf); + return(0); + } + write_to_socket("\r\n"); + return(0); +} + +int process_embeded_images(const char *boundary) +{ + char + *ib, + *b, + related[17], + cid[17], + tbuf[24], + alternative[17]; + + Attachment + *a; + + Sll + *il, + *oneline_attachment_list, + *attachment_list, + *embed_image_list; + + int + rc, + ic = 1; + + oneline_attachment_list = get_oneline_attachment_list(); + attachment_list = get_attachment_list(); + + embed_image_list = get_embed_image_attachment_list(); + if (embed_image_list == NULL) + { + return(0); + } + memset(related, 0, sizeof(related)); + memset(alternative, 0, sizeof(alternative)); + + mutilsGenerateMIMEBoundary(related,sizeof(related)); + mutilsGenerateMIMEBoundary(alternative,sizeof(alternative)); + b = boundary; + ib = boundary; + + (void) snprintf(buf, bufsz, "\r\n--%s\r\n",boundary); + write_to_socket(buf); + + if (attachment_list || oneline_attachment_list) + { + b = related; + ib = b; + (void) snprintf(buf, bufsz, "Content-Type: multipart/related; boundary=%s\r\n",b); + write_to_socket(buf); + + (void) snprintf(buf, bufsz, "Content-Type: multipart/alternative; boundary=%s\r\n\r\n", + alternative); + write_to_socket(buf); + + (void) snprintf(buf, bufsz, "\r\n--%s\r\n",b); + write_to_socket(buf); + } + else + { + ib = alternative; + (void) snprintf(buf, bufsz, "Content-Type: multipart/alternative; boundary=%s\r\n\r\n", + alternative); + write_to_socket(buf); + + (void) snprintf(buf, bufsz, "\r\n--%s\r\n",alternative); + write_to_socket(buf); + } + + write_to_socket("Content-Type: text/html; charset=ISO-8859-1\r\n\r\n"); + + /* write the img tags with cid */ + embed_image_list = get_embed_image_attachment_list(); + for (il = embed_image_list; il; il = il->next) + { + a = (Attachment *) il->data; + mutilsGenerateMIMEBoundary(cid,sizeof(cid)); + (void) snprintf(tbuf,sizeof(tbuf)-1,"ii%d_%s",ic,cid); + a->content_id = xStrdup(tbuf); + (void) snprintf(buf, bufsz, "\"inline
\n", + tbuf, + ic); + write_to_socket(buf); + ic++; + } + write_to_socket("\r\n"); + (void) snprintf(buf, bufsz, "\r\n--%s--\r\n",ib); + write_to_socket(buf); + + for (il = embed_image_list; il; il = il->next) + { + a = (Attachment *) il->data; + if (a == NULL) + continue; + rc = send_attachment(a,b); + RETURN_IF_NOT_ZERO(rc); + } + (void) snprintf(buf, bufsz, "\r\n--%s--\r\n",b); + write_to_socket(buf); + return(0); +} + +static void print_end_boundary(const char *boundary) +{ + if (get_attachment_list() == NULL) + { + (void) snprintf(buf,sizeof(buf)-1,"\r\n--%s--\r\n",boundary); + msock_puts(buf); + showVerbose(buf); + return; + } + /* process_attachments(boundary) already printed the end bounday */ +} + /* SMTP: mail */ static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,char *rt, char *subject,char *attach_file,char *msg_body_file, @@ -370,13 +1069,17 @@ static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,cha char *os="Unix", boundary[17], - mbuf[1000]; + related[17], + alternative[17], + mbuf[1024]; int newline_before; Sll - *attachment_list; + *oneline_attachment_list, + *attachment_list, + *embed_image_list; #ifdef WINNT os="Windows"; @@ -384,8 +1087,14 @@ static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,cha os="Unix"; #endif /* WINNT */ + memset(boundary, 0, sizeof(boundary)); + memset(related, 0, sizeof(related)); + memset(alternative, 0, sizeof(alternative)); + attachment_list=get_attachment_list(); - if (attachment_list) + embed_image_list = get_embed_image_attachment_list(); + oneline_attachment_list = get_oneline_attachment_list(); + if (attachment_list || embed_image_list || oneline_attachment_list) { is_mime=1; } @@ -483,6 +1192,28 @@ static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,cha showVerbose(buf); } + /* add custom headers if any. No verification is done */ + { + Sll + *l, + *custom_header_list; + custom_header_list = get_custom_header_list(); + if (custom_header_list) + { + for (l = custom_header_list; l; l = l->next) + { + if (l->data) + { + msock_puts((char *) l->data); + msock_puts("\r\n"); + showVerbose((char *) l->data); + showVerbose("\r\n"); + } + } + } + } + + memset(buf,0,sizeof(buf)); (void) snprintf(buf,sizeof(buf)-1,"X-Mailer: %s (%s)\r\n",MAILSEND_VERSION,os); msock_puts(buf); @@ -493,278 +1224,41 @@ static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,cha msock_puts(buf); showVerbose(buf); - /* - if (is_mime && msg_file) - */ if (is_mime) { + int + rc; srand(time(NULL)); memset(boundary,0,sizeof(boundary)); mutilsGenerateMIMEBoundary(boundary,sizeof(boundary)); - (void) snprintf(buf,sizeof(buf)-1,"Content-type: multipart/mixed; boundary=\"%s\"\r\n",boundary); - msock_puts(buf); - showVerbose(buf); - (void) snprintf(buf,sizeof(buf)-1,"Mime-version: 1.0\r\n"); - msock_puts(buf); - showVerbose(buf); - } + /* if msg body file is specified, include and return */ + if (msg_body_file) + { + return (include_msg_body()); + } - msock_puts("\r\n"); - showVerbose("\r\n"); + rc = print_content_type_header(boundary); + RETURN_IF_NOT_ZERO(rc); - /* - if (is_mime && msg_file) - */ - if (is_mime) - { - char - mime_tmpfile[BUFSIZ]; + rc = process_oneline_messages(boundary); + RETURN_IF_NOT_ZERO(rc); - FILE - *tfp=NULL, - *fp=NULL; - int - tfwd; + rc = process_embeded_images(boundary); + RETURN_IF_NOT_ZERO(rc); + + rc = process_attachments(boundary); + RETURN_IF_NOT_ZERO(rc); /* - ** If there a txt file or a one line messgae, attach them first + ** if there were other kind of MIME types but no attachments, + ** we have to print the last boundary */ - /* Part added by Smeeta Jalan -- starts */ - if (the_msg) - { - (void) snprintf(buf,sizeof(buf)-1,"\r\n--%s\r\n",boundary); - msock_puts(buf); - showVerbose(buf); + print_end_boundary(boundary); - (void) snprintf(buf,sizeof(buf)-1,"Content-Type: text/html; charset=%s\r\n",g_charset); - msock_puts(buf); - showVerbose(buf); - - (void) strcpy(buf,"Content-Disposition: inline\r\n"); - msock_puts(buf); - showVerbose(buf); - - msock_puts("\r\n"); - showVerbose("\r\n"); - - /* (void) strcpy(buf,the_msg); */ - mutilsSafeStrcpy(buf,the_msg,sizeof(buf)-1); - msock_puts(buf); - showVerbose("[C] %s",the_msg); - - (void) snprintf(buf,sizeof(buf)-1,"\r\n\r\n"); - msock_puts(buf); - showVerbose(buf); - } - - if (msg_body_file) - { - int - rc; - char - mime_type[32], - filename[1024]; - - FILE - *fp; - - rc=get_filepath_mimetype(msg_body_file,filename, - sizeof(filename)-1,mime_type,sizeof(mime_type)-1); - /* - * The file should not have binary characters it it. - * It's user's responsibilty to make sure file is not binary. - * If file is binary mail will have garbage as I'll not convert - * the content to base64 - */ - fp=fopen(filename,"r"); - if (fp == (FILE *) NULL) - { - errorMsg("Could not open message body file: %s",filename); - return (-1); - } - - (void) snprintf(buf,sizeof(buf)-1,"\r\n--%s\r\n",boundary); - msock_puts(buf); - showVerbose(buf); - - (void) snprintf(buf,sizeof(buf)-1,"Content-Type: %s; charset=%s\r\n",mime_type,g_charset); - msock_puts(buf); - showVerbose(buf); - - (void) strcpy(buf,"Content-Disposition: inline\r\n"); - msock_puts(buf); - showVerbose(buf); - - msock_puts("\r\n"); - showVerbose("\r\n"); - - while (fgets(mbuf,sizeof(mbuf)-1,fp)) - { - msock_puts(mbuf); - showVerbose("[C] %s",mbuf); - } - (void) fclose(fp); - - (void) snprintf(buf,sizeof(buf)-1,"\r\n\r\n"); - msock_puts(buf); - showVerbose(buf); - } - /* Part added by Smeeta Jalan --ends --*/ - - /* open a tmp file writing MIME content */ - (void) strcpy(mime_tmpfile,"./mailsendXXXXXX"); - - /* handle mime */ - { - Attachment - *a; - Sll - *al; - - for (al=attachment_list; al; al=al->next) - { - a=(Attachment *) al->data; - if (a == NULL) - continue; - - /* open the mime input file */ - fp=fopen(a->file_path,"rb"); - if (fp == (FILE *) NULL) - { - errorMsg("%s (%d) - Could not open file for reading: %s (%s)",MFL,a->file_path,ERR_STR); - return (-1); - } - - (void) strcpy(mime_tmpfile,"./mailsendXXXXXX"); -#ifdef HAVE_MKSTEMP - tfwd=mkstemp(mime_tmpfile); - if (tfwd == -1) - { - errorMsg("%s (%d) - Could not open tmp file \"%s\" for writing (for %s)\n",MFL,mime_tmpfile,a->file_name); - return (-1); - } - tfp=fdopen(tfwd,"w"); - if (tfp == NULL) - { - (void) fprintf(stderr,"fdopen() failed on %s\n",mime_tmpfile); - close(tfwd); - unlink(mime_tmpfile); - return(-1); - } -#else - mktemp(mime_tmpfile); - - tfp=fopen(mime_tmpfile,"w"); - if (tfp == NULL) - { - (void) fprintf(stderr,"Could not open tmp file \"%s\" for writing (for %s)\n",mime_tmpfile,a->file_name); - return (-1); - } -#endif /* HAVE_MKSTEMP */ - - /* base64 encode only if it is not mime type of text/plain */ - - if (mutilsStrcasecmp(a->mime_type,"text/plain") != 0) - { - mutilsBase64Encode(fp,tfp); - if (tfp) - { - (void) fclose(tfp); - } - } - else - { - FILE - *ttp; - char - xbuf[BUFSIZ]; - - /* write the text file to tmp file */ - ttp=fopen(a->file_path,"r"); - if (ttp == NULL) - - { - errorMsg("%s (%d) - could not open file %s for reading (%s)\n",MFL,a->file_path,ERR_STR); - continue; - } - while(fgets(xbuf,sizeof(xbuf)-1,ttp)) - { - fputs(xbuf,tfp); - } - fclose(ttp); - (void) fclose(tfp); - - } - if (fp) - (void) fclose(fp); - - (void) snprintf(buf,sizeof(buf)-1,"--%s\r\n",boundary); - msock_puts(buf); - showVerbose(buf); - - - if (mutilsStrcasecmp(a->mime_type,"text/plain") == 0) - { - /* - ** Guess the file type first. - ** If binary, change my type and base64 encode it. - ** If the file is text and in Unix format, write it - ** back as Dos file (with \r\n - ** TODO - ** muquit@muquit.com Mar-21-2007 - */ - - (void) snprintf(buf,sizeof(buf)-1,"Content-Type: text/plain; charset=%s\r\n",g_charset); - msock_puts(buf); - showVerbose(buf); - - (void) snprintf(buf,sizeof(buf)-1,"Content-Disposition: %s; filename=\"%s\"\r\n", - a->content_disposition, - a->file_name); - msock_puts(buf); - showVerbose(buf); - - msock_puts("\r\n"); - showVerbose("\r\n"); - } - else - { - (void) snprintf(buf,sizeof(buf)-1,"Content-Type: %s; name=%s\r\n",a->mime_type,a->file_name); - msock_puts(buf); - showVerbose(buf); - - (void) snprintf(buf,sizeof(buf)-1,"Content-Disposition: %s; filename=\"%s\"\r\n", - a->content_disposition, - a->file_name); - msock_puts(buf); - showVerbose(buf); - - msock_puts("Content-Transfer-Encoding: base64\r\n\r\n"); - showVerbose("Content-Transfer-Encoding: base64\r\n\r\n"); - } - - fp=fopen(mime_tmpfile,"r"); - if (fp == (FILE *) NULL) - { - (void) fprintf(stderr,"Could not open tmp file \"%s\" for reading\n",mime_tmpfile); - return (-1); - } - while (fgets(mbuf,sizeof(mbuf)-1,fp)) - { - msock_puts(mbuf); - showVerbose("[C] %s",mbuf); /* new line is there */ - } - (void) fclose(fp); - unlink(mime_tmpfile); - } - - (void) snprintf(buf,sizeof(buf)-1,"\r\n--%s--\r\n",boundary); - msock_puts(buf); - showVerbose(buf); - } + /* handle MIME attachments ends */ goto done; - } + } /* is_mime */ /* mail body */ if (attach_file == NULL && the_msg == NULL) /* read from stdin */ @@ -783,6 +1277,8 @@ static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,cha #endif /* WINNT */ newline_before=1; + msock_puts("\r\n"); /* RFC822 sec 3.1 */ + showVerbose("\r\n"); while (fgets(mbuf,sizeof(mbuf)-1,stdin) && (break_out == 0)) { if (newline_before && *mbuf == '.') @@ -830,10 +1326,11 @@ static int read_greetings(void) if (rc < 0) goto cleanup; - s_esmtp=g_esmtp; /* if foreced with -ehlo */ + s_esmtp=g_esmtp; /* if forced with -ehlo */ if (smtp_code != 220) { + read_smtp_multi_lines(); errorMsg("Expected smtp code 220, got %d\n",smtp_code); rc=(-1); goto cleanup; @@ -866,9 +1363,46 @@ static int read_greetings(void) } } cleanup: + smtp_sep = A_SPACE; return(rc); } +static int turn_on_raw_ssl(SOCKET sfd) +{ +#ifdef HAVE_OPENSSL + int + rc=(-1); + + SSL + *ssl; + + ssl=msock_get_ssl(); + if (ssl) + { + if (!SSL_set_fd(ssl,sfd)) + { + errorMsg("turn_on_raw_ssl: failed to set socket %d to SSL\n",sfd); + return(-1); + } + /* must set back to msock's static */ + msock_set_ssl(ssl); + rc=SSL_connect(ssl); + if (rc < 1) + { + errorMsg("turn_on_raw_ssl: SSL connection failed\n"); + ERR_print_errors_fp(stderr); + return(-1); + } + print_cert_info(ssl); + /* tell msock everything is ssl after that */ + msock_turn_ssl_on(); + rc=0; + return(0); + } +#endif /* HAVE_OPENSSL */ + return(-1); +} + /* It's stupid, I need to change all the args to a struct, one of those * days! I'll do it */ @@ -877,7 +1411,7 @@ cleanup: int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, char *smtp_server,int smtp_port,char *helo_domain, char *attach_file,char *txt_msg_file,char *the_msg,int is_mime,char *rrr,char *rt, - int add_dateh) + int add_dateh,char* return_path_addr) { SOCKET sfd; @@ -885,6 +1419,7 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, TheMail *mail; + Sll *al; @@ -893,11 +1428,14 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, char *mech=NULL, - *b64=NULL, *auth=NULL; - unsigned long - b64len=0; + /* + unsigned char + *b64=NULL; + */ + char + *b64 = NULL; int authenticated=0; @@ -949,10 +1487,11 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, mail=newTheMail(); if (mail == (TheMail *) NULL) { - (void) fprintf(stderr,"Error: malloc failed in createTheMail()\n"); + errorMsg("Error: malloc failed in createTheMail()\n"); return (-1); } + showVerbose("Connecting to %s:%d\n",smtp_server,smtp_port); /* open the network connection */ sfd=smtpConnect(smtp_server,smtp_port); if (sfd == INVALID_SOCKET) @@ -961,6 +1500,11 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, goto cleanup; } + if (g_do_ssl) /* smtp.gmail:465 supports it for example */ + { + turn_on_raw_ssl(sfd); + } + /* read greeting */ rc=read_greetings(); if (rc < 0) @@ -984,21 +1528,31 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, } } - auth=check_server_cap("AUTH"); + if (g_do_auth || g_auth_cram_md5 || g_auth_login || g_auth_plain) + { + auth=check_server_cap("AUTH"); + } if (!auth) goto MailFrom; + /* + (void) fprintf(stderr,"auth=%s\n",auth); + (void) fprintf(stderr," g_auth_cram_md5=%d; g_auth_login=%d; g_auth_plain=%d\n", g_auth_cram_md5, g_auth_login, g_auth_plain); + */ + + /* if (auth && g_do_auth) { g_auth_cram_md5=1; g_auth_login=1; g_auth_plain=1; } + */ /* Try CRAM-MD5 first */ mech="CRAM-MD5"; if (g_auth_cram_md5 && check_server_cap(mech)) { char - *cmd5; + *cmd5 = NULL; CHECK_USERNAME(mech); CHECK_USERPASS(mech); @@ -1022,7 +1576,13 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, rc=(-1); goto cleanup; } - cmd5=encode_cram_md5(smtp_line,g_username,g_userpass); + cmd5 = encode_cram_md5(smtp_line,g_username,g_userpass); + if (cmd5 == NULL) + { + errorMsg("Could not encode CRAM-MD5"); + rc = (-1); + goto cleanup; + } memset(buf,0,sizeof(buf)); (void) snprintf(buf,sizeof(buf)-1,"%s\r\n",cmd5); showVerbose("[C] %s",buf); @@ -1039,7 +1599,15 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, showVerbose("%s Authentication succeeded\n",mech); authenticated++; - + if (cmd5) + { + (void) free((char *) cmd5); + } + } + else + { + if (g_auth_cram_md5) + showVerbose("Server does not support AUTH CRAM-MD5\n"); } if (authenticated) goto MailFrom; @@ -1065,19 +1633,21 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, rc=(-1); goto cleanup; } - + /* b64=mutils_encode_base64(g_username,strlen(g_username),&b64len); + b64[b64len-2]='\0'; + */ + b64=mutils_encode_base64_noformat(g_username,strlen(g_username)); if (b64 == NULL) { - errorMsg("Could not base64 encode user: %s",buf); + errorMsg("Could not base64 encode user: %s",g_username); rc=(-1); goto cleanup; } - /* mutils_encode_base64 adds CRLF */ - b64[b64len-2]='\0'; memset(buf,0,sizeof(buf)); (void) snprintf(buf,sizeof(buf)-1,"%s\r\n",b64); + showVerbose("[C] %s",buf); msock_puts(buf); read_smtp_line(); if (smtp_code != 334) @@ -1089,19 +1659,23 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, goto cleanup; } + /* b64=mutils_encode_base64(g_userpass,strlen(g_userpass),&b64len); + b64[b64len-2]='\0'; + */ + b64=mutils_encode_base64_noformat(g_userpass,strlen(g_userpass)); if (b64 == NULL) { - errorMsg("Could not base64 encode user: %s",buf); + errorMsg("Could not base64 encode passworf of user: %s",g_username); rc=(-1); goto cleanup; } - /* mutils_encode_base64 adds CRLF */ - b64[b64len-2]='\0'; memset(buf,0,sizeof(buf)); (void) snprintf(buf,sizeof(buf)-1,"%s\r\n",b64); + showVerbose("[C] %s",buf); msock_puts(buf); + read_smtp_line(); if (smtp_code != 235) { @@ -1113,6 +1687,12 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, } authenticated++; } + else + { + if (g_auth_login) + showVerbose("Server does not support AUTH LOGIN\n"); + } + if (authenticated) goto MailFrom; @@ -1131,6 +1711,7 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, CHECK_USERNAME(mech); CHECK_USERPASS(mech); + showVerbose("Using AUTH %s\n",mech); memset(buf,0,sizeof(buf)); /* ** authzid\0authid\0pass @@ -1143,9 +1724,19 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, memcpy(buf + ulen + 2,g_userpass,plen); len=ulen + plen + 2; +#if 0 b64=mutils_encode_base64(buf,len,&b64len); /* mutils_encode_base64 adds CRLF */ b64[b64len-2]='\0'; +#endif + b64=mutils_encode_base64_noformat(buf,len); + if (b64 == NULL) + { + errorMsg("Could not base64 for AUTH-PLAIN for user: %s",g_username); + rc=(-1); + goto cleanup; + } + (void) snprintf(buf,sizeof(buf)-1,"AUTH PLAIN %s\r\n",(char *) b64); showVerbose("[C] %s",buf); @@ -1163,6 +1754,11 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, showVerbose("PLAIN Authentication succeeded\n"); authenticated++; } + else + { + if (g_auth_plain) + showVerbose("Server does not support AUTH PLAIN\n"); + } if (authenticated) goto MailFrom; @@ -1173,22 +1769,16 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, { if (check_server_cap("CRAM-MD5")) { - (void) fprintf(stderr, -" *Server supports AUTH CRAM-MD5."); - (void) fprintf(stderr, -" Enable with -auth-cram-md5 or -auth\n"); + (void) fprintf(stderr, +" * Server supports AUTH CRAM-MD5."); } } if (!g_auth_login) { if (check_server_cap("LOGIN")) { - (void) fprintf(stderr, -" *Server supports AUTH LOGIN."); - (void) fprintf(stderr, -" Enable with -auth-login or -auth\n"); - (void) fprintf(stderr, -" AUTH LOGIN should be used if server supports STARTTLS (-starttls)\n"); + (void) fprintf(stderr, +" * Server supports AUTH LOGIN.\n"); } } @@ -1196,18 +1786,23 @@ int send_the_mail(char *from,char *to,char *cc,char *bcc,char *sub, { if (check_server_cap("PLAIN")) { - (void) fprintf(stderr, -" *Server supports AUTH PLAIN."); - (void) fprintf(stderr, -" Enable with -auth-plain or -auth\n"); - (void) fprintf(stderr, -" AUTH PLAIN should be used if server supports STARTTLS (-starttls)\n"); + (void) fprintf(stderr, +" * Server supports AUTH PLAIN.\n"); } } + if (!authenticated) + { + (void) fprintf(stderr, +" Use -auth or specify a mechanism that server supports. exiting.\n"); + exit_error(); + } } MailFrom: - rc=smtp_MAIL_FROM(from); + if (return_path_addr) + rc=smtp_MAIL_FROM(return_path_addr); + else + rc=smtp_MAIL_FROM(from); if (rc != 0) goto cleanup; @@ -1220,8 +1815,10 @@ MailFrom: goto cleanup; rc=smtpMail(sfd,to,cc,bcc,from,rrr,rt,sub,attach_file,txt_msg_file,the_msg,is_mime,add_dateh); + RETURN_IF_NOT_ZERO(rc); rc=smtpEom(sfd); + RETURN_IF_NOT_ZERO(rc); smtp_QUIT(); cleanup: @@ -1230,35 +1827,64 @@ cleanup: /* ** print info about SMTP server on stdout +** return 0 on success -1 on error */ -void show_smtp_info(char *smtp_server,int port,char *domain) +int show_smtp_info(char *smtp_server,int port,char *domain) { int fd, - rc; - char - *x; + rc = (-1); +#ifdef HAVE_OPENSSL + SSL + *ssl=NULL; +#endif /* HAVE_OPENSSL */ + g_verbose=1; - x="localhost"; - if (mutilsStrncasecmp(smtp_server,x,strlen(x)) == 0) - { - print_info("SMTP serve: localhost, specify different one with -smtp \n"); - } - else - { - print_info("SMTP server: %s\n",smtp_server); - } + print_info("Connecting to SMTP server: %s at Port: %d\n",smtp_server,port); + print_info("Connection timeout: %d secs\n",g_connect_timeout); /* connect */ fd=smtpConnect(smtp_server,port); if (fd == INVALID_SOCKET) { + rc = (-1); goto ExitProcessing; } +#ifdef HAVE_OPENSSL + if (g_do_ssl) + { + ssl=msock_get_ssl(); + if (ssl) + { + if (!SSL_set_fd(ssl,fd)) + { + errorMsg("failed to set socket to SSL\n"); + goto ExitProcessing; + } + /* must set back to msock's static */ + msock_set_ssl(ssl); + rc=SSL_connect(ssl); + if (rc < 1) + { + errorMsg("SSL connection failed\n"); + ERR_print_errors_fp(stderr); + goto ExitProcessing; + } + print_cert_info(ssl); + /* tell msock everything is ssl after that */ + msock_turn_ssl_on(); + rc=0; + } + } +#endif /* HAVE_OPENSSL */ + /* read greeting */ rc=read_greetings(); if (rc < 0) + { + errorMsg("Could not read greetings\n"); goto ExitProcessing; + } /* say HELO/EHLO */ say_helo(domain); @@ -1277,6 +1903,6 @@ void show_smtp_info(char *smtp_server,int port,char *domain) smtpDisconnect(); ExitProcessing: - return; + return (rc); } diff --git a/mermsemr/src/mailsend/utils.c b/mermsemr/src/mailsend/utils.c old mode 100644 new mode 100755 index 793462b..ae6948f --- a/mermsemr/src/mailsend/utils.c +++ b/mermsemr/src/mailsend/utils.c @@ -8,10 +8,22 @@ */ #include "mailsend.h" +#include "copyright.h" + #define DAY_MIN (24 * HOUR_MIN) /* minutes in a day */ #define HOUR_MIN 60 /* minutes in an hour */ #define MIN_SEC 60 /* seconds in a minute */ +static struct _MimeType +{ + char + *ext, + *val; +} s_mime_type[] = +{ +#include "mime_types.h" +}; + /* ** returns a positive number if the file descriptor is connected to @@ -42,10 +54,50 @@ int isInteractive(void) return(0); } + +/* +** arg: type +** at this time valid types are: "base64", "none" +*/ +int get_encoding_type(const char *type) +{ + if (type == NULL || *type == '\0') + { + return ENCODE_BASE64; + } + if (strncmp("base64", type, 6) == 0) + { + return ENCODE_BASE64; + } + else if (strncmp("none", type, 4) == 0) + { + return ENCODE_NONE; + } + + return ENCODE_BASE64; +} + +int get_content_disposition(const char *disposition) +{ + if (disposition == NULL || *disposition == '\0') + { + return CONTENT_DISPOSITION_ATTACHMENT; + } + if (strncmp("attachment", disposition, 10) == 0) + { + return CONTENT_DISPOSITION_ATTACHMENT; + } + else if (strncmp("inline", disposition, 6) == 0) + { + return CONTENT_DISPOSITION_INLINE; + } + return CONTENT_DISPOSITION_ATTACHMENT; +} + /* ** duplicate a string. exits on failure */ -char *xStrdup (char *string) +char *xStrdup (const char *string) { char *tmp; @@ -59,13 +111,34 @@ char *xStrdup (char *string) if (tmp == (char *) NULL) { (void) fprintf(stderr,"Error: mystrdup(): memory allocation problem\n"); - exit(0); + exit_error(); } /* it's safe to copy this way */ (void) strcpy(tmp, string); return (tmp); } +void log_info(const char *fmt, ...) +{ + va_list + args; + + va_start(args, fmt); + va_end(args); +} + +void log_debug(const char *fmt, ...) +{ +} + +void log_error(const char *fmt, ...) +{ +} + +void log_fatal(const char *fmt, ...) +{ +} + void errorMsg(char *format,...) { va_list @@ -75,6 +148,21 @@ void errorMsg(char *format,...) (void) fprintf (stderr,"Error: "); vfprintf(stderr,format,args); (void) fprintf(stderr,"\n"); + (void) fflush(stderr); + + if (g_log_fp != NULL) + { + MutilsTime + mt; + char + timebuf[64]; + mutils_time_now(&mt); + mutils_time_fmt(&mt,timebuf,sizeof(timebuf)); + (void) fprintf (g_log_fp,"%s: Error: ",timebuf); + vfprintf(g_log_fp,format,args); + (void) fprintf(g_log_fp,"\n"); + (void) fflush(g_log_fp); + } va_end(args); } @@ -82,15 +170,35 @@ void showVerbose(char *format,...) { va_list args; + if (g_quiet) return; if (g_verbose == 1) { - va_start(args,format); - vfprintf(stdout,format,args); - (void) fflush(stdout); - va_end(args); + if (isInConsole(_fileno(stdout))) + { + va_start(args,format); + vfprintf(stdout,format,args); + (void) fflush(stdout); + va_end(args); + } + + if (g_log_fp != NULL) + { + MutilsTime + mt; + char + timebuf[64]; + mutils_time_now(&mt); + mutils_time_fmt(&mt,timebuf,sizeof(timebuf)); + (void) fprintf(g_log_fp,"%s: " ,timebuf); + va_start(args,format); + vfprintf(g_log_fp,format,args); + (void) fflush(g_log_fp); + va_end(args); + } + } } @@ -106,7 +214,50 @@ void print_info(char *format,...) vfprintf(stdout,format,args); (void) fflush(stdout); va_end(args); +} +void write_log(char *format,...) +{ + va_list + args; + + MutilsTime + mt; + char + timebuf[64]; + + if (g_log_fp == NULL) + return; + + mutils_time_now(&mt); + mutils_time_fmt(&mt,timebuf,sizeof(timebuf)); + + va_start(args,format); + (void) fprintf(g_log_fp,"%s: " ,timebuf); + vfprintf(g_log_fp,format,args); + (void) fflush(g_log_fp); + va_end(args); +} + +void close_log(void) +{ + if (g_log_fp != NULL) + { + (void) fclose(g_log_fp); + g_log_fp = NULL; + } +} + +void exit_ok(void) +{ + close_log(); + exit(0); +} + +void exit_error(void) +{ + close_log(); + exit(1); } @@ -188,6 +339,7 @@ int validateMusts(char *from,char *to,char *smtp_server,char *helo_domain) char *askFor(char *buf,int buflen,char *label,int ask) { + char *s; if (label == NULL || *label == '\0') return (NULL); @@ -195,13 +347,13 @@ char *askFor(char *buf,int buflen,char *label,int ask) again: if (isInConsole(_fileno(stdin))) { - (void) fprintf(stdout,label); + (void) fprintf(stdout,"%s",label); (void) fflush(stdout); (void) fflush(stderr); } - (void) fgets(buf,buflen,stdin); - if (*buf == '\0' || *buf == '\n') + s = fgets(buf,buflen,stdin); + if (s == NULL || *buf == '\0' || *buf == '\n') { if (ask == EMPTY_NOT_OK) goto again; @@ -259,11 +411,13 @@ int get_filepath_mimetype(char *str,char *filepath,int fp_size,char *mype_type,i { int + separator, rc=0; char *fp, *mt; - if ((mt=strchr(str,ATTACHMENT_SEP))) + separator = *g_attach_sep; + if ((mt=strchr(str,separator))) { *mt++='\0'; } @@ -272,11 +426,11 @@ int get_filepath_mimetype(char *str,char *filepath,int fp_size,char *mype_type,i errorMsg("Could not determine mime-type from input: %s\n",str); return(-1); } - mutilsSafeStrcpy(mype_type,mt,mt_size); + mutilsSafeStrcpy(mype_type,mt,mt_size-1); /* get the filepath out */ fp=str; - mutilsSafeStrcpy(filepath,fp,fp_size); + mutilsSafeStrcpy(filepath,fp,fp_size-1); return(rc); } @@ -289,6 +443,7 @@ void initialize_openssl(char *cipher) SSL_library_init(); SSL_load_error_strings(); RAND_seed(rnd_seed,sizeof(rnd_seed)); + OpenSSL_add_all_algorithms(); ssl_ctx=SSL_CTX_new(SSLv23_client_method()); if (ssl_ctx == NULL) { @@ -403,11 +558,15 @@ int rfc822_date(time_t when,char *datebuf,int bufsiz) /* ** return 0 on success, -1 on failure +** super simple naive funtion to detect if a file is +** binary or not.. it's just to prevent attaching binary file +** if no encoding type is specified. It's not a simple task +** to detect if a file is binary or not correctly. */ int guess_file_type(char *file,unsigned int *flag) { char - buf[BUFSIZ]; + buf[513]; int i, @@ -474,6 +633,7 @@ ExitProcessing: } +/* static int unix2dos(FILE *ifp,FILE *ofp) { int @@ -489,7 +649,7 @@ static int unix2dos(FILE *ifp,FILE *ofp) return(-1); #ifdef WINNT _setmode(_fileno(ofp),_O_BINARY); -#endif /* WINNT */ +#endif while(!feof(ifp)) { n=fread(buf,1,BUFSIZ,ifp); @@ -513,7 +673,82 @@ static int unix2dos(FILE *ifp,FILE *ofp) } } } +*/ +void print_copyright(void) +{ + char + **p; + + for (p = mailsend_copyright; *p != NULL; p++) + { + (void) fprintf(stdout,"%s\n",*p); + } + (void) fflush(stdout); +} + +/* +** Return the MIME type of the file +** Parameters: +** path - path of the file +** Return Values: +** mime type +** Side Effects: +** none +** Comments: +** If no extension is found, "text/plain" will be returned +** Development History: +*/ +char *get_mime_type(char *path) +{ + char + *npath = NULL, + *ext = NULL; + + char + *text_plain = "text/plain"; + int + i; + + if (path == NULL || *path == '\0') + { + return(text_plain); + } + + /* Issue #140. path was modified */ + npath = xStrdup(path); + ext = mutilsExtensionLower(npath); + for (i=0; i < sizeof(s_mime_type)/sizeof(*s_mime_type); i++) + { + if (strcmp(s_mime_type[i].ext, ext) == 0) + { + if (npath != NULL) + { + (void) free((char *) npath); + } + return (s_mime_type[i].val); + } + } + if (npath != NULL) + { + (void) free((char *) npath); + } + + return(text_plain); +} + +void show_mime_types() +{ + int + i; + for (i=0; i < sizeof(s_mime_type)/sizeof(*s_mime_type); i++) + { + (void) fprintf(stdout,"%s\t%s\n", + s_mime_type[i].val, + s_mime_type[i].ext); + } + +} #ifdef HAVE_OPENSSL void print_cert_info(SSL *ssl) @@ -576,8 +811,19 @@ char *encode_cram_md5(char *challenge,char *user,char *secret) unsigned char hmac_md5[16]; +#ifdef LIBRESSL_VERSION_NUMBER HMAC_CTX ctx; +#else +#if OPENSSL_VERSION_NUMBER < 0x10100000L + HMAC_CTX + ctx; +#else + /* OpenSSL 1.1.x*/ + HMAC_CTX + *ctx; +#endif +#endif const EVP_MD *md5=NULL; @@ -591,9 +837,10 @@ char *encode_cram_md5(char *challenge,char *user,char *secret) char *b64; + /* unsigned long b64len=0; - + */ char hex[33], buf[BUFSIZ]; @@ -602,22 +849,41 @@ char *encode_cram_md5(char *challenge,char *user,char *secret) secret == NULL || *secret == '\0') return(NULL); + showVerbose("Server Challenge: %s\n",challenge); OpenSSL_add_all_digests(); /* decode the challenge */ - data=mutils_decode_base64(challenge,strlen(challenge),&data_len); + data=mutils_decode_base64((unsigned char *) challenge,strlen(challenge),&data_len); if (data == NULL) { errorMsg("Could not base64 decode CRAM-MD5 challenge: %s",challenge); return(NULL); } + showVerbose("Challenge After decoding: %s\n",data); /* take HMAC-MD5 of the challenge*/ + +#ifdef LIBRESSL_VERSION_NUMBER md5=EVP_get_digestbyname("md5"); HMAC_CTX_init(&ctx); HMAC_Init(&ctx,secret,strlen(secret),md5); HMAC_Update(&ctx,data,data_len); HMAC_Final(&ctx,hmac_md5,&hmac_len); +#else +#if OPENSSL_VERSION_NUMBER < 0x10100000L + md5=EVP_get_digestbyname("md5"); + HMAC_CTX_init(&ctx); + HMAC_Init(&ctx,secret,strlen(secret),md5); + HMAC_Update(&ctx,data,data_len); + HMAC_Final(&ctx,hmac_md5,&hmac_len); +#else + /* OpenSSL 1.1.x */ + ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx,secret,strlen(secret),EVP_md5(),NULL); + HMAC_Update(ctx,data,data_len); + HMAC_Final(ctx,hmac_md5,&hmac_len); +#endif +#endif /* LIBRESSL_VERSION_NUMBER */ /* convert the digest to hex */ memset(hex,0,sizeof(hex)); @@ -625,22 +891,36 @@ char *encode_cram_md5(char *challenge,char *user,char *secret) { (void) sprintf(hex+2*i,"%02x",hmac_md5[i]); } + showVerbose("HMAC-MD5 of challenge: %s\n",hex); (void) snprintf(buf,sizeof(buf)-1,"%s %s",user,hex); + showVerbose("base64 encode: %s\n",buf); + showVerbose("Taking base64 of \"%s\"\n",buf); /* base64 encode "user hex_digest" */ - b64=mutils_encode_base64(buf,strlen(buf),&b64len); +#if 0 + b64=mutils_encode_base64((unsigned char *) buf,strlen(buf),&b64len); if (b64len <= 0) return(NULL); /* mutils_encode_base64 adds CRLF */ if (b64len > 2) b64[b64len-2]='\0'; +#endif + b64 = mutils_encode_base64_noformat(buf,strlen(buf)); + if (b64 == NULL) + { + errorMsg("Could not base64 encode: %s",buf); + return (NULL); + } + showVerbose("base64: %s\n",b64); + return(b64); } #else char *encode_cram_md5(char *challenge,char *user,char *secret) { - errorMsg("Must be compiled with OpenSSL in order to get CRAM-MD5 support\n"); + errorMsg("Must be compiled with OpenSSL in order to get CRAM-MD5 support\n"); return(NULL); } #endif /* HAVE_OPENSSL */ +