/* * Heirloom mailx - a mail user agent derived from Berkeley Mail. * * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany. */ /* * Copyright (c) 1980, 1993 * The Regents of the University of California. 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 the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. */ #ifndef lint #ifdef DOSCCS static char sccsid[] = "@(#)fio.c 2.76 (gritter) 9/16/09"; #endif #endif /* not lint */ #include "rcv.h" #ifndef HAVE_WORDEXP #error wordexp support is required #endif #include #include #include #include #include #if defined (USE_NSS) #include #include #elif defined (USE_OPENSSL) #include #include #include #include #include #endif /* USE_SSL */ #ifdef HAVE_SOCKETS #include #include #include #ifdef HAVE_ARPA_INET_H #include #endif /* HAVE_ARPA_INET_H */ #endif /* HAVE_SOCKETS */ #include #include "extern.h" /* * Mail -- a mail program * * File I/O. */ static void makemessage(void); static void append(struct message *mp); static char *globname(char *name); static size_t length_of_line(const char *line, size_t linesize); static char *fgetline_byone(char **line, size_t *linesize, size_t *llen, FILE *fp, int appendnl, size_t n); static enum okay get_header(struct message *mp); /* * Set up the input pointers while copying the mail file into /tmp. */ void setptr(FILE *ibuf, off_t offset) { int c; size_t count; char *cp, *cp2; struct message this; int maybe, inhead, thiscnt; char *linebuf = NULL; size_t linesize = 0, filesize; int broken_mbox = value("broken-mbox") != NULL; maybe = 1; inhead = 0; thiscnt = 0; memset(&this, 0, sizeof this); this.m_flag = MUSED|MNEW|MNEWEST; filesize = mailsize - offset; offset = ftell(mb.mb_otf); for (;;) { if (fgetline(&linebuf, &linesize, &filesize, &count, ibuf, 0) == NULL) { this.m_xsize = this.m_size; this.m_xlines = this.m_lines; this.m_have = HAVE_HEADER|HAVE_BODY; if (thiscnt > 0) append(&this); makemessage(); if (linebuf) free(linebuf); return; } #ifdef notdef if (linebuf[0] == '\0') linebuf[0] = '.'; #endif fwrite(linebuf, sizeof *linebuf, count, mb.mb_otf); if (ferror(mb.mb_otf)) { perror("/tmp"); exit(1); } if (linebuf[count - 1] == '\n') linebuf[count - 1] = '\0'; if (maybe && linebuf[0] == 'F' && is_head(linebuf, count)) { this.m_xsize = this.m_size; this.m_xlines = this.m_lines; this.m_have = HAVE_HEADER|HAVE_BODY; if (thiscnt++ > 0) append(&this); msgCount++; this.m_flag = MUSED|MNEW|MNEWEST; this.m_size = 0; this.m_lines = 0; this.m_block = mailx_blockof(offset); this.m_offset = mailx_offsetof(offset); inhead = 1; } else if (linebuf[0] == 0) { inhead = 0; } else if (inhead) { for (cp = linebuf, cp2 = "status";; cp++) { if ((c = *cp2++) == 0) { while (c = *cp++, whitechar(c)); if (cp[-1] != ':') break; while ((c = *cp++) != '\0') if (c == 'R') this.m_flag |= MREAD; else if (c == 'O') this.m_flag &= ~MNEW; break; } if (*cp != c && *cp != upperconv(c)) break; } for (cp = linebuf, cp2 = "x-status";; cp++) { if ((c = *cp2++) == 0) { while (c = *cp++, whitechar(c)); if (cp[-1] != ':') break; while ((c = *cp++) != '\0') if (c == 'F') this.m_flag |= MFLAGGED; else if (c == 'A') this.m_flag|=MANSWERED; else if (c == 'T') this.m_flag|=MDRAFTED; break; } if (*cp != c && *cp != upperconv(c)) break; } } offset += count; this.m_size += count; this.m_lines++; if (!broken_mbox) maybe = linebuf[0] == 0; } /*NOTREACHED*/ } /* * Drop the passed line onto the passed output buffer. * If a write error occurs, return -1, else the count of * characters written, including the newline. */ int putline(FILE *obuf, char *linebuf, size_t count) { fwrite(linebuf, sizeof *linebuf, count, obuf); putc('\n', obuf); if (ferror(obuf)) return (-1); return (count + 1); } /* * Read up a line from the specified input into the line * buffer. Return the number of characters read. Do not * include the newline at the end. * * n is the number of characters already read. */ int readline_restart(FILE *ibuf, char **linebuf, size_t *linesize, size_t n) { long sz; clearerr(ibuf); /* * Interrupts will cause trouble if we are inside a stdio call. As * this is only relevant if input comes from a terminal, we can simply * bypass it by read() then. */ if (fileno(ibuf) == 0 && is_a_tty[0]) { if (*linebuf == NULL || *linesize < LINESIZE + n + 1) *linebuf = srealloc(*linebuf, *linesize = LINESIZE + n + 1); for (;;) { if (n >= *linesize - 128) *linebuf = srealloc(*linebuf, *linesize += 256); again: sz = read(0, *linebuf + n, *linesize - n - 1); if (sz > 0) { n += sz; (*linebuf)[n] = '\0'; if (n > 0 && (*linebuf)[n - 1] == '\n') break; } else { if (sz < 0 && errno == EINTR) goto again; if (n > 0) { if ((*linebuf)[n - 1] != '\n') { (*linebuf)[n++] = '\n'; (*linebuf)[n] = '\0'; } break; } else return -1; } } } else { /* * Not reading from standard input or standard input not * a terminal. We read one char at a time as it is the * only way to get lines with embedded NUL characters in * standard stdio. */ if (fgetline_byone(linebuf, linesize, &n, ibuf, 1, n) == NULL) return -1; } if (n > 0 && (*linebuf)[n - 1] == '\n') (*linebuf)[--n] = '\0'; return n; } /* * Return a file buffer all ready to read up the * passed message pointer. */ FILE * setinput(struct mailbox *mp, struct message *m, enum needspec need) { enum okay ok = STOP; switch (need) { case NEED_HEADER: if (m->m_have & HAVE_HEADER) ok = OKAY; else ok = get_header(m); break; case NEED_BODY: if (m->m_have & HAVE_BODY) ok = OKAY; else ok = get_body(m); break; case NEED_UNSPEC: ok = OKAY; break; } if (ok != OKAY) return NULL; fflush(mp->mb_otf); if (fseek(mp->mb_itf, (long)mailx_positionof(m->m_block, m->m_offset), SEEK_SET) < 0) { perror("fseek"); panic(catgets(catd, CATSET, 77, "temporary file seek")); } return (mp->mb_itf); } struct message * setdot(struct message *mp) { if (dot != mp) { prevdot = dot; did_print_dot = 0; } dot = mp; uncollapse1(dot, 0); return dot; } /* * Take the data out of the passed ghost file and toss it into * a dynamically allocated message structure. */ static void makemessage(void) { if (msgCount == 0) append(NULL); setdot(message); message[msgCount].m_size = 0; message[msgCount].m_lines = 0; } /* * Append the passed message descriptor onto the message structure. */ static void append(struct message *mp) { if (msgCount + 1 >= msgspace) message = srealloc(message, (msgspace += 64) * sizeof *message); if (msgCount > 0) message[msgCount - 1] = *mp; } /* * Delete a file, but only if the file is a plain file. */ int rm(char *name) { struct stat sb; if (stat(name, &sb) < 0) return(-1); if (!S_ISREG(sb.st_mode)) { errno = EISDIR; return(-1); } return(unlink(name)); } static int sigdepth; /* depth of holdsigs() */ static sigset_t nset, oset; /* * Hold signals SIGHUP, SIGINT, and SIGQUIT. */ void holdsigs(void) { if (sigdepth++ == 0) { sigemptyset(&nset); sigaddset(&nset, SIGHUP); sigaddset(&nset, SIGINT); sigaddset(&nset, SIGQUIT); sigprocmask(SIG_BLOCK, &nset, &oset); } } /* * Release signals SIGHUP, SIGINT, and SIGQUIT. */ void relsesigs(void) { if (--sigdepth == 0) sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL); } /* * Determine the size of the file possessed by * the passed buffer. */ off_t fsize(FILE *iob) { struct stat sbuf; if (fstat(fileno(iob), &sbuf) < 0) return 0; return sbuf.st_size; } /* * Evaluate the string given as a new mailbox name. * Supported meta characters: * % for my system mail box * %user for user's system mail box * # for previous file * & invoker's mbox file * +file file in folder directory * any shell meta character * Return the file name as a dynamic string. */ char * expand(char *name) { char xname[PATHSIZE]; char foldbuf[PATHSIZE]; struct shortcut *sh; /* * The order of evaluation is "%" and "#" expand into constants. * "&" can expand into "+". "+" can expand into shell meta characters. * Shell meta characters expand into constants. * This way, we make no recursive expansion. */ if ((sh = get_shortcut(name)) != NULL) name = sh->sh_long; next: switch (*name) { case '%': if (name[1] == ':' && name[2]) { name = &name[2]; goto next; } findmail(name[1] ? name + 1 : myname, name[1] != '\0' || uflag, xname, sizeof xname); return savestr(xname); case '#': if (name[1] != 0) break; if (prevfile[0] == 0) { printf(catgets(catd, CATSET, 80, "No previous file\n")); return NULL; } return savestr(prevfile); case '&': if (name[1] == 0 && (name = value("MBOX")) == NULL) name = "~/mbox"; /* fall through */ } if (name[0] == '@' && which_protocol(mailname) == PROTO_IMAP) { snprintf(xname, sizeof xname, "%s/%s", protbase(mailname), &name[1]); name = savestr(xname); } if (name[0] == '+' && getfold(foldbuf, sizeof foldbuf) >= 0) { if (which_protocol(foldbuf) == PROTO_IMAP && strcmp(foldbuf, protbase(foldbuf))) snprintf(xname, sizeof xname, "%s%s", foldbuf, name+1); else snprintf(xname, sizeof xname, "%s/%s", foldbuf, name+1); name = savestr(xname); if (foldbuf[0] == '%' && foldbuf[1] == ':') goto next; } /* catch the most common shell meta character */ if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) { snprintf(xname, sizeof xname, "%s%s", homedir, name + 1); name = savestr(xname); } if (!anyof(name, "|&;<>~{}()[]*?$`'\"\\")) return name; if (which_protocol(name) == PROTO_FILE) return globname(name); else return name; } static char * globname(char *name) { wordexp_t we; char *cp; sigset_t nset; int i; /* * Some systems (notably Open UNIX 8.0.0) fork a shell for * wordexp() and wait for it; waiting will fail if our SIGCHLD * handler is active. */ sigemptyset(&nset); sigaddset(&nset, SIGCHLD); sigprocmask(SIG_BLOCK, &nset, NULL); i = wordexp(name, &we, WRDE_NOCMD); sigprocmask(SIG_UNBLOCK, &nset, NULL); switch (i) { case 0: break; case WRDE_NOSPACE: fprintf(stderr, catgets(catd, CATSET, 83, "\"%s\": Expansion buffer overflow.\n"), name); return NULL; case WRDE_BADCHAR: case WRDE_SYNTAX: default: fprintf(stderr, catgets(catd, CATSET, 242, "Syntax error in \"%s\"\n"), name); return NULL; } switch (we.we_wordc) { case 1: cp = savestr(we.we_wordv[0]); break; case 0: fprintf(stderr, catgets(catd, CATSET, 82, "\"%s\": No match.\n"), name); cp = NULL; break; default: fprintf(stderr, catgets(catd, CATSET, 84, "\"%s\": Ambiguous.\n"), name); cp = NULL; } wordfree(&we); return cp; } /* * Determine the current folder directory name. */ int getfold(char *name, int size) { char *folder; enum protocol p; if ((folder = value("folder")) == NULL) return (-1); if (*folder == '/' || (p = which_protocol(folder)) != PROTO_FILE && p != PROTO_MAILDIR) { strncpy(name, folder, size); name[size-1]='\0'; } else { snprintf(name, size, "%s/%s", homedir, folder); } return (0); } /* * Return the name of the dead.letter file. */ char * getdeadletter(void) { char *cp; if ((cp = value("DEAD")) == NULL || (cp = expand(cp)) == NULL) cp = expand("~/dead.letter"); else if (*cp != '/') { char *buf; size_t sz; buf = ac_alloc(sz = strlen(cp) + 3); snprintf(buf, sz, "~/%s", cp); snprintf(buf, sz, "~/%s", cp); cp = expand(buf); ac_free(buf); } return cp; } /* * line is a buffer with the result of fgets(). Returns the first * newline or the last character read. */ static size_t length_of_line(const char *line, size_t linesize) { register size_t i; /* * Last character is always '\0' and was added by fgets. */ linesize--; for (i = 0; i < linesize; i++) if (line[i] == '\n') break; return i < linesize ? i + 1 : linesize; } /* * fgets replacement to handle lines of arbitrary size and with * embedded \0 characters. * line - line buffer. *line be NULL. * linesize - allocated size of line buffer. * count - maximum characters to read. May be NULL. * llen - length_of_line(*line). * fp - input FILE. * appendnl - always terminate line with \n, append if necessary. */ char * fgetline(char **line, size_t *linesize, size_t *count, size_t *llen, FILE *fp, int appendnl) { long i_llen, sz; if (count == NULL) /* * If we have no count, we cannot determine where the * characters returned by fgets() end if there was no * newline. We have to read one character at one. */ return fgetline_byone(line, linesize, llen, fp, appendnl, 0); if (*line == NULL || *linesize < LINESIZE) *line = srealloc(*line, *linesize = LINESIZE); sz = *linesize <= *count ? *linesize : *count + 1; if (sz <= 1 || fgets(*line, sz, fp) == NULL) /* * Leave llen untouched; it is used to determine whether * the last line was \n-terminated in some callers. */ return NULL; i_llen = length_of_line(*line, sz); *count -= i_llen; while ((*line)[i_llen - 1] != '\n') { *line = srealloc(*line, *linesize += 256); sz = *linesize - i_llen; sz = (sz <= *count ? sz : *count + 1); if (sz <= 1 || fgets(&(*line)[i_llen], sz, fp) == NULL) { if (appendnl) { (*line)[i_llen++] = '\n'; (*line)[i_llen] = '\0'; } break; } sz = length_of_line(&(*line)[i_llen], sz); i_llen += sz; *count -= sz; } if (llen) *llen = i_llen; return *line; } /* * Read a line, one character at once. */ static char * fgetline_byone(char **line, size_t *linesize, size_t *llen, FILE *fp, int appendnl, size_t n) { int c; if (*line == NULL || *linesize < LINESIZE + n + 1) *line = srealloc(*line, *linesize = LINESIZE + n + 1); for (;;) { if (n >= *linesize - 128) *line = srealloc(*line, *linesize += 256); c = getc(fp); if (c != EOF) { (*line)[n++] = c; (*line)[n] = '\0'; if (c == '\n') break; } else { if (n > 0) { if (appendnl) { (*line)[n++] = '\n'; (*line)[n] = '\0'; } break; } else return NULL; } } if (llen) *llen = n; return *line; } static enum okay get_header(struct message *mp) { switch (mb.mb_type) { case MB_FILE: case MB_MAILDIR: return OKAY; case MB_POP3: return pop3_header(mp); case MB_IMAP: case MB_CACHE: return imap_header(mp); case MB_VOID: return STOP; } /*NOTREACHED*/ return STOP; } enum okay get_body(struct message *mp) { switch (mb.mb_type) { case MB_FILE: case MB_MAILDIR: return OKAY; case MB_POP3: return pop3_body(mp); case MB_IMAP: case MB_CACHE: return imap_body(mp); case MB_VOID: return STOP; } /*NOTREACHED*/ return STOP; } #ifdef HAVE_SOCKETS static long xwrite(int fd, const char *data, size_t sz); static long xwrite(int fd, const char *data, size_t sz) { long wo, wt = 0; do { if ((wo = write(fd, data + wt, sz - wt)) < 0) { if (errno == EINTR) continue; else return -1; } wt += wo; } while (wt < sz); return sz; } int sclose(struct sock *sp) { int i; if (sp->s_fd > 0) { if (sp->s_onclose != NULL) (*sp->s_onclose)(); #if defined (USE_NSS) if (sp->s_use_ssl) { sp->s_use_ssl = 0; i = PR_Close(sp->s_prfd) == PR_SUCCESS ? 0 : -1; sp->s_prfd = NULL; } else #elif defined (USE_OPENSSL) if (sp->s_use_ssl) { sp->s_use_ssl = 0; SSL_shutdown(sp->s_ssl); SSL_free(sp->s_ssl); sp->s_ssl = NULL; SSL_CTX_free(sp->s_ctx); sp->s_ctx = NULL; } #endif /* USE_SSL */ { i = close(sp->s_fd); } sp->s_fd = -1; return i; } sp->s_fd = -1; return 0; } enum okay swrite(struct sock *sp, const char *data) { return swrite1(sp, data, strlen(data), 0); } enum okay swrite1(struct sock *sp, const char *data, int sz, int use_buffer) { int x; if (use_buffer > 0) { int di; enum okay ok; if (sp->s_wbuf == NULL) { sp->s_wbufsize = 4096; sp->s_wbuf = smalloc(sp->s_wbufsize); sp->s_wbufpos = 0; } while (sp->s_wbufpos + sz > sp->s_wbufsize) { di = sp->s_wbufsize - sp->s_wbufpos; sz -= di; if (sp->s_wbufpos > 0) { memcpy(&sp->s_wbuf[sp->s_wbufpos], data, di); ok = swrite1(sp, sp->s_wbuf, sp->s_wbufsize, -1); } else ok = swrite1(sp, data, sp->s_wbufsize, -1); if (ok != OKAY) return STOP; data += di; sp->s_wbufpos = 0; } if (sz == sp->s_wbufsize) { ok = swrite1(sp, data, sp->s_wbufsize, -1); if (ok != OKAY) return STOP; } else if (sz) { memcpy(&sp->s_wbuf[sp->s_wbufpos], data, sz); sp->s_wbufpos += sz; } return OKAY; } else if (use_buffer == 0 && sp->s_wbuf != NULL && sp->s_wbufpos > 0) { x = sp->s_wbufpos; sp->s_wbufpos = 0; if (swrite1(sp, sp->s_wbuf, x, -1) != OKAY) return STOP; } if (sz == 0) return OKAY; #if defined (USE_NSS) if (sp->s_use_ssl) { x = PR_Write(sp->s_prfd, data, sz); } else #elif defined (USE_OPENSSL) if (sp->s_use_ssl) { ssl_retry: x = SSL_write(sp->s_ssl, data, sz); if (x < 0) { switch (SSL_get_error(sp->s_ssl, x)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: goto ssl_retry; } } } else #endif /* USE_SSL */ { x = xwrite(sp->s_fd, data, sz); } if (x != sz) { char o[512]; snprintf(o, sizeof o, "%s write error", sp->s_desc ? sp->s_desc : "socket"); #if defined (USE_NSS) sp->s_use_ssl ? nss_gen_err("%s", o) : perror(o); #elif defined (USE_OPENSSL) sp->s_use_ssl ? ssl_gen_err("%s", o) : perror(o); #else /* !USE_SSL */ perror(o); #endif /* !USE_SSL */ if (x < 0) sclose(sp); return STOP; } return OKAY; } int sgetline(char **line, size_t *linesize, size_t *linelen, struct sock *sp) { char *lp = *line; if (sp->s_rsz < 0) { sclose(sp); return sp->s_rsz; } do { if (*line == NULL || lp > &(*line)[*linesize - 128]) { size_t diff = lp - *line; *line = srealloc(*line, *linesize += 256); lp = &(*line)[diff]; } if (sp->s_rbufptr == NULL || sp->s_rbufptr >= &sp->s_rbuf[sp->s_rsz]) { #if defined (USE_NSS) if (sp->s_use_ssl) { if ((sp->s_rsz = PR_Read(sp->s_prfd, sp->s_rbuf, sizeof sp->s_rbuf)) <= 0) { if (sp->s_rsz < 0) { char o[512]; snprintf(o, sizeof o, "%s", sp->s_desc ? sp->s_desc : "socket"); nss_gen_err("%s", o); } break; } } else #elif defined (USE_OPENSSL) if (sp->s_use_ssl) { ssl_retry: if ((sp->s_rsz = SSL_read(sp->s_ssl, sp->s_rbuf, sizeof sp->s_rbuf)) <= 0) { if (sp->s_rsz < 0) { char o[512]; switch(SSL_get_error(sp->s_ssl, sp->s_rsz)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: goto ssl_retry; } snprintf(o, sizeof o, "%s", sp->s_desc ? sp->s_desc : "socket"); ssl_gen_err("%s", o); } break; } } else #endif /* USE_SSL */ { again: if ((sp->s_rsz = read(sp->s_fd, sp->s_rbuf, sizeof sp->s_rbuf)) <= 0) { if (sp->s_rsz < 0) { char o[512]; if (errno == EINTR) goto again; snprintf(o, sizeof o, "%s", sp->s_desc ? sp->s_desc : "socket"); perror(o); } break; } } sp->s_rbufptr = sp->s_rbuf; } } while ((*lp++ = *sp->s_rbufptr++) != '\n'); *lp = '\0'; if (linelen) *linelen = lp - *line; return lp - *line; } enum okay sopen(const char *xserver, struct sock *sp, int use_ssl, const char *uhp, const char *portstr, int verbose) { #ifdef HAVE_IPv6_FUNCS char hbuf[NI_MAXHOST]; struct addrinfo hints, *res0, *res; #else /* !HAVE_IPv6_FUNCS */ struct sockaddr_in servaddr; struct in_addr **pptr; struct hostent *hp; struct servent *ep; unsigned short port = 0; #endif /* !HAVE_IPv6_FUNCS */ int sockfd; char *cp; char *server = (char *)xserver; if ((cp = strchr(server, ':')) != NULL) { portstr = &cp[1]; #ifndef HAVE_IPv6_FUNCS port = strtol(portstr, NULL, 10); #endif /* HAVE_IPv6_FUNCS */ server = salloc(cp - xserver + 1); memcpy(server, xserver, cp - xserver); server[cp - xserver] = '\0'; } #ifdef HAVE_IPv6_FUNCS memset(&hints, 0, sizeof hints); hints.ai_socktype = SOCK_STREAM; if (verbose) fprintf(stderr, "Resolving host %s . . .", server); if (getaddrinfo(server, portstr, &hints, &res0) != 0) { fprintf(stderr, catgets(catd, CATSET, 252, "Could not resolve host: %s\n"), server); return STOP; } else if (verbose) fprintf(stderr, " done.\n"); sockfd = -1; for (res = res0; res != NULL && sockfd < 0; res = res->ai_next) { if (verbose) { if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof hbuf, NULL, 0, NI_NUMERICHOST) != 0) strcpy(hbuf, "unknown host"); fprintf(stderr, catgets(catd, CATSET, 192, "Connecting to %s:%s . . ."), hbuf, portstr); } if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) >= 0) { if (connect(sockfd, res->ai_addr, res->ai_addrlen)!=0) { close(sockfd); sockfd = -1; } } } if (sockfd < 0) { perror(catgets(catd, CATSET, 254, "could not connect")); freeaddrinfo(res0); return STOP; } freeaddrinfo(res0); #else /* !HAVE_IPv6_FUNCS */ if (port == 0) { if (equal(portstr, "smtp")) port = htons(25); else if (equal(portstr, "smtps")) port = htons(465); else if (equal(portstr, "imap")) port = htons(143); else if (equal(portstr, "imaps")) port = htons(993); else if (equal(portstr, "pop3")) port = htons(110); else if (equal(portstr, "pop3s")) port = htons(995); else if ((ep = getservbyname((char *)portstr, "tcp")) != NULL) port = ep->s_port; else { fprintf(stderr, catgets(catd, CATSET, 251, "Unknown service: %s\n"), portstr); return STOP; } } else port = htons(port); if (verbose) fprintf(stderr, "Resolving host %s . . .", server); if ((hp = gethostbyname(server)) == NULL) { fprintf(stderr, catgets(catd, CATSET, 252, "Could not resolve host: %s\n"), server); return STOP; } else if (verbose) fprintf(stderr, " done.\n"); pptr = (struct in_addr **)hp->h_addr_list; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror(catgets(catd, CATSET, 253, "could not create socket")); return STOP; } memset(&servaddr, 0, sizeof servaddr); servaddr.sin_family = AF_INET; servaddr.sin_port = port; memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr)); if (verbose) fprintf(stderr, catgets(catd, CATSET, 192, "Connecting to %s:%d . . ."), inet_ntoa(**pptr), ntohs(port)); if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof servaddr) != 0) { perror(catgets(catd, CATSET, 254, "could not connect")); return STOP; } #endif /* !HAVE_IPv6_FUNCS */ if (verbose) fputs(catgets(catd, CATSET, 193, " connected.\n"), stderr); memset(sp, 0, sizeof *sp); sp->s_fd = sockfd; #if defined (USE_SSL) if (use_ssl) { enum okay ok; if ((ok = ssl_open(server, sp, uhp)) != OKAY) sclose(sp); return ok; } #endif /* USE_SSL */ return OKAY; } #endif /* HAVE_SOCKETS */