VSTRING *vstring_sprintf_prepend(VSTRING *vp, const char *format,...) { va_list ap; ssize_t old_len = VSTRING_LEN(vp); ssize_t result_len; /* Construct: old|new|free */ va_start(ap, format); vp = vstring_vsprintf_append(vp, format, ap); va_end(ap); result_len = VSTRING_LEN(vp); /* Construct: old|new|old|free */ VSTRING_SPACE(vp, old_len); vstring_memcat(vp, vstring_str(vp), old_len); /* Construct: new|old|free */ memmove(vstring_str(vp), vstring_str(vp) + old_len, result_len); VSTRING_AT_OFFSET(vp, result_len); VSTRING_TERMINATE(vp); return (vp); }
int main(int argc, char **argv) { SESSION *session; char *host; char *port; char *path; int path_len; int sessions = 1; int ch; int i; char *buf; const char *parse_err; struct addrinfo *res; int aierr; const char *protocols = INET_PROTO_NAME_ALL; INET_PROTO_INFO *proto_info; char *message_file = 0; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; signal(SIGPIPE, SIG_IGN); msg_vstream_init(argv[0], VSTREAM_ERR); /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "46AcC:df:F:l:Lm:M:Nor:R:s:S:t:T:vw:")) > 0) { switch (ch) { case '4': protocols = INET_PROTO_NAME_IPV4; break; case '6': protocols = INET_PROTO_NAME_IPV6; break; case 'A': allow_reject = 1; break; case 'c': count++; break; case 'C': if ((connect_count = atoi(optarg)) <= 0) msg_fatal("bad connection count: %s", optarg); break; case 'd': disconnect = 0; break; case 'f': sender = optarg; break; case 'F': if (message_file == 0 && message_length > 0) msg_fatal("-l option cannot be used with -F"); message_file = optarg; break; case 'l': if (message_file != 0) msg_fatal("-l option cannot be used with -F"); if ((message_length = atoi(optarg)) <= 0) msg_fatal("bad message length: %s", optarg); break; case 'L': talk_lmtp = 1; break; case 'm': if ((message_count = atoi(optarg)) <= 0) msg_fatal("bad message count: %s", optarg); break; case 'M': if (*optarg == '[') { if (!valid_mailhost_literal(optarg, DO_GRIPE)) msg_fatal("bad address literal: %s", optarg); } else { if (!valid_hostname(optarg, DO_GRIPE)) msg_fatal("bad hostname: %s", optarg); } var_myhostname = optarg; break; case 'N': number_rcpts = 1; break; case 'o': send_helo_first = 0; send_headers = 0; break; case 'r': if ((recipients = atoi(optarg)) <= 0) msg_fatal("bad recipient count: %s", optarg); break; case 'R': if (fixed_delay > 0) msg_fatal("do not use -w and -R options at the same time"); if ((random_delay = atoi(optarg)) <= 0) msg_fatal("bad random delay: %s", optarg); break; case 's': if ((sessions = atoi(optarg)) <= 0) msg_fatal("bad session count: %s", optarg); break; case 'S': subject = optarg; break; case 't': recipient = optarg; break; case 'T': if ((inet_windowsize = atoi(optarg)) <= 0) msg_fatal("bad TCP window size: %s", optarg); break; case 'v': msg_verbose++; break; case 'w': if (random_delay > 0) msg_fatal("do not use -w and -R options at the same time"); if ((fixed_delay = atoi(optarg)) <= 0) msg_fatal("bad fixed delay: %s", optarg); break; default: usage(argv[0]); } } if (argc - optind != 1) usage(argv[0]); if (random_delay > 0) srand(getpid()); /* * Initialize the message content, SMTP encoded. smtp_fputs() will append * another \r\n but we don't care. */ if (message_file != 0) { VSTREAM *fp; VSTRING *buf = vstring_alloc(100); VSTRING *msg = vstring_alloc(100); if ((fp = vstream_fopen(message_file, O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", message_file); while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) { if (*vstring_str(buf) == '.') VSTRING_ADDCH(msg, '.'); vstring_memcat(msg, vstring_str(buf), VSTRING_LEN(buf)); vstring_memcat(msg, "\r\n", 2); } if (vstream_ferror(fp)) msg_fatal("read %s: %m", message_file); vstream_fclose(fp); vstring_free(buf); message_length = VSTRING_LEN(msg); message_data = vstring_export(msg); send_headers = 0; } else if (message_length > 0) { message_data = mymalloc(message_length); memset(message_data, 'X', message_length); for (i = 80; i < message_length; i += 80) { message_data[i - 80] = "0123456789"[(i / 80) % 10]; message_data[i - 2] = '\r'; message_data[i - 1] = '\n'; } } /* * Translate endpoint address to internal form. */ proto_info = inet_proto_init("protocols", protocols); if (strncmp(argv[optind], "unix:", 5) == 0) { path = argv[optind] + 5; path_len = strlen(path); if (path_len >= (int) sizeof(sun.sun_path)) msg_fatal("unix-domain name too long: %s", path); memset((char *) &sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; #ifdef HAS_SUN_LEN sun.sun_len = path_len + 1; #endif memcpy(sun.sun_path, path, path_len); sa = (struct sockaddr *) & sun; sa_length = sizeof(sun); } else { if (strncmp(argv[optind], "inet:", 5) == 0) argv[optind] += 5; buf = mystrdup(argv[optind]); if ((parse_err = host_port(buf, &host, (char *) 0, &port, "smtp")) != 0) msg_fatal("%s: %s", argv[optind], parse_err); if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0) msg_fatal("%s: %s", argv[optind], MAI_STRERROR(aierr)); myfree(buf); sa = (struct sockaddr *) & ss; if (res->ai_addrlen > sizeof(ss)) msg_fatal("address length %d > buffer length %d", (int) res->ai_addrlen, (int) sizeof(ss)); memcpy((char *) sa, res->ai_addr, res->ai_addrlen); sa_length = res->ai_addrlen; #ifdef HAS_SA_LEN sa->sa_len = sa_length; #endif freeaddrinfo(res); } /* * Make sure the SMTP server cannot run us out of memory by sending * never-ending lines of text. */ if (buffer == 0) { buffer = vstring_alloc(100); vstring_ctl(buffer, VSTRING_CTL_MAXLEN, (ssize_t) var_line_limit, 0); } /* * Make sure we have sender and recipient addresses. */ if (var_myhostname == 0) var_myhostname = get_hostname(); if (sender == 0 || recipient == 0) { vstring_sprintf(buffer, "foo@%s", var_myhostname); defaddr = mystrdup(vstring_str(buffer)); if (sender == 0) sender = defaddr; if (recipient == 0) recipient = defaddr; } /* * Start sessions. */ while (sessions-- > 0) { session = (SESSION *) mymalloc(sizeof(*session)); session->stream = 0; session->xfer_count = 0; session->connect_count = connect_count; session->next = 0; session_count++; startup(session); } for (;;) { event_loop(-1); if (session_count <= 0 && message_count <= 0) { if (count) { VSTREAM_PUTC('\n', VSTREAM_OUT); vstream_fflush(VSTREAM_OUT); } exit(0); } } }