sympa-6.2.24/ 0000755 0001750 0001750 00000000000 13216651447 011703 5 ustar racke racke sympa-6.2.24/src/ 0000755 0001750 0001750 00000000000 13216651447 012472 5 ustar racke racke sympa-6.2.24/src/Sympa/ 0000755 0001750 0001750 00000000000 13216651447 013563 5 ustar racke racke sympa-6.2.24/src/Sympa/Extractor.pm 0000644 0001750 0001750 00000002210 13216651447 016067 0 ustar racke racke package Sympa::Extractor;
use strict;
use base qw(Locale::Maketext::Extract::Plugin::Base);
our $VERSION = '0.1';
=head1 NAME
Sympa::Extractor - Sympa plugin for Locale::Maketext::Extract
=head1 SYNOPSIS
$plugin = Sympa::Extractor->new(
$lexicon # A Locale::Maketext::Extract object
@file_types # Optionally specify a list of recognised file types
)
$plugin->extract($filename,$filecontents);
=head1 DESCRIPTION
Extracts strings to localise from List.pm and scenarios files
=head1 VALID FORMATS
gettext_id entries from List.pm, and title.gettext entries from scenarios are
extracted.
=head1 KNOWN FILE TYPES
=over 4
=item All file types
=back
=cut
sub file_types {
return qw( * );
}
sub extract {
my $self = shift;
local $_ = shift;
my $count = 1;
foreach my $line (split(/\n/, $_)) {
# scenarios
if ($line =~ /^title.gettext\s+(.+)$/) {
$self->add_entry($1, $count, '');
}
# List.pm
if ($line =~ /'gettext_id'\s+=>\s+(["'])(.+)\1/) {
$self->add_entry($2, $count, '');
}
$count++;
}
}
1;
sympa-6.2.24/src/smtpc/ 0000755 0001750 0001750 00000000000 13216651447 013620 5 ustar racke racke sympa-6.2.24/src/smtpc/utf8.c 0000644 0001750 0001750 00000011036 13216651447 014653 0 ustar racke racke /* $Id$ */
/*
* Sympa - SYsteme de Multi-Postage Automatique
*
* Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
* Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* utf8_check was originally taken from UTF8.xs in Unicode-UTF8 module by
* Christian Hansen distributed under Perl 5 License:
* .
*
* Copyright 2011-2012 by Christian Hansen.
*/
#include "config.h"
#include
#include
#if SIZEOF_UNSIGNED_INT >= 4
typedef unsigned int unichar_t;
#elif SIZEOF_UNSIGNED_LONG >= 4
typedef unsigned long unichar_t;
#else
#error "Integral types on your system are too short"
#endif
static const unsigned char utf8_sequence_len[0x100] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00-0x0F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10-0x1F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x20-0x2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x30-0x3F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40-0x4F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50-0x5F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60-0x6F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70-0x7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0-0xAF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0-0xBF */
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xC0-0xCF */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xD0-0xDF */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xE0-0xEF */
4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0-0xFF */
};
/** Check string
* Check if the string consists of valid UTF-8 sequence.
* @param[in] s Buffer.
* @param[in] len Length of buffer.
* @returns If the buffer contains only ASCII characters, -1.
* Else if the buffer contains non-ASCII sequence not forming valid UTF-8,
* index of the first position such sequence appears.
* Otherwise, length of the buffer.
*/
ssize_t utf8_check(const unsigned char *s, const size_t len)
{
const unsigned char *p = s;
const unsigned char *e = s + len;
const unsigned char *e4 = e - 4;
unichar_t v;
int is_asciionly = 1; /* Added to check if non-ASCII is included. */
while (p < e4) {
while (p < e4 && *p < 0x80)
p++;
check:
switch (utf8_sequence_len[*p]) {
case 0:
goto done;
case 1:
p += 1;
break;
case 2:
/* 110xxxxx 10xxxxxx */
if ((p[1] & 0xC0) != 0x80)
goto done;
p += 2;
is_asciionly = 0;
break;
case 3:
v = ((unichar_t) p[0] << 16)
| ((unichar_t) p[1] << 8)
| ((unichar_t) p[2]);
/* 1110xxxx 10xxxxxx 10xxxxxx */
if ((v & 0x00F0C0C0) != 0x00E08080 ||
/* Non-shortest form */
v < 0x00E0A080 ||
/* Surrogates U+D800..U+DFFF */
(v & 0x00EFA080) == 0x00EDA080 ||
/* Non-characters U+FDD0..U+FDEF, U+FFFE..U+FFFF */
(v >= 0x00EFB790 && (v <= 0x00EFB7AF || v >= 0x00EFBFBE)))
goto done;
p += 3;
is_asciionly = 0;
break;
case 4:
v = ((unichar_t) p[0] << 24)
| ((unichar_t) p[1] << 16)
| ((unichar_t) p[2] << 8)
| ((unichar_t) p[3]);
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
if ((v & 0xF8C0C0C0) != 0xF0808080 ||
/* Non-shortest form */
v < 0xF0908080 ||
/* Greater than U+10FFFF */
v > 0xF48FBFBF ||
/* Non-characters U+nFFFE..U+nFFFF on plane 1-16 */
(v & 0x000FBFBE) == 0x000FBFBE)
goto done;
p += 4;
is_asciionly = 0;
break;
}
}
if (p < e && p + utf8_sequence_len[*p] <= e)
goto check;
done:
if (p == e && is_asciionly)
return -1;
else
return p - s;
}
sympa-6.2.24/src/smtpc/sockstr.c 0000644 0001750 0001750 00000036034 13216651447 015462 0 ustar racke racke /* $Id$ */
/*
* Sympa - SYsteme de Multi-Postage Automatique
*
* Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
* Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* sockstr.c was originally written by IKEDA Soji
* as a part of smtpc utility for Sympa project.
*
* 2015-05-17 IKEDA Soji: Initial checkin to source repository.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "sockstr.h"
/** Constructor
* Creats new instance of sockstr object.
* @param[in] nodename Hostname of the server. Default is "localhost".
* @param[in] servname Port number or service name. Default is "smtp".
* @returns New instance.
* If error occurred, sets errno and returns NULL.
*/
sockstr_t *sockstr_new(char *nodename, char *servname, char *path)
{
sockstr_t *self;
self = (sockstr_t *) malloc(sizeof(sockstr_t));
if (self == NULL)
return NULL;
self->_errstr[0] = '\0';
self->_sock = -1;
self->_bufcnt = 0;
self->_bufptr = self->_buf;
self->timeout = 300;
if (path != NULL && *path) {
self->path = strdup(path);
if (self->path == NULL) {
free(self);
return NULL;
}
self->nodename = NULL;
self->servname = NULL;
} else {
self->path = NULL;
if (!nodename || !*nodename)
nodename = "localhost";
if (!servname || !*servname)
servname = "25";
self->nodename = strdup(nodename);
self->servname = strdup(servname);
if (self->nodename == NULL || self->servname == NULL) {
if (self->nodename != NULL)
free(self->nodename);
if (self->servname != NULL)
free(self->servname);
free(self);
return NULL;
}
}
return self;
}
/** Destructor
* Unallocate memory for the instance.
* @retuns None.
*/
void sockstr_destroy(sockstr_t * self)
{
if (self == NULL)
return;
if (0 <= self->_sock) {
shutdown(self->_sock, SHUT_RDWR);
close(self->_sock);
}
if (self->nodename != NULL)
free(self->nodename);
if (self->servname != NULL)
free(self->servname);
if (self->path != NULL)
free(self->path);
free(self);
}
static void sockstr_set_error(sockstr_t * self, int errnum,
const char *errstr)
{
self->_errnum = errnum;
if (errstr == NULL) {
char *buf;
buf = strerror(errnum);
if (buf == NULL)
snprintf(self->_errstr, SOCKSTR_ERRSIZE, "(%d) Error", errnum);
else
snprintf(self->_errstr, SOCKSTR_ERRSIZE, "(%d) %s", errnum,
buf);
} else
snprintf(self->_errstr, SOCKSTR_ERRSIZE, "(%d) %s", errnum,
errstr);
}
/** Last error
* Gets error by the last operation.
* @returns String, or if the last operation was success, NULL.
*/
char *sockstr_errstr(sockstr_t * self)
{
return self->_errstr;
}
static int _connect_socket(sockstr_t * self, int sock,
struct sockaddr *ai_addr, socklen_t ai_addrlen,
int blocking)
{
long flags;
flags = fcntl(sock, F_GETFL, NULL);
if (flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
}
if (connect(sock, ai_addr, ai_addrlen) < 0) {
if (errno == EINPROGRESS) {
struct timeval tv;
fd_set rfd, wfd;
int rc, errnum;
socklen_t errlen;
do {
tv.tv_sec = self->timeout;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(sock, &rfd);
wfd = rfd;
rc = select(sock + 1, &rfd, &wfd, NULL, &tv);
} while (rc < 0 && errno == EINTR);
if (rc == 0) {
sockstr_set_error(self, ETIMEDOUT, NULL);
return -1;
} else if (FD_ISSET(sock, &rfd) || FD_ISSET(sock, &wfd)) {
errlen = sizeof(errnum);
getsockopt(sock, SOL_SOCKET, SO_ERROR,
(void *) &errnum, &errlen);
if (errnum) {
sockstr_set_error(self, errnum, NULL);
return -1;
}
} else {
sockstr_set_error(self, errno, NULL);
return -1;
}
} else {
sockstr_set_error(self, errno, NULL);
return -1;
}
}
if (blocking) {
if (fcntl(sock, F_SETFL, flags) < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
}
}
return 0;
}
int socktcp_connect(sockstr_t * self)
{
struct addrinfo hints, *ai0, *ai;
int errnum;
int sock = -1;
if (0 <= self->_sock) {
sockstr_set_error(self, EISCONN, NULL);
return -1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
errnum = getaddrinfo(self->nodename, self->servname, &hints, &ai0);
if (errnum) {
sockstr_set_error(self, errnum, gai_strerror(errnum));
return -1;
}
for (ai = ai0; ai != NULL; ai = ai->ai_next) {
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock < 0) {
sockstr_set_error(self, errno, NULL);
continue;
}
if (_connect_socket(self, sock, ai->ai_addr, ai->ai_addrlen, 0) ==
0)
break;
close(sock);
sock = -1;
}
freeaddrinfo(ai0);
if (sock < 0)
return -1;
self->_sock = sock;
return 0;
}
int sockunix_connect(sockstr_t * self)
{
struct sockaddr_un sa_un; /* The name "sun" messes Solaris. */
size_t sunlen;
int sock = -1;
if (0 <= self->_sock) {
sockstr_set_error(self, EISCONN, NULL);
return -1;
}
if (self->path == NULL || self->path[0] == '\0') {
sockstr_set_error(self, EINVAL, NULL);
return -1;
}
sunlen = strlen(self->path);
if (sizeof(sa_un.sun_path) < sunlen + 1) {
sockstr_set_error(self, ENAMETOOLONG, NULL);
return -1;
}
memset(&sa_un, 0, sizeof(sa_un));
sa_un.sun_family = PF_UNIX;
memcpy(sa_un.sun_path, self->path, sunlen + 1);
/* I don't know any platforms need to set .sun_len member. */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
}
if (_connect_socket
(self, sock, (struct sockaddr *) &sa_un, sizeof(sa_un), 0) < 0) {
close(sock);
return -1;
}
self->_sock = sock;
return 0;
}
/** Connect
* Connects to the host.
* @returns 1 if success, otherwise 0.
* Description of error can be got by sockstr_errstr().
*/
int sockstr_client_connect(sockstr_t * self)
{
if (self->path != NULL)
return sockunix_connect(self);
else
return socktcp_connect(self);
}
static ssize_t sockstr_read(sockstr_t * self, char *buf, size_t count)
{
int cnt;
while (self->_bufcnt <= 0) {
self->_bufcnt = read(self->_sock, self->_buf, sizeof(self->_buf));
if (self->_bufcnt < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
int rc;
struct timeval tv;
fd_set wfd;
do {
tv.tv_sec = self->timeout;
tv.tv_usec = 0;
FD_ZERO(&wfd);
FD_SET(self->_sock, &wfd);
rc = select(self->_sock + 1, NULL, &wfd, NULL, &tv);
} while (rc < 0 && errno == EINTR);
if (rc < 0)
return -1;
else if (rc == 0) {
errno = ETIMEDOUT;
return -1;
}
} else if (errno != EINTR)
return -1;
} else if (self->_bufcnt == 0)
return 0;
else
self->_bufptr = self->_buf;
}
cnt = count;
if (self->_bufcnt < count)
cnt = self->_bufcnt;
memcpy(buf, self->_bufptr, cnt);
self->_bufptr += cnt;
self->_bufcnt -= cnt;
return cnt;
}
#define SOCKSTR_MIN_BUFSIZ (4)
#define SOCKSTR_DEFAULT_BUFSIZ (128)
/** Read one line
* Read one line termined by a newline (LF) from peer.
* @param[in,out] lineptr Pointer to buffer provided by user.
* @param[in,out] n Pointer to allocated size of buffer.
* @param[in] omitnul If true value is specified, ignores NUL octets (\0) in
* input.
* @returns Size of read data, 0 if socket is no longer readalbe
* or -1 on failure.
* lineptr and n may be changed.
*/
ssize_t sockstr_getline(sockstr_t * self, char **lineptr, size_t * n,
int omitnul)
{
ssize_t rs;
char chr, *p, *newbuf;
size_t len, newsiz;
if (self->_sock < 0 || lineptr == NULL || n == NULL) {
sockstr_set_error(self, EINVAL, NULL);
return -1;
}
p = *lineptr;
while (1) {
rs = sockstr_read(self, &chr, 1);
if (rs == 1) {
len = p - *lineptr;
if (*lineptr == NULL || *n < len + 2) {
if (*lineptr == NULL || *n < SOCKSTR_MIN_BUFSIZ)
newsiz = SOCKSTR_DEFAULT_BUFSIZ;
else
newsiz = *n << 1;
if (*lineptr == NULL)
newbuf = malloc(newsiz);
else
newbuf = realloc(*lineptr, newsiz);
if (newbuf == NULL) {
sockstr_set_error(self, errno, NULL);
return -1;
}
*lineptr = newbuf;
*n = newsiz;
p = *lineptr + len;
}
if (!omitnul || chr != '\0')
*p++ = chr;
if (chr == '\n')
break;
} else if (rs == 0) { /* Disconnected. */
if (p == *lineptr) { /* EOF */
sockstr_set_error(self, ECONNRESET, NULL);
return 0;
}
break;
} else {
sockstr_set_error(self, errno, NULL);
return -1;
}
}
*p = '\0';
return p - *lineptr;
}
/* Get status line(s)
* Read (one or more) status line(s) from peer.
* @param[in,out] lineptr Pointer to buffer provided by user.
* @oaram[in,out] n Pointer to allocated size of buffer.
* @returns Size of read data, 0 if socket is no longer readalbe
* or -1 on failure.
* lineptr and n may be changed.
* NUL octets (\0) in input are ignored.
*/
ssize_t sockstr_getstatus(sockstr_t * self, char **lineptr, size_t * n)
{
ssize_t rs;
char *buf = NULL, *newbuf;
size_t bufsiz = 0, newsiz, len = 0;
if (self->_sock < 0 || lineptr == NULL || n == NULL) {
sockstr_set_error(self, EINVAL, NULL);
return -1;
}
while (1) {
rs = sockstr_getline(self, &buf, &bufsiz, 1);
if (rs < 0) {
if (buf != NULL)
free(buf);
return -1;
} else if (rs == 0) { /* Disconnected. */
if (len == 0) { /* EOF */
sockstr_set_error(self, ECONNRESET, NULL);
if (buf != NULL)
free(buf);
return 0;
}
break;
} else {
if (*lineptr == NULL || *n < len + rs + 1) {
if (*lineptr == NULL || *n < SOCKSTR_DEFAULT_BUFSIZ)
newsiz = SOCKSTR_DEFAULT_BUFSIZ;
else
newsiz = *n;
while (newsiz < len + rs + 1)
newsiz <<= 1;
if (*lineptr == NULL)
newbuf = malloc(newsiz);
else
newbuf = realloc(*lineptr, newsiz);
if (newbuf == NULL) {
sockstr_set_error(self, errno, NULL);
if (buf != NULL)
free(buf);
return -1;
}
*n = newsiz;
*lineptr = newbuf;
}
memcpy(*lineptr + len, buf, rs + 1);
len += rs;
if (3 <= rs &&
'2' <= buf[0] && buf[0] <= '5' &&
'0' <= buf[1] && buf[1] <= '9' &&
'0' <= buf[2] && buf[2] <= '9') {
if (buf[3] != '-')
break;
} else {
sockstr_set_error(self, EINVAL, NULL);
if (buf != NULL)
free(buf);
return -1;
}
}
}
if (buf != NULL)
free(buf);
return len;
}
static ssize_t sockstr_write(sockstr_t * self, void *buf, size_t count)
{
size_t leftlen = count;
ssize_t rs;
char *p = buf;
while (leftlen > 0) {
rs = write(self->_sock, p, leftlen);
if (rs < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
int rc;
struct timeval tv;
fd_set rfd;
do {
tv.tv_sec = self->timeout;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(self->_sock, &rfd);
rc = select(self->_sock + 1, &rfd, NULL, NULL, &tv);
} while (rc < 0 && errno == EINTR);
if (rc < 0)
return -1;
else if (rc == 0) {
errno = ETIMEDOUT;
return -1;
}
} else if (errno != EINTR)
return -1;
} else {
leftlen -= rs;
p += rs;
}
}
return count;
}
/** Write formatted string
* Formats string according to format and write to peer.
* @param[in] format Format.
* @param[in] ap Arguments fed to vsnprintf(3).
* @returns Number of octets written.
*/
ssize_t sockstr_vprintf(sockstr_t * self, const char *format, va_list ap)
{
int rc;
ssize_t rs;
char *buf, *newbuf;
va_list ap_again;
buf = malloc(SOCKSTR_DEFAULT_BUFSIZ);
if (buf == NULL) {
sockstr_set_error(self, errno, NULL);
return -1;
}
va_copy(ap_again, ap);
rc = vsnprintf(buf, SOCKSTR_DEFAULT_BUFSIZ, format, ap);
if (rc < 0) {
sockstr_set_error(self, errno, NULL);
va_end(ap_again);
free(buf);
return -1;
} else if (SOCKSTR_DEFAULT_BUFSIZ < rc + 1) {
newbuf = realloc(buf, rc + 1);
if (newbuf == NULL) {
sockstr_set_error(self, errno, NULL);
va_end(ap_again);
free(buf);
return -1;
}
buf = newbuf;
rc = vsnprintf(buf, rc + 1, format, ap_again);
if (rc < 0) {
sockstr_set_error(self, errno, NULL);
va_end(ap_again);
free(buf);
return -1;
}
}
va_end(ap_again);
rs = sockstr_write(self, buf, rc);
if (rs < 0)
sockstr_set_error(self, errno, NULL);
free(buf);
return rs;
}
/** @todo doc
*
*/
ssize_t sockstr_printf(sockstr_t * self, const char *format, ...)
{
va_list ap;
ssize_t rs;
va_start(ap, format);
rs = sockstr_vprintf(self, format, ap);
va_end(ap);
return rs;
}
/** Write data to peer
* Writes data to peer.
* @param[in] buf Buffer including data.
* @param[in] count Size of data.
* @param[in] delim Delimiter appended to output.
* @param[in] fixnewline Whether newlines will be canonicalized or not.
* @param[in] fixdot Fix lines beginning with dot (.).
* @returns Number of octets written.
*/
ssize_t sockstr_putdata(sockstr_t * self, void *buf, size_t count,
char *delim, int fixnewline, int fixdot)
{
char *p, *q, *end;
ssize_t rs, len, linelen;
p = q = buf;
end = buf + count;
len = 0;
while (p < end) {
if (fixdot && *p == '.') {
rs = sockstr_write(self, ".", 1);
if (rs < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
} else
len += rs;
}
while (q < end)
if (*(q++) == '\n')
break;
if (fixnewline) {
if ((p + 1 == q && q[-1] == '\n') ||
q[-1] == '\r' ||
(p + 1 < q && q[-2] != '\r' && q[-1] == '\n'))
linelen = q - p - 1;
else if (q[-1] != '\n')
linelen = q - p;
else
linelen = q - p - 2;
} else
linelen = q - p;
rs = sockstr_write(self, p, linelen);
if (rs < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
} else
len += rs;
if (fixnewline) {
rs = sockstr_write(self, "\r\n", 2);
if (rs < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
} else
len += rs;
}
p = q;
}
if (delim != NULL && *delim != '\0') {
rs = sockstr_write(self, delim, strlen(delim));
if (rs < 0) {
sockstr_set_error(self, errno, NULL);
return -1;
} else
len += rs;
}
return len;
}
sympa-6.2.24/src/smtpc/configure.ac 0000644 0001750 0001750 00000002255 13216651447 016112 0 ustar racke racke # -*- Autoconf -*-
# $Id$
AC_PREREQ([2.59])
AC_INIT([smtpc], [0.3], [sympa-developpers@listes.renater.fr])
AM_INIT_AUTOMAKE([foreign -Wall -Werror 1.9 tar-pax])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS([config.h])
# Check options
# If you bundle me in other package, use --disable-smtpc not to build me.
AC_ARG_ENABLE(
smtpc, [],
[case "$enableval" in
yes) smtpc=true;;
no) smtpc=false;;
*) smtpc=true;;
esac],
[smtpc=true]
)
# Checks for programs.
AC_PROG_CC
if test x$smtpc = xtrue; then
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([fcntl.h netdb.h stdlib.h string.h sys/socket.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_CHECK_SIZEOF([unsigned int])
AC_CHECK_SIZEOF([unsigned long])
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([memset select socket strdup strerror])
AC_FUNC_SNPRINTF
AC_CHECK_FUNC([getaddrinfo], [],
[AC_CHECK_LIB([socket], [getaddrinfo], [LIBS="-lsocket -lnsl $LIBS"], [],
[-lnsl])])
fi
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
sympa-6.2.24/src/smtpc/sockstr.h 0000644 0001750 0001750 00000003572 13216651447 015470 0 ustar racke racke /* $Id$ */
/*
* Sympa - SYsteme de Multi-Postage Automatique
*
* Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
* Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#define SOCKSTR_ERRSIZE (128)
#define SOCKSTR_BUFSIZE (8192)
typedef struct {
char *nodename;
char *servname;
char *path;
int timeout;
int _sock;
int _errnum;
char _errstr[SOCKSTR_ERRSIZE];
ssize_t _bufcnt;
char *_bufptr;
char _buf[SOCKSTR_BUFSIZE];
} sockstr_t;
extern sockstr_t *sockstr_new(char *, char *, char *);
extern void sockstr_destroy(sockstr_t *);
extern char *sockstr_errstr(sockstr_t *);
extern int sockstr_client_connect(sockstr_t *);
extern ssize_t sockstr_getline(sockstr_t *, char **, size_t *, int);
extern ssize_t sockstr_getstatus(sockstr_t *, char **, size_t *);
extern ssize_t sockstr_vprintf(sockstr_t *, const char *, va_list);
extern ssize_t sockstr_printf(sockstr_t *, const char *, ...);
extern ssize_t sockstr_putdata(sockstr_t *, void *, size_t, char *, int,
int);
sympa-6.2.24/src/smtpc/smtpc.c 0000644 0001750 0001750 00000051012 13216651447 015111 0 ustar racke racke /* $Id$ */
/*
* Sympa - SYsteme de Multi-Postage Automatique
*
* Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel
* Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
* Copyright 2017 The Sympa Community. See the AUTHORS.md file at the top-level
* directory of this distribution and at
* .
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* smtpc was originally written by IKEDA Soji
* for Sympa project.
*
* 2015-05-17 IKEDA Soji: Initial checkin to source repository.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "sockstr.h"
#include "utf8.h"
#define SMTPC_BUFSIZ (8192)
#define SMTPC_ERR_SOCKET (255)
#define SMTPC_ERR_PROTOCOL (254)
#define SMTPC_ERR_SUBMISSION (253)
#define SMTPC_ERR_UNKNOWN (252)
#define SMTPC_7BIT (0)
#define SMTPC_8BIT (1)
#define SMTPC_UTF8 (2)
#define SMTPC_PROTO_TCP (1)
#define SMTPC_PROTO_UNIX (1 << 1)
#define SMTPC_PROTO_ESMTP (1 << 2)
#define SMTPC_PROTO_LMTP (1 << 3)
#define SMTPC_EXT_8BITMIME (1)
#define SMTPC_EXT_AUTH (1 << 1)
#define SMTPC_EXT_DSN (1 << 2)
#define SMTPC_EXT_PIPELINING (1 << 3)
#define SMTPC_EXT_SIZE (1 << 4)
#define SMTPC_EXT_SMTPUTF8 (1 << 5)
#define SMTPC_EXT_STARTTLS (1 << 6)
#define SMTPC_NOTIFY_NEVER (1)
#define SMTPC_NOTIFY_SUCCESS (1 << 1)
#define SMTPC_NOTIFY_FAILURE (1 << 2)
#define SMTPC_NOTIFY_DELAY (1 << 3)
static char buf[SMTPC_BUFSIZ];
static sockstr_t *sockstr;
static struct {
int dump;
int verbose;
unsigned int protocol;
char *myname;
char *nodename;
char *servname;
char *path;
char *sender;
unsigned int notify;
char *envid;
int smtputf8;
} options = {
0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0};
static struct {
char **recips;
int recipnum;
char *buf;
size_t buflen;
size_t size;
int envfeature;
int headfeature;
int bodyfeature;
} message = {
NULL, 0, NULL, 0, 0, 0, 0};
static struct {
char *buf;
size_t buflen;
unsigned long extensions;
} server = {
NULL, 0, 0};
static char *encode_xtext(unsigned char *str)
{
unsigned char *p;
char *encbuf, *q;
size_t enclen = 0;
p = str;
while (*p != '\0') {
if (*p == '+' || *p == '=')
enclen += 3;
else if (33 <= *p && *p <= 126)
enclen++;
else
enclen += 3;
p++;
}
encbuf = malloc(enclen + 1);
if (encbuf == NULL)
return NULL;
p = str;
q = encbuf;
while (*p != '\0') {
if (*p == '+' || *p == '=')
q += sprintf(q, "+%02X", (unsigned int) *p);
else if (33 <= *p && *p <= 126)
*q++ = *p;
else
q += sprintf(q, "+%02X", (unsigned int) *p);
p++;
}
*q = '\0';
return encbuf;
}
static char *encode_unitext(unsigned char *str)
{
unsigned char *p;
char *encbuf, *q;
size_t enclen = 0;
p = str;
while (*p != '\0') {
if (*p == '\\' || *p == '+' || *p == '=')
enclen += 6;
else if ((33 <= *p && *p <= 126) || 128 <= *p)
enclen++;
else
enclen += 6;
p++;
}
encbuf = malloc(enclen + 1);
if (encbuf == NULL)
return NULL;
p = str;
q = encbuf;
while (*p != '\0') {
if (*p == '\\' || *p == '+' || *p == '=')
q += sprintf(q, "\\x{%02X}", (unsigned int) *p);
else if ((33 <= *p && *p <= 126) || 128 <= *p)
*q++ = *p;
else
q += sprintf(q, "\\x{%02X}", (unsigned int) *p);
p++;
}
*q = '\0';
return encbuf;
}
static int parse_options(int *argcptr, char ***argvptr)
{
int argc = *argcptr;
char **argv = *argvptr;
size_t i;
char *arg, *p;
options.dump = 0;
options.verbose = 0;
options.protocol = 0;
options.myname = "localhost";
options.nodename = NULL;
options.servname = NULL;
options.sender = NULL;
options.notify = 0;
options.envid = NULL;
options.smtputf8 = 0;
for (i = 1; i < argc && argv[i] != NULL; i++) {
arg = argv[i];
if (arg[0] != '-')
break;
else if (arg[0] == '-' && arg[1] == '-') {
if (arg[2] == '\0') {
i++;
break;
} else if (strcmp(arg, "--dump") == 0)
options.dump++;
else if (strcmp(arg, "--esmtp") == 0 && i + 1 < argc) {
if (options.protocol != 0) {
fprintf(stderr, "Multiple servers are specified\n");
return -1;
}
options.protocol = SMTPC_PROTO_TCP | SMTPC_PROTO_ESMTP;
arg = argv[++i];
if (arg[0] == '[') {
p = options.nodename = arg + 1;
while (*p != '\0' && *p != ']')
p++;
if (*p == ']' && options.nodename < p)
*p++ = '\0';
else {
fprintf(stderr, "Malformed host \"%s\"\n", arg);
return -1;
}
if (*p == ':' && *(++p) != '\0')
options.servname = p;
else if (*p != '\0') {
fprintf(stderr, "Malformed port \"%s\"\n", p);
return -1;
} else
options.servname = "25";
} else {
p = options.nodename = arg;
while (*p != '\0' && *p != ':')
p++;
if (*p == ':' && options.nodename < p)
*p++ = '\0';
if (*p != '\0')
options.servname = p;
else
options.servname = "25";
}
} else if (strcmp(arg, "--iam") == 0 && i + 1 < argc)
options.myname = argv[++i];
else if (strcmp(arg, "--lmtp") == 0 && i + 1 < argc) {
if (options.protocol != 0) {
fprintf(stderr, "Multiple servers are specified\n");
return -1;
}
options.protocol = SMTPC_PROTO_LMTP;
arg = argv[++i];
if (arg[0] == '/') {
options.protocol |= SMTPC_PROTO_UNIX;
options.path = arg;
} else if (arg[0] == '[') {
options.protocol |= SMTPC_PROTO_TCP;
p = options.nodename = arg + 1;
while (*p != '\0' && *p != ']')
p++;
if (*p == ']' && options.nodename < p)
*p++ = '\0';
else {
fprintf(stderr, "Malformed host \"%s\"\n", arg);
return -1;
}
if (*p == ':' && *(++p) != '\0')
options.servname = p;
else if (*p != '\0') {
fprintf(stderr, "Malformed port \"%s\"\n", p);
return -1;
} else
options.servname = "24";
} else {
options.protocol |= SMTPC_PROTO_TCP;
p = options.nodename = arg;
while (*p != '\0' && *p != ':')
p++;
if (*p == ':' && options.nodename < p)
*p++ = '\0';
if (*p != '\0')
options.servname = p;
else
options.servname = "24";
}
} else if (strcmp(arg, "--smtputf8") == 0)
options.smtputf8 = 1;
else if (strcmp(arg, "--verbose") == 0)
options.verbose++;
}
switch (arg[1]) {
case 'f':
if (options.sender != NULL) {
fprintf(stderr, "Multiple senders are specified\n");
return -1;
}
if (arg[2] == '\0' && i + 1 < argc)
options.sender = argv[++i];
else if (arg[2] != '\0')
options.sender = arg + 2;
else
goto parse_options_novalue;
if (strcmp(options.sender, "<>") == 0)
options.sender += 2;
break;
case 'N':
if (arg[2] == '\0' && i + 1 < argc)
p = argv[++i];
else if (arg[2] != '\0')
p = arg + 2;
else
goto parse_options_novalue;
while (*p != '\0') {
char word[29], *wp;
wp = word;
while (*p == '\t' || *p == ' ' || *p == ',')
p++;
if (*p == '\0')
break;
while (*p != '\0' && *p != '\t' && *p != ' ' && *p != ','
&& wp - word + 1 < sizeof(word))
if ('a' <= *p && *p <= 'z')
*wp++ = *p++ + ('A' - 'a');
else
*wp++ = *p++;
*wp = '\0';
if (strcmp(word, "NEVER") == 0) {
options.notify |= SMTPC_NOTIFY_NEVER;
} else if (strcmp(word, "SUCCESS") == 0)
options.notify |= SMTPC_NOTIFY_SUCCESS;
else if (strcmp(word, "FAILURE") == 0)
options.notify |= SMTPC_NOTIFY_FAILURE;
else if (strcmp(word, "DELAY") == 0)
options.notify |= SMTPC_NOTIFY_DELAY;
else {
fprintf(stderr, "Unknown NOTIFY keyword \"%s\"\n",
word);
return -1;
}
if (options.notify & SMTPC_NOTIFY_NEVER &&
options.notify & ~SMTPC_NOTIFY_NEVER) {
fprintf(stderr,
"NEVER keyword must not appear with other keywords\n");
return -1;
}
}
break;
case 'V':
if (arg[2] == '\0' && i + 1 < argc)
options.envid = argv[++i];
else if (arg[2] != '\0')
options.envid = arg + 2;
else
goto parse_options_novalue;
p = options.envid;
while (*p != '\0')
if (32 <= *p && *p <= 126)
p++;
else {
fprintf(stderr,
"ENVID contains illegal character \\x%02X\n",
*p);
return -1;
}
break;
default:
break;
parse_options_novalue:
fprintf(stderr, "No value for option \"%s\"\n", arg);
return -1;
}
}
if ((options.protocol & (SMTPC_PROTO_ESMTP | SMTPC_PROTO_LMTP)) == 0) {
fprintf(stderr, "Either --esmtp or --lmtp option must be given\n");
return -1;
}
if ((options.protocol & SMTPC_PROTO_TCP && options.nodename == NULL)
|| (options.protocol & SMTPC_PROTO_UNIX && options.path == NULL)) {
fprintf(stderr, "Nodename nor path is not specified\n");
return -1;
}
if (options.sender == NULL) {
fprintf(stderr, "Envelope sender is not specified\n");
return -1;
}
*argcptr -= i;
*argvptr += i;
return 0;
}
static int check_utf8_address(char *addrbuf)
{
size_t len;
ssize_t rs;
len = strlen(addrbuf);
if (len == 0)
return SMTPC_7BIT;
rs = utf8_check((unsigned char *) addrbuf, len);
if (rs < 0)
return SMTPC_7BIT;
else if (rs < len)
return SMTPC_8BIT;
else
return SMTPC_UTF8;
}
static int read_envelope(char *sender, size_t recipnum, char **recips)
{
char **pp, **end;
if (recipnum <= 0) {
fprintf(stderr, "No recipients are specified\n");
return -1;
}
message.recipnum = recipnum;
message.recips = recips;
/*
* Check feature of sender.
*/
message.envfeature = check_utf8_address(sender);
/*
* Check feature of recipients.
*/
end = recips + recipnum;
for (pp = recips;
message.envfeature != SMTPC_8BIT && pp < end && *pp != NULL; pp++)
switch (check_utf8_address(*pp)) {
case SMTPC_8BIT:
message.envfeature = SMTPC_8BIT;
break;
case SMTPC_UTF8:
message.envfeature = SMTPC_UTF8;
break;
default:
break;
}
return 0;
}
static ssize_t read_message(void)
{
size_t cr;
ssize_t rs;
char *newbuf, *p, *end;
while (1) {
rs = fread(buf, 1, SMTPC_BUFSIZ, stdin);
if (rs == 0)
break;
if (message.buf == NULL) {
message.buf = malloc(rs + 1);
if (message.buf == NULL)
return -1;
} else {
newbuf = realloc(message.buf, message.buflen + rs + 1);
if (newbuf == NULL)
return -1;
message.buf = newbuf;
}
memcpy(message.buf + message.buflen, buf, rs);
message.buflen += rs;
message.buf[message.buflen] = '\0';
if (rs < SMTPC_BUFSIZ)
break;
}
if (feof(stdin)) {
if (fclose(stdin) != 0)
return -1;
} else {
fclose(stdin);
return -1;
}
/*
* Check message features:
* - Feature of message header.
* - Feature of message body.
* - Estimated size of the message considering newlines.
*/
cr = 0;
message.headfeature = SMTPC_7BIT;
message.bodyfeature = SMTPC_7BIT;
if (0 < message.buflen) {
end = message.buf + message.buflen;
for (p = message.buf; p < end; p++)
if (*p == '\n') {
if (p == message.buf || p[-1] != '\r')
cr++;
if (p[1] == '\n' || (p[1] == '\r' && p[2] == '\n')) {
p++;
break;
}
}
rs = utf8_check((unsigned char *) message.buf, p - message.buf);
if (rs < 0)
message.headfeature = SMTPC_7BIT;
else if (rs < p - message.buf)
message.headfeature = SMTPC_8BIT;
else
message.headfeature = SMTPC_UTF8;
for (; p < end; p++)
if (*p & 0x80) {
message.bodyfeature = SMTPC_8BIT;
p++;
break;
} else if (*p == '\n' && p[-1] != '\r')
cr++;
for (; p < end; p++)
if (*p == '\n' && p[-1] != '\r')
cr++;
if (end[-1] == '\r')
cr++;
else if (end[-1] != '\n')
cr += 2;
} else
cr = 2;
message.size = message.buflen + cr;
return message.buflen;
}
static int dialog(int timeout, const char *format, ...)
{
va_list ap;
ssize_t rs;
sockstr->timeout = timeout;
if (format != NULL && *format != '\0') {
if (options.dump) {
fprintf(stderr, "C: ");
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
va_start(ap, format);
rs = sockstr_vprintf(sockstr, format, ap);
va_end(ap);
if (rs < 0)
return -1;
}
rs = sockstr_getstatus(sockstr, &server.buf, &server.buflen);
if (rs <= 0)
return -1;
if (options.dump)
fprintf(stderr, "%s", server.buf);
return server.buf[0];
}
static int datasend(int timeout)
{
ssize_t rs;
sockstr->timeout = timeout;
if (options.dump)
fprintf(stderr, "C: (MESSAGE)\r\nC: .\r\n");
if (sockstr_putdata
(sockstr, message.buf, message.buflen, ".\r\n", 1, 1) < 0)
return -1;
rs = sockstr_getstatus(sockstr, &server.buf, &server.buflen);
if (rs <= 0)
return -1;
if (options.dump)
fprintf(stderr, "%s", server.buf);
return server.buf[0];
}
static void parse_extensions(void)
{
char *p = server.buf;
unsigned long extensions = 0L;
char word[512], *wp;
while (*p != '\n' && *p != '\0')
p++;
if (*p == '\n')
p++;
while (*p != '\0') {
if (p[0] && p[1] && p[2] && p[3]) {
p += 4;
while (*p == '\t' || *p == ' ' || *p == '-')
p++;
if (*p == '\0')
break;
wp = word;
while (wp - word + 1 < sizeof(word) &&
(*p == '-' || ('0' <= *p && *p <= '9') ||
('A' <= *p && *p <= 'Z') || ('a' <= *p && *p <= 'z')))
if ('a' <= *p && *p <= 'z')
*wp++ = *p++ + ('A' - 'a');
else
*wp++ = *p++;
*wp = '\0';
if (strcmp(word, "8BITMIME") == 0)
extensions |= SMTPC_EXT_8BITMIME;
else if (strcmp(word, "AUTH") == 0)
extensions |= SMTPC_EXT_AUTH;
else if (strcmp(word, "DSN") == 0)
extensions |= SMTPC_EXT_DSN;
else if (strcmp(word, "PIPELINING") == 0)
extensions |= SMTPC_EXT_PIPELINING;
else if (strcmp(word, "SIZE") == 0)
extensions |= SMTPC_EXT_SIZE;
else if (strcmp(word, "SMTPUTF8") == 0)
extensions |= SMTPC_EXT_SMTPUTF8;
else if (strcmp(word, "STARTTLS") == 0)
extensions |= SMTPC_EXT_STARTTLS;
}
while (*p != '\n' && *p != '\0')
p++;
if (*p == '\n')
p++;
}
server.extensions = extensions;
}
static ssize_t transaction(void)
{
ssize_t sent = 0;
char *hello;
char *ext_8bitmime, ext_envid[108], ext_notify[37], ext_orcpt[508],
ext_size[27], *ext_smtputf8;
int i;
ext_8bitmime = "";
*ext_envid = '\0';
*ext_notify = '\0';
*ext_orcpt = '\0';
*ext_size = '\0';
ext_smtputf8 = "";
if (options.protocol & SMTPC_PROTO_ESMTP)
hello = "EHLO";
else if (options.protocol & SMTPC_PROTO_LMTP)
hello = "LHLO";
else
return SMTPC_ERR_UNKNOWN;
switch (dialog(300, "%s %s\r\n", hello, options.myname)) {
case '2':
break;
case '4':
case '5':
return 0;
case -1:
return SMTPC_ERR_SOCKET;
default:
return SMTPC_ERR_PROTOCOL;
}
parse_extensions();
if (server.extensions & SMTPC_EXT_8BITMIME &&
(message.headfeature != SMTPC_7BIT
|| message.bodyfeature != SMTPC_7BIT))
ext_8bitmime = " BODY=8BITMIME";
if (server.extensions & SMTPC_EXT_DSN) {
if (options.envid != NULL && options.envid[0] != '\0') {
char *encbuf;
encbuf = encode_xtext((unsigned char *) options.envid);
if (encbuf == NULL) {
perror("transaction");
return SMTPC_ERR_UNKNOWN;
}
snprintf(ext_envid, sizeof(ext_envid), " ENVID=%s", encbuf);
free(encbuf);
}
if (options.notify) {
unsigned int mask;
for (mask = 1; mask < (1 << 4); mask <<= 1) {
if (options.notify & mask) {
if (*ext_notify == '\0')
strcat(ext_notify, " NOTIFY=");
else
strcat(ext_notify, ",");
switch (mask) {
case SMTPC_NOTIFY_NEVER:
strcat(ext_notify, "NEVER");
break;
case SMTPC_NOTIFY_SUCCESS:
strcat(ext_notify, "SUCCESS");
break;
case SMTPC_NOTIFY_FAILURE:
strcat(ext_notify, "FAILURE");
break;
case SMTPC_NOTIFY_DELAY:
strcat(ext_notify, "DELAY");
break;
}
}
} /* for (mask ...) */
} /* if (options.notify & mask) */
}
if (server.extensions & SMTPC_EXT_SIZE)
snprintf(ext_size, sizeof(ext_size), " SIZE=%lu",
(unsigned long) message.size);
if (server.extensions & SMTPC_EXT_SMTPUTF8 &&
options.smtputf8 &&
((message.envfeature == SMTPC_UTF8
&& message.headfeature != SMTPC_8BIT)
|| (message.envfeature != SMTPC_8BIT
&& message.headfeature == SMTPC_UTF8)))
ext_smtputf8 = " SMTPUTF8";
switch (dialog(300, "MAIL FROM:<%s>%s%s%s%s\r\n", options.sender,
ext_8bitmime, ext_envid, ext_size, ext_smtputf8)) {
case '2':
break;
case '4':
case '5':
return 0;
case -1:
return SMTPC_ERR_SOCKET;
default:
return SMTPC_ERR_PROTOCOL;
}
for (i = 0; i < message.recipnum; i++) {
if (server.extensions & SMTPC_EXT_DSN) {
char *encbuf;
if (*ext_smtputf8) {
encbuf =
encode_unitext((unsigned char *) message.recips[i]);
if (encbuf == NULL) {
perror("transaction");
return SMTPC_ERR_UNKNOWN;
}
snprintf(ext_orcpt, sizeof(ext_orcpt), " ORCPT=utf-8;%s",
encbuf);
} else {
encbuf = encode_xtext((unsigned char *) message.recips[i]);
if (encbuf == NULL) {
perror("transaction");
return SMTPC_ERR_UNKNOWN;
}
snprintf(ext_orcpt, sizeof(ext_orcpt), " ORCPT=rfc822;%s",
encbuf);
}
free(encbuf);
}
switch (dialog
(300, "RCPT TO:<%s>%s%s\r\n", message.recips[i],
ext_notify, ext_orcpt)) {
case '2':
sent++;
break;
case '4':
case '5':
return 0;
case -1:
return SMTPC_ERR_SOCKET;
default:
return SMTPC_ERR_PROTOCOL;
}
} /* for (i ...) */
switch (dialog(120, "DATA\r\n")) {
case '3':
break;
case '4':
case '5':
return 0;
case -1:
return SMTPC_ERR_SOCKET;
default:
return SMTPC_ERR_PROTOCOL;
}
switch (datasend(600)) {
case '2':
return sent;
case '5':
return 0;
case -1:
return SMTPC_ERR_SOCKET;
default:
return SMTPC_ERR_PROTOCOL;
}
}
static ssize_t session()
{
ssize_t rs;
switch (dialog(300, NULL)) {
case '2':
break;
case '4':
case '5':
return SMTPC_ERR_SUBMISSION;
case -1:
return SMTPC_ERR_SOCKET;
default:
return SMTPC_ERR_PROTOCOL;
}
rs = transaction();
if (rs == 0)
return SMTPC_ERR_SUBMISSION;
return rs;
}
int main(int argc, char *argv[])
{
ssize_t rs;
if (parse_options(&argc, &argv) < 0)
exit(EX_USAGE);
if (read_envelope(options.sender, argc, argv) < 0)
exit(EX_USAGE);
if (read_message() < 0) {
perror("read_message");
if (message.buf != NULL)
free(message.buf);
exit(EX_OSERR);
}
if (options.protocol & SMTPC_PROTO_TCP)
sockstr = sockstr_new(options.nodename, options.servname, NULL);
else if (options.protocol & SMTPC_PROTO_UNIX)
sockstr = sockstr_new(NULL, NULL, options.path);
else
sockstr = NULL;
if (sockstr == NULL) {
perror("sockstr_new");
if (message.buf != NULL)
free(message.buf);
exit(EX_OSERR);
}
sockstr->timeout = 300;
signal(SIGPIPE, SIG_IGN);
if (sockstr_client_connect(sockstr) < 0) {
fprintf(stderr, "error: %s\n", sockstr_errstr(sockstr));
sockstr_destroy(sockstr);
if (message.buf != NULL)
free(message.buf);
exit(EX_IOERR);
}
rs = session();
if (message.buf != NULL)
free(message.buf);
if (options.verbose && server.buf != NULL && 0 < server.buflen)
fputs(server.buf, stdout);
if (rs < 0) {
switch (rs) {
case SMTPC_ERR_SOCKET:
fprintf(stderr, "Socket error: %s\n", sockstr_errstr(sockstr));
break;
case SMTPC_ERR_PROTOCOL:
fprintf(stderr, "Unexpected response: %s", server.buf);
break;
case SMTPC_ERR_SUBMISSION:
dialog(10, "QUIT\r\n");
break;
default:
fprintf(stderr, "Unknown error %ld\n", (long) rs);
break;
}
sockstr_destroy(sockstr);
if (server.buf != NULL)
free(server.buf);
exit(rs);
}
/* entirely or partially sent */
dialog(10, "QUIT\r\n");
sockstr_destroy(sockstr);
free(server.buf);
exit(EX_OK);
}
sympa-6.2.24/src/smtpc/Makefile.am 0000644 0001750 0001750 00000000377 13216651447 015663 0 ustar racke racke # $Id$
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = smtpc
smtpc_SOURCES = \
smtpc.c \
sockstr.c \
sockstr.h \
utf8.c \
utf8.h
dist_doc_DATA = smtpc.1.md
EXTRA_DIST = configure.gnu
CLEANFILES = $(bin_PROGRAMS) *~ *.bak core.*
smtpc.o: sockstr.h utf8.h
sympa-6.2.24/src/smtpc/m4/ 0000755 0001750 0001750 00000000000 13216651447 014140 5 ustar racke racke sympa-6.2.24/src/smtpc/m4/ac_func_snprintf.m4 0000644 0001750 0001750 00000004626 13216651447 017733 0 ustar racke racke dnl @synopsis AC_FUNC_SNPRINTF
dnl
dnl Checks for a fully C99 compliant snprintf, in particular checks
dnl whether it does bounds checking and returns the correct string
dnl length; does the same check for vsnprintf. If no working snprintf
dnl or vsnprintf is found, request a replacement and warn the user
dnl about it. Note: the mentioned replacement is freely available and
dnl may be used in any project regardless of it's licence (just like
dnl the autoconf special exemption).
dnl
dnl @category C
dnl @author RĂ¼diger Kuhlmann
dnl @version 2002-09-26
dnl @license AllPermissive
AC_DEFUN([AC_FUNC_SNPRINTF],
[AC_CHECK_FUNCS(snprintf vsnprintf)
AC_MSG_CHECKING(for working snprintf)
AC_CACHE_VAL(ac_cv_have_working_snprintf,
[AC_TRY_RUN(
[#include
int main(void)
{
char bufs[5] = { 'x', 'x', 'x', '\0', '\0' };
char bufd[5] = { 'x', 'x', 'x', '\0', '\0' };
int i;
i = snprintf (bufs, 2, "%s", "111");
if (strcmp (bufs, "1")) exit (1);
if (i != 3) exit (1);
i = snprintf (bufd, 2, "%d", 111);
if (strcmp (bufd, "1")) exit (1);
if (i != 3) exit (1);
exit(0);
}], ac_cv_have_working_snprintf=yes, ac_cv_have_working_snprintf=no, ac_cv_have_working_snprintf=cross)])
AC_MSG_RESULT([$ac_cv_have_working_snprintf])
AC_MSG_CHECKING(for working vsnprintf)
AC_CACHE_VAL(ac_cv_have_working_vsnprintf,
[AC_TRY_RUN(
[#include
#include
int my_vsnprintf (char *buf, const char *tmpl, ...)
{
int i;
va_list args;
va_start (args, tmpl);
i = vsnprintf (buf, 2, tmpl, args);
va_end (args);
return i;
}
int main(void)
{
char bufs[5] = { 'x', 'x', 'x', '\0', '\0' };
char bufd[5] = { 'x', 'x', 'x', '\0', '\0' };
int i;
i = my_vsnprintf (bufs, "%s", "111");
if (strcmp (bufs, "1")) exit (1);
if (i != 3) exit (1);
i = my_vsnprintf (bufd, "%d", 111);
if (strcmp (bufd, "1")) exit (1);
if (i != 3) exit (1);
exit(0);
}], ac_cv_have_working_vsnprintf=yes, ac_cv_have_working_vsnprintf=no, ac_cv_have_working_vsnprintf=cross)])
AC_MSG_RESULT([$ac_cv_have_working_vsnprintf])
if test x$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf != "xyesyes"; then
AC_LIBOBJ(snprintf)
AC_MSG_WARN([Replacing missing/broken (v)snprintf() with version from http://www.ijs.si/software/snprintf/.])
AC_DEFINE(PREFER_PORTABLE_SNPRINTF, 1, "enable replacement (v)snprintf if system (v)snprintf is broken")
fi])
sympa-6.2.24/src/smtpc/smtpc.1.md 0000644 0001750 0001750 00000007230 13216651447 015431 0 ustar racke racke %SMTPC(1)
# NAME
smtpc - SMTP / LMTP client
# SYNOPSIS
`smtpc` `--esmtp` _host_`:`_port_ `-f` _envelope_@_sen.der_
[ _options_... ] [ `--` ] _recipient_@_add.ress_ ...
`smtpc` `--lmtp` _host_`:`_port_ `-f` _envelope_@_sen.der_
[ _options_... ] [ `--` ] _recipient_@_add.ress_ ...
`smtpc` `--lmtp` _path_ `-f` _envelope_@_sen.der_
[ _options_... ] [ `--` ] _recipient_@_add.ress_ ...
# DESCRIPTION
**smtpc** is an email client.
It reads a message from standard input and submits it to email server through
socket.
## Options
Any options not listed here are silently ignored.
* `--dump`
Show dialog in the session.
* `--esmtp` _host_[:_port_]
Uses TCP socket and ESMTP protocol to submit message.
Either this option or `--lmtp` option is required.
If _host_ is the IPv6 address, it must be enclosed in [...]
to avoid confusion with colon separating _host_ and _port_,
e.g. "`[::1]`", "`[::1]:587`".
If _port_ is omitted, "25" is used.
* `-f` _envelope_@_sen.der_, `-f`_envelope_@_sen.der_
Specifys envelope sender.
This option is required.
To specify "null envelope sender", use a separate empty argument or "`<>`".
* `--iam` _host.name_
Specifys host name or IP address literal used in EHLO or LHLO request.
Default is "`localhost`".
* `--lmtp` _host_[:_port_], `--lmtp` _path_
Uses TCP or Unix domain socket and LMTP protocol to submit message.
Either this option or `--esmtp` option is required.
If _port_ is omitted, "24" is used.
_path_ must be full path to socket file.
* `-N` _dsn_, `-N`_dsn_
Controls delivery status notification.
_dsn_ may be single word "`NEVER`" or one or more of words "`SUCCESS`",
"`FAILURE`" and "`DELAY`" separated by comma.
If this option is not given, delivery status notification will be controlled
by server.
* `--smtputf8`
Enables support for SMTPUTF8 extension.
**smtpc** detects valid UTF-8 sequence in envelope and message header,
then requests this extension as neccessity.
* `-V` _envid_, `-V`_envid_
Specifys envelope ID.
* `--verbose`
Output the last response from the server to standard output.
* `--`
Terminates options.
Remainder of command line arguments are considered to be recipient
addresses, even if any of them begin with "`-`".
* _recipent_@_add.ress_ ...
Recipients to whom the message would be delivered.
At least one recipient is required.
## Exit status
* `0`
Message was successfully submitted.
* `253`
Message was rejected by server.
* `254`
The server returns malformed or illegal response.
* `255`
Network error occurred.
## SMTP extensions
**smtpc** supports following extensions.
* **8-bit MIME Transport** (RFC 6152)
**smtpc** requests this extension if message contains octets with high bit.
* **Delivery Status Notification** (RFC 3461)
**smtpc** issues ORCPT parameters.
See also `-N` and `-V` options.
* **Internationalized Email** (RFC 6531)
Experimentally supported.
See `--smtputf8` option.
* **Message Size Declaration** (RFC 1870)
Estimated size of the message is informed to the server.
# LIMITATIONS
**smtpc** provides the feature of SMTP / LMTP client submitting messages
to particular server.
It will never provide extensive features such as message queuing, retry after
temporary failure, routing using MX DNS record and so on.
Once the server rejects delivery, **smtpc** exits and message is discarded.
# KNOWN BUGS
* If NUL octets (\\0) are included in messages, they are transmitted to the
server.
# SEE ALSO
sendmail(1)
# HISTORY
**smtpc** was initially written for Sympa project by
IKEDA Soji .
sympa-6.2.24/src/smtpc/configure.gnu 0000644 0001750 0001750 00000000465 13216651447 016321 0 ustar racke racke # $Id$
args=
for arg; do
case "$arg" in
*\'*)
arg=`cat <