/* * Test that the SMTP server is conforming to RFC1854 (PIPELINING). * Public domain. */ #include #include #include #include #include #include #include #include char *host = NULL; char *port = "25"; static void printusage(void) { extern char *__progname; printf("Usage: %s [-h host] [-p port]\n", __progname); } static int ExpectSingle(FILE *f, const char *code) { char *buf, *lbuf = NULL; size_t len; int rv = 0; if ((buf = fgetln(f, &len)) == NULL) { fprintf(stderr, "EOF from server\n"); return (0); } if (buf[len-1] == '\n') { buf[len-1] = '\0'; } else { if ((lbuf = malloc(len+1)) == NULL) { fprintf(stderr, "malloc linebuf\n"); return (0); } memcpy(lbuf, buf, len); lbuf[len] = '\0'; buf = lbuf; } if (code[0] != buf[0]) { fprintf(stderr, "Server returned \"%s\" (was expecting %s)\n", buf, code); rv = 0; } if (lbuf != NULL) { free(lbuf); } return (1); } int main(int argc, char *argv[]) { struct addrinfo hints, *res, *res0; const char *cause = NULL; char *buf, *lbuf; int rv, s; FILE *f; extern char *optarg; size_t len; int c; while ((c = getopt(argc, argv, "h:p:?")) != -1) { switch (c) { case 'h': host = optarg; break; case 'p': port = optarg; break; default: printusage(); exit(1); } } if (host == NULL) { printusage(); exit(1); } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((rv = getaddrinfo(host, port, &hints, &res0)) != 0) { printf("%s:%s: %s\n", host, port, gai_strerror(rv)); return (-1); } for (s = -1, res = res0; res != NULL; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; } if (s == -1) { printf("%s: %s\n", cause, strerror(errno)); goto fail_addr; } if ((f = fdopen(s, "w+")) == NULL) { printf("fdopen: %s\n", strerror(errno)); goto fail; } if (setvbuf(f, NULL, _IOFBF, 0) == EOF) { printf("setvbuf failed\n"); goto fail; } if (!ExpectSingle(f, "220")) { goto fail; } fputs("EHLO [127.0.0.1]\n", f); fflush(f); if (!ExpectSingle(f, "250")) { goto fail; } fputs("MAIL FROM:\n", f); fputs("RCPT TO:\n", f); fputs("RCPT TO:\n", f); fputs("RCPT TO:\n", f); fputs("RCPT TO:\n", f); fputs("RCPT TO:\n", f); fputs("DATA\n", f); fflush(stdout); lbuf = NULL; rv = 0; while ((buf = fgetln(f, &len)) != NULL) { if (buf[len-1] == '\n') { buf[len-1] = '\0'; } else { if ((lbuf = malloc(len+1)) == NULL) { printf("malloc linebuf\n"); exit(1); } memcpy(lbuf, buf, len); lbuf[len] = '\0'; buf = lbuf; } printf("< %s\n", buf); switch (rv) { case 0: if (buf[0] != '2') { printf("Bad FROM response: `%s'\n", buf); exit(1); } break; case 1: case 2: case 3: case 4: case 5: if (buf[0] != '2' && buf[0] != '5') { printf("Bad TO response: `%s'\n", buf); exit(1); } break; case 6: if (buf[0] != '3') { printf("Bad DATA response: `%s'\n", buf); exit(1); } goto out1; } rv++; } out1: free(lbuf); fputs("Subject: Test for RFC1854\n", f); fputs("\n\nTest\r\n.\r\n", f); fputs("quit\n", f); fflush(stdout); lbuf = NULL; rv = 0; while ((buf = fgetln(f, &len)) != NULL) { if (buf[len-1] == '\n') { buf[len-1] = '\0'; } else { if ((lbuf = malloc(len+1)) == NULL) { printf("malloc linebuf\n"); exit(1); } memcpy(lbuf, buf, len); lbuf[len] = '\0'; buf = lbuf; } printf("< %s\n", buf); switch (rv) { case 0: if (buf[0] != '2' && buf[0] != '5') { printf("Bad END-OF-DATA response: `%s'\n", buf); exit(1); } break; case 1: if (buf[0] != '2') { printf("Bad QUIT response: `%s'\n", buf); exit(1); } goto out2; } rv++; } out2: free(lbuf); close(s); freeaddrinfo(res0); return (0); fail: close(s); fail_addr: freeaddrinfo(res0); return (1); }