/* * Copyright (c) 2004 David Parsons. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgement: * * This product includes software developed by David Parsons * (orc@pell.chi.il.us) * * 4. My name may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * The licence and distribution terms for any publically available * version or derivative of this code cannot be changed. i.e. this * code cannot simply be copied and put under another distribution * licence [including the GNU Public Licence.] */ #include #include #include #include #include #include #include #include #include extern void say(char*,...); #include "smtp.h" SMTP* smtp(name) char *name; { struct hostent *host; struct servent *p; struct sockaddr_in sock; char *c; int fd; SMTP *ret = malloc(sizeof *ret); if (ret == 0) { say("Out of memory connecting to %s.", name); return 0; } ret->fd = -1; /* copy the name into scratch space in case we have to split host:port */ if (ret->host = malloc(strlen(name)+1)) { strcpy(ret->host, name); } else { say("Out of memory connecting to %s.", name); free(ret); return 0; } /* find the port to connect to */ if ( (c = strchr(ret->host, ':')) ) { *c++ = 0; ret->port = htons(atoi(c)); } else if (p = getservbyname("smtp", "tcp")) { ret->port = p->s_port; } else { say("Using %d for SMTP port.", 25); ret->port = 25; } /* then find the host */ if ( (host = gethostbyname(name)) == 0) { struct in_addr addr; struct hostent hbuf; char *alist[1]; if ( (addr.s_addr = inet_addr(name)) == -1) { say("unknown host %s.", name); nfree(ret); return 0; } hbuf.h_name = name; hbuf.h_addr_list = alist; hbuf.h_addr = (char*)&addr; hbuf.h_length = sizeof(addr); hbuf.h_addrtype = AF_INET; hbuf.h_aliases = 0; host = &hbuf; } /* open up a socket, then return a SMTP* attached to the socket */ sock.sin_family = host->h_addrtype; sock.sin_port = ret->port; memcpy(&sock.sin_addr, host->h_addr, host->h_length); if ( (fd = socket(host->h_addrtype, SOCK_STREAM, 0)) < 0) { say("smtp socket open failed: %s", strerror(errno)); nfree(ret); return 0; } if (connect(fd, (struct sockaddr *)&sock, sizeof(sock)) < 0) { say("smtp socket open failed: %s", strerror(errno)); close(fd); nfree(ret); return 0; } say("connected to %s:%d", host->h_name, ntohs(ret->port)); ret->fd = fd; return ret; } char * nreadline(srv) SMTP *srv; { int eof = 0; char *ret = readline(srv->fd, &eof); if (ret == 0) { say("Out of memory talking to %s.", srv->host); srv->flags |= SMTP_EOF; return 0; } if (eof) srv->flags |= SMTP_EOF; if (ndbg(srv)) fprintf(stderr, "<< %s\n%s", ret, eof ? "* EOF *\n" : ""); return ret; } char * readline(int fd, int *eof) { static char *buf = 0; static int alloc = 0, base = 0, len = 0; int idx, sz, add; char *ret; *eof = 0; more: for (idx=base; idx < len; idx++) { if ( (buf[idx] == '\n') || (buf[idx] == '\r' && buf[idx+1] == '\n') ) { ret = buf+base; add = (buf[idx] == '\r') ? 2 : 1; buf[idx] = 0; idx += add; if (idx == len) base = len = 0; else base = idx; return ret; } } if (len >= alloc) { buf = (alloc == 0) ? malloc(alloc=80) : realloc(buf, alloc *= 2); if (buf == 0) { return 0; } } if ( (sz = read(fd, buf+len, alloc-len)) > 0) { len += sz; goto more; } *eof = 1; ret = buf+base; buf[len] = 0; base = 0; return ret; } void nwriteline(srv,s) SMTP *srv; char *s; { struct iovec vec[2]; if (ndbg(srv)) fprintf(stderr, ">> %s\n", s); vec[0].iov_base = s; vec[0].iov_len = strlen(s); vec[1].iov_base = "\r\n"; vec[1].iov_len = 2; writev(srv->fd, vec, 2); } int nreply(SMTP *srv) { char *line; char *e; int code; if (srv == 0) return 0; do { if ( ((line = nreadline(srv)) == 0) || neof(srv) ) return 0; code = strtol(line, &e, 10); if (nverbose(srv)) fprintf(stderr, "%s\n", line); } while ( (*e == '-') || (code/100) == 1); return code; } void nfree(SMTP *srv) { if (srv->fd != -1) close(srv->fd); free(srv->host); free(srv); }