зеркало из https://github.com/mozilla/pjs.git
Fix range off by one bug. Properly fix local doc link. Add glob support to SMTP sends
This commit is contained in:
Родитель
e237ef56e9
Коммит
eab4a51869
|
@ -1,873 +0,0 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
/*
|
||||
bench.c has all the OS independent utilities.
|
||||
*/
|
||||
#include "bench.h"
|
||||
|
||||
/* allocate memory and exit if out of memory */
|
||||
void *
|
||||
mymalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
errexit(stderr, "Call to malloc(%d) failed\n", size);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
mycalloc(size_t size)
|
||||
{
|
||||
void *retp;
|
||||
|
||||
if ((retp = mymalloc(size)) == NULL)
|
||||
return NULL;
|
||||
memset(retp, 0, size);
|
||||
return(retp);
|
||||
}
|
||||
|
||||
/* allocate memory and exit if out of memory */
|
||||
void *
|
||||
myrealloc(void *ptr, size_t size)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
if (ptr == NULL)
|
||||
errexit(stderr, "Call to realloc(%d, %d) failed\n", ptr, size);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
myfree(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *
|
||||
mystrdup(const char *cp)
|
||||
{
|
||||
char *retcp;
|
||||
|
||||
if ((retcp = (char *)mymalloc(strlen(cp)+1)) == NULL)
|
||||
return NULL;
|
||||
strcpy(retcp, cp);
|
||||
|
||||
return retcp;
|
||||
}
|
||||
|
||||
/*
|
||||
* waitReadWrite(int fd, int flags)
|
||||
* parameter: fd: file descriptor
|
||||
* read_write: 0 --> read
|
||||
* 1 --> write
|
||||
* 2 --> read & write
|
||||
* return: NON-Zero something is read
|
||||
* 0 sth is wrong
|
||||
*/
|
||||
|
||||
#define CHECK_READ 0x0
|
||||
#define CHECK_WRITE 0x1
|
||||
#define CHECK_RW 0x2
|
||||
#define CHECK_ALL 0x3
|
||||
#define CHECK_FOREVER 0x4
|
||||
|
||||
#define waitReadable(fd) waitReadWrite((fd),CHECK_READ)
|
||||
#define waitWriteable(fd) waitReadWrite((fd),CHECK_WRITE)
|
||||
#define waitWriteableForever(fd) waitReadWrite((fd),CHECK_WRITE | CHECK_FOREVER)
|
||||
|
||||
/* Return 1 if bytes readable; 0 if error or time up */
|
||||
int
|
||||
waitReadWrite(int fd, int flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
struct pollfd pfd;
|
||||
int timeleft;
|
||||
int ret;
|
||||
int timeouts = 0;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLHUP;
|
||||
|
||||
if ((flags & CHECK_ALL) == CHECK_READ) {
|
||||
pfd.events |= POLLIN;
|
||||
} else if ((flags & CHECK_ALL) == CHECK_WRITE) {
|
||||
pfd.events |= POLLOUT;
|
||||
} else if ((flags & CHECK_ALL) == CHECK_RW) {
|
||||
pfd.events |= (POLLIN | POLLOUT);
|
||||
}
|
||||
for (;;) {
|
||||
if (flags & CHECK_FOREVER) { /* for writing status out */
|
||||
timeleft = 60;
|
||||
} else {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr, "waitReadWrite gf_timeexpired=%d\n",
|
||||
gf_timeexpired);
|
||||
return 0;
|
||||
}
|
||||
timeleft = 5;
|
||||
}
|
||||
|
||||
/*fprintf(stderr, "poll(%d,%d)\n", fd, timeleft*1000);*/
|
||||
ret = poll(&pfd, 1, timeleft*1000);
|
||||
/*fprintf(stderr, "poll(%d,%d)=%d\n", fd, timeleft*1000, ret);*/
|
||||
|
||||
if (ret == 0) {
|
||||
if (!(flags & CHECK_FOREVER) && (++timeouts >= 12)) {
|
||||
return 0; /* time out after 60sec total */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
D_PRINTF(stderr, "waitReadWrite error ret=%d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* error */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
retryRead(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
{
|
||||
int ret;
|
||||
int bytesread = 0;
|
||||
|
||||
D_PRINTF(debugfile, "retryRead(%d, %d (gf_timeexpired=%d))\n",
|
||||
sock, count, gf_timeexpired);
|
||||
while (count) {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF (debugfile, "retryRead gf_timeexpired\n");
|
||||
strcpy (ptcx->errMsg, "retryRead:TIMEOUT");
|
||||
break;
|
||||
}
|
||||
if (0 == waitReadable (sock)) {
|
||||
D_PRINTF (debugfile, "retryRead waitReadable time/error\n");
|
||||
strcpy (ptcx->errMsg, "waitReadable TIMEOUT<retryRead");
|
||||
break;
|
||||
}
|
||||
ret = NETREAD(sock, buf, count);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
if (bytesread > 0)
|
||||
break; /* return what we got so far */
|
||||
if (waitReadable(sock)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (bytesread == 0) {
|
||||
bytesread = -1;
|
||||
}
|
||||
sprintf (ptcx->errMsg, "retryRead(sock=%d) IO error", sock);
|
||||
break;
|
||||
}
|
||||
bytesread += ret;
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
break; /* return any good bytes */
|
||||
}
|
||||
D_PRINTF(debugfile, "retryRead(%d, %d)=%d\n", sock, count, bytesread);
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
int
|
||||
retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
{
|
||||
int ret;
|
||||
int byteswritten = 0;
|
||||
|
||||
D_PRINTF(debugfile, "retryWrite(%d, %d)\n", sock, count);
|
||||
while (count) {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF (debugfile, "retryWrite gf_timeexpired\n");
|
||||
strcpy (ptcx->errMsg, "read:timeout");
|
||||
break;
|
||||
}
|
||||
ret = NETWRITE(sock, buf, count);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
if (waitWriteable(sock)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (byteswritten == 0) {
|
||||
byteswritten = -1;
|
||||
}
|
||||
sprintf (ptcx->errMsg,
|
||||
"retryWrite(sock=%d, n=%d) IO error", sock, count);
|
||||
break;
|
||||
}
|
||||
byteswritten += ret;
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
}
|
||||
D_PRINTF(debugfile, "retryWrite(%d, %d)=%d\n", sock, count, byteswritten);
|
||||
return byteswritten;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
readResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen)
|
||||
{
|
||||
/* read the server response and do nothing with it */
|
||||
int totalbytesread = 0;
|
||||
int resplen = 0;
|
||||
int bytesread;
|
||||
char *offset;
|
||||
|
||||
memset (buffer, 0, sizeof(buffer));
|
||||
while (totalbytesread < buflen)
|
||||
{
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"readResponse() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
if ((bytesread = retryRead(ptcx, sock, buffer+totalbytesread,
|
||||
buflen-totalbytesread)) <= 0) {
|
||||
strcat (ptcx->errMsg, "<ReadResponse");
|
||||
return -1;
|
||||
}
|
||||
totalbytesread += bytesread;
|
||||
|
||||
buffer[totalbytesread] = 0;
|
||||
/* search for end of response (assume single line) */
|
||||
if ((offset = strstr(buffer, "\n"))) {
|
||||
resplen = offset - buffer + 1;
|
||||
break;
|
||||
} else if ((offset = strstr(buffer, "\r\n"))) {
|
||||
resplen = offset - buffer + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
D_PRINTF(debugfile, "Read from server: %s\n", buffer );
|
||||
|
||||
ptcx->bytesread += resplen;
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
/* expects pointers to buffers of these sizes */
|
||||
/* char command[MAX_COMMAND_LEN] */
|
||||
/* char response[MAX_RESPONSE_LEN] */
|
||||
|
||||
int
|
||||
doCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (response == NULL)
|
||||
return -1;
|
||||
memset(response, 0, resplen);
|
||||
|
||||
/* send the command already formatted */
|
||||
if ((ret = sendCommand(ptcx, sock, command)) == -1) {
|
||||
strcat (ptcx->errMsg, "<doCommandResponse");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read server response line */
|
||||
if ((ret = readResponse(ptcx, sock, response, resplen)) <= 0) {
|
||||
strcat (ptcx->errMsg, "<doCommandResponse");
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sendCommand(ptcx_t ptcx, SOCKET sock, char *command)
|
||||
{
|
||||
int writelen;
|
||||
int sentbytes = 0;
|
||||
int sent;
|
||||
|
||||
D_PRINTF(debugfile, "sendCommand(%s)\n", command );
|
||||
|
||||
writelen = strlen(command);
|
||||
|
||||
while (sentbytes < writelen) {
|
||||
if ((sent = retryWrite(ptcx, sock, command + sentbytes,
|
||||
writelen - sentbytes)) == -1) {
|
||||
strcat (ptcx->errMsg, "<sendCommand");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sentbytes += sent;
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"sendCommand() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptcx->byteswritten += sentbytes;
|
||||
|
||||
return sentbytes;
|
||||
}
|
||||
|
||||
/* assumes we already included the <CRLF>.<CRLF> at the end of message */
|
||||
int
|
||||
sendMessage(ptcx_t ptcx, SOCKET sock, char *message)
|
||||
{
|
||||
int writelen;
|
||||
int sentbytes = 0;
|
||||
int sent;
|
||||
|
||||
writelen = strlen(message);
|
||||
|
||||
D_PRINTF(debugfile, "Writing message to server: len=%d\n", writelen );
|
||||
|
||||
while (sentbytes < writelen) {
|
||||
if ((sent = retryWrite(ptcx, sock, message + sentbytes,
|
||||
writelen - sentbytes)) == -1) {
|
||||
strcat (ptcx->errMsg, "<sendMessage");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sentbytes += sent;
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"sendMessage() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptcx->byteswritten += sentbytes;
|
||||
|
||||
return sentbytes;
|
||||
}
|
||||
|
||||
/* This is how status messages are sent */
|
||||
int
|
||||
sendOutput(int fd, char *string)
|
||||
{
|
||||
int writelen;
|
||||
int sentbytes = 0;
|
||||
int sent;
|
||||
|
||||
/*D_PRINTF(stderr, "sendOutput(%d, %s)\n", fd, string );*/
|
||||
|
||||
writelen = strlen(string);
|
||||
|
||||
while (sentbytes < writelen) {
|
||||
sent = OUTPUT_WRITE(fd, string + sentbytes, writelen - sentbytes);
|
||||
|
||||
if (sent == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
if (waitWriteableForever(fd))
|
||||
continue;
|
||||
else
|
||||
returnerr(stderr,
|
||||
"sendOutput(%d) - Got EAGAIN and fd not ready\n",
|
||||
fd); /* has this ever happened? die??? */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
sentbytes += sent;
|
||||
|
||||
#if 0
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr,"sendOutput() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return sentbytes;
|
||||
}
|
||||
|
||||
/* read from socket until we find <CRLF>.<CRLF> */
|
||||
int
|
||||
retrMsg(ptcx_t ptcx, char *buffer, int maxBytes, SOCKET sock)
|
||||
{
|
||||
int totalbytesread = 0;
|
||||
int bytesread;
|
||||
int sz;
|
||||
char garbage[10000], *sp;
|
||||
|
||||
if (buffer) {
|
||||
sp = buffer;
|
||||
sz = maxBytes-1;
|
||||
} else {
|
||||
sp = garbage;
|
||||
sz = sizeof (garbage)-1;
|
||||
}
|
||||
|
||||
while (!buffer || (totalbytesread < maxBytes)) {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"Time expired while reading messages - in retrMsg\n");
|
||||
break;
|
||||
}
|
||||
|
||||
bytesread = retryRead(ptcx, sock,
|
||||
sp+totalbytesread, sz-totalbytesread);
|
||||
|
||||
/*D_PRINTF (stderr, "retrMsg: got %d bytes\n", bytesread);*/
|
||||
if (bytesread <= 0) {
|
||||
strcat (ptcx->errMsg, "<retrMsg");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptcx->bytesread += bytesread;
|
||||
totalbytesread += bytesread;
|
||||
|
||||
sp[totalbytesread] = 0; /* terminate string */
|
||||
if (NULL != strstr (sp, "\r\n.\r\n")) {
|
||||
D_PRINTF (stderr, "retrMsg: saw terminating string\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strncmp (sp, "-ERR", 4)) { /* watch for error response */
|
||||
trimEndWhite (sp);
|
||||
sprintf (ptcx->errMsg, "retrMsg: ERROR response=[%.40s]", sp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!buffer && (totalbytesread > 5)) { /* reset our scratch buffer */
|
||||
int i;
|
||||
char *from, *to;
|
||||
/* shuffle last 5 bytes to start */
|
||||
from = sp + totalbytesread - 5;
|
||||
to = garbage;
|
||||
for (i=5; i > 0; --i)
|
||||
*to++ = *from++;
|
||||
totalbytesread = 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return totalbytesread;
|
||||
}
|
||||
|
||||
/*
|
||||
Record current time
|
||||
*/
|
||||
int
|
||||
timeval_stamp(struct timeval *tv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = GETTIMEOFDAY(tv, NULL);
|
||||
if (rc != 0) {
|
||||
errexit(stderr, "Error from gettimeofday()\n");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
This is the main event timing routine. This resets counters
|
||||
Note that event timing cannot be nested.
|
||||
*/
|
||||
void
|
||||
event_start(ptcx_t ptcx, event_timer_t *pevent)
|
||||
{
|
||||
ptcx->bytesread = 0;
|
||||
ptcx->byteswritten = 0;
|
||||
timeval_stamp(&ptcx->starttime);
|
||||
}
|
||||
|
||||
/*
|
||||
This ends an event and increments the counters
|
||||
Multiple stops are no longer allowed. (broke min, max, and sum of t*t)
|
||||
*/
|
||||
void
|
||||
event_stop(ptcx_t ptcx, event_timer_t *pevent)
|
||||
{
|
||||
struct timeval tv;
|
||||
double t;
|
||||
|
||||
timeval_stamp(&tv); /* get the time */
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) { /* if aborting run, ignore it */
|
||||
return;
|
||||
}
|
||||
pevent->trys++; /* count try with time */
|
||||
pevent->bytesread += ptcx->bytesread;
|
||||
pevent->byteswritten += ptcx->byteswritten;
|
||||
t = compdifftime_double(&tv, &ptcx->starttime); /* find time span */
|
||||
pevent->elapsedtime += t;
|
||||
pevent->elapsedtimesq += t * t;
|
||||
|
||||
if (t > pevent->maxtime) /* check max time */
|
||||
pevent->maxtime = t;
|
||||
|
||||
/* this gets initialized to 0.0 */
|
||||
if (!pevent->mintime || /* check min time */
|
||||
((t > 0.0) && (t < pevent->mintime))) /* smallest non 0 time */
|
||||
pevent->mintime = t;
|
||||
}
|
||||
|
||||
/*
|
||||
reset the event structure
|
||||
*/
|
||||
void
|
||||
event_reset(event_timer_t *pevent)
|
||||
{
|
||||
memset(pevent, 0, sizeof(event_timer_t));
|
||||
}
|
||||
|
||||
/*
|
||||
Add pincr event into psum event
|
||||
*/
|
||||
void
|
||||
event_sum(event_timer_t *psum, event_timer_t *pincr)
|
||||
{
|
||||
psum->trys += pincr->trys;
|
||||
psum->errs += pincr->errs;
|
||||
psum->bytesread += pincr->bytesread;
|
||||
psum->byteswritten += pincr->byteswritten;
|
||||
psum->elapsedtime += pincr->elapsedtime;
|
||||
psum->elapsedtimesq += pincr->elapsedtimesq;
|
||||
if (pincr->maxtime > psum->maxtime)
|
||||
psum->maxtime = pincr->maxtime;
|
||||
if (!psum->mintime ||
|
||||
((pincr->mintime > 0.0) && (pincr->mintime < psum->mintime)))
|
||||
psum->mintime = pincr->mintime;
|
||||
}
|
||||
|
||||
/* Format string for every timer. Must match event_to_text */
|
||||
const char *gs_eventToTextFormat = "Try+Error/BytesR+BytesW/Time[TimeMin,TimeMax]Time2";
|
||||
|
||||
/*
|
||||
Output event into ebuf.
|
||||
*/
|
||||
char *
|
||||
event_to_text(event_timer_t *pevent, char *ebuf)
|
||||
{
|
||||
/* these have to be sane to avoid overflowing the print buffer */
|
||||
assert (pevent->bytesread < 1.0e20);
|
||||
assert (pevent->byteswritten < 1.0e20);
|
||||
assert (pevent->elapsedtime < 1.0e10);
|
||||
assert (pevent->maxtime < 1.0e10);
|
||||
assert (pevent->elapsedtimesq < 1.0e20);
|
||||
if (pevent->elapsedtime) {
|
||||
sprintf(ebuf, "%ld+%ld/%.0f+%.0f/%.6f[%.6f,%.6f]%.6f",
|
||||
pevent->trys, pevent->errs,
|
||||
pevent->bytesread, pevent->byteswritten,
|
||||
pevent->elapsedtime,
|
||||
pevent->mintime,
|
||||
pevent->maxtime,
|
||||
pevent->elapsedtimesq);
|
||||
} else { /* trim extra 0s for simple case*/
|
||||
sprintf(ebuf, "%ld+%ld/%.0f+%.0f/0.0[0.0,0.0]0.0",
|
||||
pevent->trys, pevent->errs,
|
||||
pevent->bytesread, pevent->byteswritten);
|
||||
}
|
||||
return ebuf;
|
||||
}
|
||||
|
||||
/*
|
||||
Given the last value we returned, return the next sequential or random value
|
||||
If the initial value is out of the range, a valid number will be returned.
|
||||
*/
|
||||
unsigned long
|
||||
rangeNext (range_t *range, unsigned long last)
|
||||
{
|
||||
unsigned long n;
|
||||
|
||||
assert (range != NULL);
|
||||
|
||||
if (range->span == 0) /* empty range (span = 0) */
|
||||
return range->first;
|
||||
|
||||
if (range->sequential > 0) { /* incrementing sequential */
|
||||
n = last + 1;
|
||||
} else if (range->sequential < 0) { /* decrementing sequential */
|
||||
n = last - 1;
|
||||
} else { /* random */
|
||||
n = range->first + (RANDOM() % range->span);
|
||||
assert ((n >= range->first) && (n <= range->last));
|
||||
}
|
||||
/* check range */
|
||||
if (n > range->last) n = range->first;
|
||||
if (n < range->first) n = range->last;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
Setup range given a first and last valid values (inclusive)
|
||||
Direction: + incrementing, 0 random, - decrementing
|
||||
If first and last are reversed, it will adjust accordingly
|
||||
*/
|
||||
void
|
||||
rangeSetFirstLast (range_t *range,
|
||||
unsigned long first,
|
||||
unsigned long last,
|
||||
int dir)
|
||||
{
|
||||
assert (range != NULL);
|
||||
if (last > first) {
|
||||
range->first = first;
|
||||
range->last = last;
|
||||
range->sequential = dir;
|
||||
} else {
|
||||
range->first = last;
|
||||
range->last = first;
|
||||
range->sequential = -dir;
|
||||
}
|
||||
range->span = range->last - range->first;
|
||||
}
|
||||
|
||||
/*
|
||||
Setup range given a first valid value (inclusive) and number (1..)
|
||||
Direction: + incrementing, 0 random, - decrementing
|
||||
*/
|
||||
void
|
||||
rangeSetFirstCount (range_t *range,
|
||||
unsigned long first,
|
||||
unsigned long num,
|
||||
int dir)
|
||||
{
|
||||
assert (range != NULL);
|
||||
if (num > 0) --num; /* adjust to internal notation */
|
||||
range->first = first;
|
||||
range->span = num;
|
||||
range->last = range->first + range->span;
|
||||
range->sequential = dir;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a specified range, split it based on process and thread
|
||||
*/
|
||||
void
|
||||
rangeSplit (range_t *whole, range_t *sub, int pnum, int tnum)
|
||||
{
|
||||
unsigned long perproc, first, count;
|
||||
|
||||
if (!whole->sequential) { /* just copy it */
|
||||
sub->first = whole->first;
|
||||
sub->last = whole->last;
|
||||
sub->span = whole->span;
|
||||
sub->sequential = whole->sequential;
|
||||
return;
|
||||
}
|
||||
/* To avoid cumulative rounding errors,
|
||||
the 0th process/thread rounds up, all others round down */
|
||||
perproc = (pnum > 0)
|
||||
? (whole->span+1) / gn_numprocs
|
||||
: (whole->span+1 + gn_numprocs - 1) / gn_numprocs;
|
||||
|
||||
if (perproc <= 0) perproc = 1; /* in case logins > processes */
|
||||
|
||||
if (gn_numthreads > 0) {
|
||||
unsigned long perthread;
|
||||
perthread = (tnum > 0)
|
||||
? perproc / gn_numthreads
|
||||
: (perproc + gn_numthreads - 1) / gn_numthreads;
|
||||
|
||||
if (perthread <= 0) perthread = 1; /* in case logins > threads */
|
||||
|
||||
first = whole->first + (perproc * pnum) + (perthread * tnum);
|
||||
count = perthread;
|
||||
} else {
|
||||
first = whole->first + (perproc * pnum);
|
||||
count = perproc;
|
||||
}
|
||||
/* If logins > processes*threads, we have to wrap the space */
|
||||
while (first >= (whole->first + whole->span+1)) {
|
||||
first -= whole->span+1;
|
||||
}
|
||||
assert (first >= whole->first);
|
||||
|
||||
rangeSetFirstCount (sub, first, count, whole->sequential);
|
||||
}
|
||||
|
||||
/*
|
||||
clear protocol independ parts of cmd_stats_t
|
||||
*/
|
||||
void
|
||||
cmdStatsInit (cmd_stats_t *p)
|
||||
{
|
||||
assert (NULL != p);
|
||||
|
||||
p->totalerrs = 0;
|
||||
p->totalcommands = 0;
|
||||
event_reset (&p->combined);
|
||||
event_reset (&p->idle);
|
||||
}
|
||||
|
||||
void
|
||||
stats_init(stats_t *p)
|
||||
{
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
|
||||
/*
|
||||
Given a buffer, trim tailing CR-NL and whitespace from it
|
||||
Moves 0 terminator to exclude extra portion.
|
||||
*/
|
||||
void
|
||||
trimEndWhite (char *buff)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (!buff) return;
|
||||
|
||||
for (cp = buff; *cp; ++cp); /* find the end */
|
||||
while (cp > buff) {
|
||||
--cp;
|
||||
if ((*cp != '\n') && (*cp !='\r')
|
||||
&& (*cp != '\t') && (*cp != ' ')) return;
|
||||
*cp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* never used */
|
||||
|
||||
int
|
||||
timeval_clear(struct timeval *tv)
|
||||
{
|
||||
if (tv == NULL)
|
||||
return -1;
|
||||
|
||||
tv->tv_sec = 0;
|
||||
tv->tv_usec = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* timetextbuf should be (SIZEOF_TIMEVALTEXT + 1) */
|
||||
char *
|
||||
timeval_to_text(const struct timeval *the_timeval, char *timetextbuf)
|
||||
{
|
||||
/*
|
||||
* given a timeval (seconds and microseconds), put the text
|
||||
* "seconds.microseconds" into timeval_as_text
|
||||
*/
|
||||
int seconds, microseconds;
|
||||
|
||||
seconds = the_timeval->tv_sec;
|
||||
microseconds = the_timeval->tv_usec;
|
||||
sprintf(timetextbuf, "%10d.%6.6d\t", seconds, microseconds);
|
||||
return timetextbuf;
|
||||
}
|
||||
|
||||
|
||||
/* doubletextbuf should be (SIZEOF_DOUBLETEXT+1) */
|
||||
|
||||
char *
|
||||
double_to_text(const double the_double, char *doubletextbuf)
|
||||
{
|
||||
/*
|
||||
* given a double, return text
|
||||
*/
|
||||
sprintf(doubletextbuf, "%17.01f\t", the_double);
|
||||
return(doubletextbuf);
|
||||
}
|
||||
|
||||
struct timeval
|
||||
text_to_timeval(ptcx_t ptcx, char *timeval_as_text) {
|
||||
long int seconds, microseconds;
|
||||
struct timeval the_timeval;
|
||||
|
||||
D_PRINTF(debugfile,"T/%d %s\n", (int)timeval_as_text, timeval_as_text);
|
||||
sscanf(timeval_as_text, "%ld.%ld", &seconds, µseconds);
|
||||
the_timeval.tv_sec = seconds;
|
||||
the_timeval.tv_usec = microseconds;
|
||||
return the_timeval;
|
||||
}
|
||||
|
||||
double
|
||||
text_to_double(ptcx_t ptcx, char *double_as_text) {
|
||||
double the_double = 0;
|
||||
int returnval = 0;
|
||||
|
||||
D_PRINTF(debugfile,"D/%d %s\n", (int)double_as_text, double_as_text);
|
||||
returnval = sscanf(double_as_text, "%lf", &the_double);
|
||||
if (returnval == 1)
|
||||
return(the_double);
|
||||
else
|
||||
return(0.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* not currently used, but useful for debugging */
|
||||
void
|
||||
dumpevent(ptcx_t ptcx, event_timer_t *pevent)
|
||||
{
|
||||
D_PRINTF(debugfile, "trys=%d errs=%d br=%f bw=%f elapsed=%f sq=%f\n",
|
||||
pevent->trys, pevent->errs,
|
||||
pevent->bytesread, pevent->byteswritten,
|
||||
pevent->elapsedtime,
|
||||
pevent->elapsedtimesq);
|
||||
}
|
||||
|
||||
void
|
||||
dumptimer(ptcx_t ptcx, cmd_stats_t *rqsttimer)
|
||||
{
|
||||
if (gn_debug) {
|
||||
D_PRINTF(debugfile, "Connect: ");
|
||||
dumpevent(ptcx, &rqsttimer->connect);
|
||||
|
||||
D_PRINTF(debugfile, "Banner: ");
|
||||
dumpevent(ptcx, &rqsttimer->banner);
|
||||
|
||||
D_PRINTF(debugfile, "Login: ");
|
||||
dumpevent(ptcx, &rqsttimer->login);
|
||||
|
||||
D_PRINTF(debugfile, "Cmd: ");
|
||||
dumpevent(ptcx, &rqsttimer->cmd);
|
||||
|
||||
D_PRINTF(debugfile, "MsgRead: ");
|
||||
dumpevent(ptcx, &rqsttimer->msgread);
|
||||
|
||||
D_PRINTF(debugfile, "MsgWrite: ");
|
||||
dumpevent(ptcx, &rqsttimer->msgwrite);
|
||||
|
||||
D_PRINTF(debugfile, "Idle: ");
|
||||
dumpevent(ptcx, &rqsttimer->idle);
|
||||
|
||||
D_PRINTF(debugfile, "Logout: ");
|
||||
dumpevent(ptcx, &rqsttimer->logout);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
@ -372,7 +372,6 @@ extern void rqstat_to_buffer(char *buf, char *comm, cmd_stats_t *stats);
|
|||
extern int readResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen);
|
||||
extern int sendCommand(ptcx_t ptcx, SOCKET sock, char *command);
|
||||
extern int doCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen);
|
||||
extern int sendMessage(ptcx_t ptcx, SOCKET sock, char *message);
|
||||
extern int sendOutput(int fd, char *command);
|
||||
extern int retrMsg(ptcx_t ptcx, char *buffer, int maxBytes, SOCKET sock);
|
||||
extern void trimEndWhite (char *buff);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
/* http-util.h -- Shared HTTP functions */
|
||||
|
||||
#define HTTP_HEADER_BREAK "\r\n\r\n"
|
||||
#define HTTP_CONTENT_TYPE_POST "Content-type: application/x-www-form-urlencoded"
|
||||
#define HTTP_CONTENT_LENGTH "Content-length:"
|
||||
#define HTTP_LOCATION "Location:"
|
||||
#define HTTP_PROTOCOL "http://"
|
||||
|
||||
#define HTTP_MAX_RECONNECTS 5 /* max to reconnect/retry a command */
|
||||
|
||||
/* Callback type for parsing messages on the fly */
|
||||
typedef int (*parseMsgPtr_t)(
|
||||
ptcx_t, pmail_command_t, void *me,
|
||||
char *buffer, int bytesInBuffer, char **searchStr, const char **findStr);
|
||||
|
||||
extern int HttpConnect(ptcx_t ptcx, resolved_addr_t *hostInfo,
|
||||
event_timer_t *timer);
|
||||
|
||||
extern int HttpReadResponse(ptcx_t ptcx, mail_command_t *cmd, void *me,
|
||||
char *responce, int resplen,
|
||||
parseMsgPtr_t msgParse);
|
||||
|
||||
extern int HttpCommandResponse (ptcx_t ptcx, mail_command_t *cmd, void *me,
|
||||
resolved_addr_t *hostInfo, event_timer_t *reconnect,
|
||||
event_timer_t *timer, char *command, char *response, int resplen,
|
||||
parseMsgPtr_t msgParse);
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
@ -72,9 +72,12 @@ typedef struct _doIMAP4_state {
|
|||
int *searchSchedule;
|
||||
} doIMAP4_state_t;
|
||||
|
||||
/* IMAP flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
#define leaveMailUnseen 0x02
|
||||
|
||||
static void doImap4Exit (ptcx_t ptcx, doIMAP4_state_t *me);
|
||||
|
||||
#define IMAP_LEAVE_UNSEEN 2
|
||||
|
||||
static int
|
||||
ImapParseNameValue (pmail_command_t cmd,
|
||||
|
@ -87,17 +90,21 @@ ImapParseNameValue (pmail_command_t cmd,
|
|||
if (pishParseNameValue(cmd, name, tok) == 0)
|
||||
; /* done */
|
||||
else if (strcmp(name, "leavemailonserver") == 0) {
|
||||
int v = atoi(tok);
|
||||
if (v <= 0) { /* turn off */
|
||||
pish->leaveMailOnServer = 0;
|
||||
} else if (0 == pish->leaveMailOnServer) { /* turn on if < leavemailunseen */
|
||||
pish->leaveMailOnServer = 1;
|
||||
if (atoi(tok) > 0) {
|
||||
pish->flags |= leaveMailOnServer;
|
||||
} else { /* turn on if < leavemailunseen */
|
||||
pish->flags &= ~leaveMailOnServer;
|
||||
}
|
||||
D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);
|
||||
/*D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);*/
|
||||
}
|
||||
else if (strcmp(name, "leavemailunseen") == 0) {
|
||||
pish->leaveMailOnServer = IMAP_LEAVE_UNSEEN * (atoi(tok) > 0);
|
||||
D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);
|
||||
if (atoi(tok) > 0) {
|
||||
/* leaving mail unseen implies leaving on server */
|
||||
pish->flags |= leaveMailUnseen | leaveMailOnServer;
|
||||
} else { /* turn on if < leavemailunseen */
|
||||
pish->flags &= ~leaveMailUnseen;
|
||||
}
|
||||
/*D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);*/
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
|
@ -834,15 +841,15 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
|||
}
|
||||
|
||||
/* if we're told to leave mail on server, do not delete the message */
|
||||
if (pish->leaveMailOnServer < IMAP_LEAVE_UNSEEN) {
|
||||
if (0 == pish->leaveMailOnServer) {
|
||||
/* mark the msg \deleted and \seen */
|
||||
sprintf(command, "%d STORE %d +FLAGS (\\DELETED \\SEEN)%s",
|
||||
++pIMAP->seq_num,i, CRLF);
|
||||
} else {
|
||||
if (!(pish->flags & leaveMailUnseen)) {
|
||||
if (pish->flags & leaveMailOnServer) { /* just mark seen */
|
||||
/* mark the msg \seen needed??? */
|
||||
sprintf(command, "%d STORE %d +FLAGS (\\SEEN)%s",
|
||||
++pIMAP->seq_num,i, CRLF);
|
||||
} else { /* delete message */
|
||||
/* mark the msg \deleted and \seen */
|
||||
sprintf(command, "%d STORE %d +FLAGS (\\DELETED \\SEEN)%s",
|
||||
++pIMAP->seq_num,i, CRLF);
|
||||
}
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doImapCommandResponse(ptcx, sock, pIMAP->seq_num,
|
||||
|
@ -859,7 +866,7 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
|||
}
|
||||
}
|
||||
|
||||
if (0 == pish->leaveMailOnServer) { /* expunge if we are deleting */
|
||||
if (!(pish->flags & leaveMailOnServer)) { /* expunge if we are deleting */
|
||||
/* EXPUNGE \deleted messages */
|
||||
sprintf(command, "%d EXPUNGE%s", ++pIMAP->seq_num, CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
|
@ -1,633 +0,0 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
/*
|
||||
* parse the workload description file
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bench.h"
|
||||
|
||||
/* global variables */
|
||||
param_list_t *g_default_params; /* list of default values */
|
||||
|
||||
|
||||
/* Find a protocol in the global protocol list */
|
||||
protocol_t *
|
||||
protocol_get (char *name)
|
||||
{
|
||||
protocol_t *pp;
|
||||
|
||||
for (pp=g_protocols; pp->name != NULL; ++pp) {
|
||||
/* we only check the length of the registered protocol name */
|
||||
/* that way NAME can have additonal stuff after it */
|
||||
/* This is much better than the old single letter checking */
|
||||
if (0 == strnicmp (name, pp->name, strlen (pp->name)))
|
||||
return pp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
converts a string of the form #x to seconds
|
||||
where x can be a unit specifier of
|
||||
d or D days
|
||||
h or H hours
|
||||
m or M minutes
|
||||
s or S seconds
|
||||
the default is seconds
|
||||
*/
|
||||
int
|
||||
time_atoi(const char *pstr)
|
||||
{
|
||||
int ret=0;
|
||||
int len = strlen(pstr);
|
||||
|
||||
if (!pstr[0]) return 0;
|
||||
switch (pstr[len-1]) {
|
||||
case 'd': /* days */
|
||||
case 'D':
|
||||
ret = 24 * 60 * 60 * atoi(pstr);
|
||||
break;
|
||||
case 'h': /* hours */
|
||||
case 'H':
|
||||
ret = 60 * 60 * atoi(pstr);
|
||||
break;
|
||||
case 'm': /* minutes */
|
||||
case 'M':
|
||||
ret = 60 * atoi(pstr);
|
||||
break;
|
||||
case 's': /* seconds */
|
||||
case 'S':
|
||||
default:
|
||||
ret = atoi(pstr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Simple keyword indexed string storage
|
||||
This kind of thing has been invented many times. Once more with gusto!
|
||||
*/
|
||||
param_list_t *
|
||||
paramListInit (void)
|
||||
{
|
||||
param_list_t *np = (param_list_t *)mycalloc (sizeof (param_list_t));
|
||||
return np;
|
||||
}
|
||||
|
||||
/* paramListAdd returns: 1 update existing value, 0 new, -1 out of memory */
|
||||
int
|
||||
paramListAdd (param_list_t *list,
|
||||
const char *name,
|
||||
const char *value)
|
||||
{
|
||||
param_list_t *pl;
|
||||
int found = 0;
|
||||
assert (list != NULL);
|
||||
assert (name != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
if (NULL == list->name) { /* first one special case */
|
||||
list->name = mystrdup (name);
|
||||
if (NULL == list->name) return -1; /* out of memory */
|
||||
list->value = mystrdup (value);
|
||||
if (NULL == list->value) return -1; /* out of memory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pl = list; pl->next; pl = pl->next) {
|
||||
if (0 == strcmp (pl->name, name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
free (pl->value);
|
||||
pl->value = mystrdup (value);
|
||||
if (NULL == pl->value) return -1; /* out of memory */
|
||||
return 1;
|
||||
} else {
|
||||
param_list_t *np = (param_list_t *)mycalloc (sizeof (param_list_t));
|
||||
if (NULL == np) return -1; /* out of memory */
|
||||
np->name = mystrdup (name);
|
||||
if (NULL == np->name) return -1; /* out of memory */
|
||||
np->value = mystrdup (value);
|
||||
if (NULL == np->value) return -1; /* out of memory */
|
||||
pl->next = np;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* paramListGet returns value or NULL */
|
||||
char *
|
||||
paramListGet (param_list_t *list,
|
||||
const char *name)
|
||||
{
|
||||
param_list_t *pl;
|
||||
assert (list != NULL);
|
||||
assert (name != NULL);
|
||||
|
||||
for (pl = list; pl->next; pl = pl->next) {
|
||||
if (0 == strcmp (pl->name, name)) {
|
||||
return pl->value;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Simple keyword indexed string storage
|
||||
This kind of thing has been invented many times. Once more with gusto!
|
||||
*/
|
||||
string_list_t *
|
||||
stringListInit (const char *value)
|
||||
{
|
||||
string_list_t *np = (string_list_t *)mycalloc (sizeof (string_list_t));
|
||||
if (value)
|
||||
np->value = mystrdup (value); /* This can be NULL */
|
||||
return np;
|
||||
}
|
||||
|
||||
void
|
||||
stringListFree (string_list_t *list)
|
||||
{
|
||||
string_list_t *pl, *next;
|
||||
assert (list != NULL);
|
||||
|
||||
for (pl = list; pl; pl = next) {
|
||||
next = pl->next;
|
||||
if (pl->value)
|
||||
free (pl->value);
|
||||
free (pl);
|
||||
}
|
||||
}
|
||||
|
||||
/* stringListAdd returns: 0 new, -1 out of memory */
|
||||
int
|
||||
stringListAdd (string_list_t *list,
|
||||
const char *value)
|
||||
{
|
||||
string_list_t *pl;
|
||||
string_list_t *np;
|
||||
assert (list != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
if (NULL == list->value) { /* first one special case */
|
||||
list->value = mystrdup (value);
|
||||
if (NULL == list->value) return -1; /* out of memory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pl = list; pl->next; pl = pl->next)
|
||||
; /* skip to end */
|
||||
np = (string_list_t *)mycalloc (sizeof (string_list_t));
|
||||
if (NULL == np)
|
||||
return -1; /* out of memory */
|
||||
np->value = mystrdup (value);
|
||||
if (NULL == np->value)
|
||||
return -1; /* out of memory */
|
||||
pl->next = np;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return non 0 if whitespace */
|
||||
#define IS_WHITE(c) ((' ' == (c)) || '\t' == (c))
|
||||
#define IS_TERM(c) (('\r' == (c)) || '\n' == (c))
|
||||
#define IS_NUM(c) (('0' <= (c)) && ('9' >= (c)))
|
||||
|
||||
/*
|
||||
Get a 'line' from a text buffer (terminated by CR-NL or NL)
|
||||
Handle comments.
|
||||
Skip empty lines.
|
||||
Handle continued lines (backslash as last character)
|
||||
|
||||
Return the pointer to the next line (or NULL at end)
|
||||
*/
|
||||
char *
|
||||
get_line_from_buffer (char *buffer, /* buffer to sort through */
|
||||
char *line, /* line buffer to fill in */
|
||||
int *lineCount, /* count of lines */
|
||||
int continuation) /* part of previous line */
|
||||
{
|
||||
char *end, *start;
|
||||
char *next;
|
||||
int len;
|
||||
|
||||
assert (buffer != NULL);
|
||||
assert (line != NULL);
|
||||
|
||||
next = strchr (buffer, '\n');
|
||||
if (next) {
|
||||
++next; /* start point for next line */
|
||||
} else if (strlen (buffer) > 0) {
|
||||
d_printf (stderr, "Last line missing NEWLINE\n");
|
||||
} else { /* done with buffer */
|
||||
*line = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (lineCount) ++(*lineCount); /* increment line count */
|
||||
|
||||
if (continuation) {
|
||||
/* continuation lines keep everything */
|
||||
start = buffer;
|
||||
end = next-1;
|
||||
} else {
|
||||
/* find usefull text */
|
||||
len = strcspn (buffer, "#\r\n");
|
||||
if (!len) { /* empty line, go to next */
|
||||
return get_line_from_buffer (next, line, lineCount, continuation);
|
||||
}
|
||||
/* skip trailing white too */
|
||||
for (end = buffer + len; end > buffer; --end) {
|
||||
if (!IS_WHITE (end[-1])) break;
|
||||
}
|
||||
if (end == buffer) { /* blank line */
|
||||
return get_line_from_buffer (next, line, lineCount, continuation);
|
||||
}
|
||||
|
||||
/* find leading whitespace */
|
||||
start = buffer + strspn (buffer, " \t");
|
||||
}
|
||||
|
||||
assert (end > start); /* we should have found blank above */
|
||||
|
||||
strncpy(line, start, end - start); /* get a line */
|
||||
line[end-start] = '\0';
|
||||
|
||||
if (line[end-start-1] == '\\') { /* continuation line */
|
||||
return get_line_from_buffer (next, &line[end-start-1], lineCount, 1);
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "clean line [%s]\n", line);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*
|
||||
return 1 if for us, 0 if everyone, -1 if not for us
|
||||
*/
|
||||
int
|
||||
check_hostname_attribute (const char *line)
|
||||
{
|
||||
char *hostp;
|
||||
/* Section open, check if for us */
|
||||
if ((hostp = strstr(line, "hosts="))
|
||||
|| (hostp = strstr(line, "HOSTS="))) {
|
||||
hostp = strchr (hostp, '='); /* skip to the equals */
|
||||
assert (hostp != NULL);
|
||||
|
||||
/* look for our hostname */
|
||||
if (strstr(hostp, gs_parsename) != NULL) {
|
||||
/* should check for complete string match */
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* not host specific */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Protocol independent parsing
|
||||
*/
|
||||
int
|
||||
cmdParseNameValue (pmail_command_t cmd,
|
||||
char *name,
|
||||
char *tok)
|
||||
{
|
||||
if (strcmp(name, "numloops") == 0)
|
||||
cmd->numLoops = atoi(tok);
|
||||
else if (strcmp(name, "throttle") == 0)
|
||||
cmd->throttle = atoi(tok);
|
||||
else if (strcmp(name, "weight") == 0)
|
||||
cmd->weight = atoi(tok);
|
||||
else if (strcmp(name, "idletime") == 0)
|
||||
cmd->idleTime = time_atoi(tok);
|
||||
else if (strcmp(name, "blockid") == 0)
|
||||
cmd->blockID = time_atoi(tok);
|
||||
else if (strcmp(name, "blocktime") == 0)
|
||||
cmd->blockTime = time_atoi(tok);
|
||||
else if (strcmp(name, "loopdelay") == 0)
|
||||
cmd->loopDelay = time_atoi(tok);
|
||||
else if (strcmp(name, "checkmailinterval") == 0) /* BACK COMPAT */
|
||||
cmd->loopDelay = time_atoi(tok);
|
||||
else
|
||||
return 0; /* no match */
|
||||
|
||||
return 1; /* matched it */
|
||||
}
|
||||
|
||||
/*
|
||||
* count_num_commands()
|
||||
* given a commandsfile string, count the valid command for us.
|
||||
TODO Dynamically load the protocols found
|
||||
*/
|
||||
static int
|
||||
count_num_commands(char *commands)
|
||||
{
|
||||
char *cmdptr = commands;
|
||||
int num_comms = 0;
|
||||
char line[LINE_BUFSIZE];
|
||||
|
||||
/*
|
||||
* parse through the string line-by-line,strip out comments
|
||||
*/
|
||||
/*D_PRINTF(stderr, "count_num_commands[%s]\n", commands);*/
|
||||
|
||||
while (NULL != (cmdptr = get_line_from_buffer (cmdptr, line, NULL, 0))) {
|
||||
/* increment count if we've hit a open tag (e.g. <SMTP...) and
|
||||
it's not the <Default> tag, or <Graph> tag */
|
||||
if (line[0] != '<') continue; /* not an open */
|
||||
if (line[1] == '/') continue; /* a close */
|
||||
if (0 == strnicmp (line+1, "default", 7)) continue; /* default */
|
||||
|
||||
/* should already be filtered out */
|
||||
if (0 == strnicmp (line+1, "graph", 5)) continue; /* graph */
|
||||
|
||||
/* Section open, check if for us */
|
||||
if (check_hostname_attribute (line) < 0) {
|
||||
D_PRINTF (stderr, "count_num_commands: section not for us '%s'\n",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find protocol */
|
||||
if (NULL == protocol_get (line+1)) {
|
||||
/* TODO load handler */
|
||||
|
||||
/* TODO add to protocol list */
|
||||
|
||||
D_PRINTF (stderr, "count_num_commands: No handler for '%s'\n",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "count_num_commands: Found section '%s'\n", line);
|
||||
num_comms++;
|
||||
}
|
||||
|
||||
return (num_comms);
|
||||
}
|
||||
|
||||
char *
|
||||
string_tolower(char *string)
|
||||
{
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
|
||||
/* convert to lower case */
|
||||
for (; *string != '\0'; ++string) {
|
||||
*string = tolower (*string);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
char *
|
||||
string_unquote(char *string)
|
||||
{
|
||||
int len, num;
|
||||
char *from, *to;
|
||||
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
|
||||
len = strlen(string);
|
||||
|
||||
if (string[0] == '"' && string[len-1] == '"') {
|
||||
/* remove matching double-quotes */
|
||||
string[len-1] = '\0';
|
||||
++string;
|
||||
}
|
||||
|
||||
/* replace quoted characters (and decimal codes) */
|
||||
/* assuming line-continuation already happened */
|
||||
from = to = string;
|
||||
while (*from) {
|
||||
if (*from == '\\') {
|
||||
++from;
|
||||
if (IS_NUM(*from)) {
|
||||
num = *from++ - '0';
|
||||
if (IS_NUM(*from))
|
||||
num = num*10 + (*from++ - '0');
|
||||
if (IS_NUM(*from))
|
||||
num = num*10 + (*from++ - '0');
|
||||
*to++ = num;
|
||||
} else {
|
||||
switch (*from) {
|
||||
case '\0': continue;
|
||||
case 'n': *to++ = '\n'; break;
|
||||
case 'r': *to++ = '\r'; break;
|
||||
case 't': *to++ = '\t'; break;
|
||||
default: *to++ = *from; break;
|
||||
}
|
||||
++from;
|
||||
}
|
||||
} else {
|
||||
*to++ = *from++;
|
||||
}
|
||||
}
|
||||
*to = '\0';
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/*
|
||||
* load_commands()
|
||||
* Parse the commlist file again, this time getting the commands, filenames
|
||||
* and weights and reading the message files into memory.
|
||||
*/
|
||||
int
|
||||
load_commands(char *commands)
|
||||
{
|
||||
char *cmdptr = commands;
|
||||
|
||||
int total_weight = 0;
|
||||
char line[LINE_BUFSIZE];
|
||||
int lineNumber = 0;
|
||||
int commIndex = 0;
|
||||
int inCommand = 0; /* 0 none, -1 ignore, 1 default, 2 other */
|
||||
string_list_t *param_list = NULL;
|
||||
|
||||
g_default_params = paramListInit (); /* create default section list */
|
||||
|
||||
/* set built in defaults. always use lower case names */
|
||||
paramListAdd (g_default_params, "numloops", "1");
|
||||
paramListAdd (g_default_params, "numrecipients", "1");
|
||||
paramListAdd (g_default_params, "numlogins", "1");
|
||||
paramListAdd (g_default_params, "numaddresses", "1");
|
||||
paramListAdd (g_default_params, "weight", "100");
|
||||
|
||||
gn_number_of_commands = count_num_commands(commands);
|
||||
D_PRINTF(stderr, "number_of_commands = %d\n", gn_number_of_commands);
|
||||
if (gn_number_of_commands <= 0) { /* no mail msgs - exit */
|
||||
return returnerr (stderr, "No commands found\n");
|
||||
}
|
||||
|
||||
/* allocate structure to hold command list (command filename weight) */
|
||||
g_loaded_comm_list =
|
||||
(mail_command_t *) mycalloc(gn_number_of_commands
|
||||
* sizeof(mail_command_t));
|
||||
|
||||
while (NULL
|
||||
!= (cmdptr = get_line_from_buffer (cmdptr, line, &lineNumber, 0))) {
|
||||
|
||||
/* The pre-process step does lots of checking, keep this simple */
|
||||
/* check for close tag */
|
||||
if ((line[0] == '<') && (line[1] == '/')) {
|
||||
/* default or ignored command */
|
||||
if (inCommand < 2) {
|
||||
assert (param_list == NULL);
|
||||
inCommand = 0;
|
||||
continue;
|
||||
}
|
||||
stringListAdd (param_list, line); /* store last line */
|
||||
|
||||
if (g_loaded_comm_list[commIndex].proto->parseEnd) {
|
||||
int ret;
|
||||
ret = (g_loaded_comm_list[commIndex].proto->parseEnd)
|
||||
(g_loaded_comm_list+commIndex,
|
||||
param_list, g_default_params);
|
||||
|
||||
if (ret < 0) {
|
||||
D_PRINTF (stderr, "Error finalizing section for '%s'\n",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
g_loaded_comm_list[commIndex].proto->cmdCount++;
|
||||
D_PRINTF (stderr, "Section done: '%s' weight=%d\n\n",
|
||||
line, g_loaded_comm_list[commIndex].weight);
|
||||
/* update total weight */
|
||||
total_weight += g_loaded_comm_list[commIndex].weight;
|
||||
|
||||
commIndex++;
|
||||
inCommand = 0;
|
||||
if (param_list) {
|
||||
stringListFree (param_list);
|
||||
param_list = NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* open tag */
|
||||
if (line[0] == '<') {
|
||||
protocol_t *pp;
|
||||
|
||||
if (check_hostname_attribute (line) < 0) { /* not for us */
|
||||
D_PRINTF (stderr, "Section not for us %s\n", line);
|
||||
inCommand = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if default special case */
|
||||
if (0 == strnicmp (line+1, "default", 7)) { /* default */
|
||||
D_PRINTF (stderr, "DEFAULT section\n");
|
||||
inCommand = 1;
|
||||
continue;
|
||||
}
|
||||
/* Check if we should ignore it */
|
||||
if (0 == strnicmp (line+1, "graph", 5)) { /* ignore graph */
|
||||
D_PRINTF (stderr, "GRAPH section (ignored)\n");
|
||||
inCommand = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
pp = protocol_get (line+1);
|
||||
if (NULL == pp) { /* protocol not found */
|
||||
d_printf (stderr,
|
||||
"Warning: Skipping section with no protocol handler '%s'\n",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pp->parseStart) {
|
||||
int ret;
|
||||
ret = (pp->parseStart) (g_loaded_comm_list+commIndex,
|
||||
line, g_default_params);
|
||||
if (ret < 0) {
|
||||
D_PRINTF (stderr, "Error Initializing section for '%s'\n",
|
||||
line);
|
||||
continue;
|
||||
} else if (ret == 0) {
|
||||
D_PRINTF (stderr, "Ignoring section for '%s'\n",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* start a command */
|
||||
D_PRINTF (stderr, "New Section: %s\n", line);
|
||||
g_loaded_comm_list[commIndex].proto = pp;
|
||||
inCommand = 2;
|
||||
param_list = stringListInit (line); /* store first line */
|
||||
/* ignoring rest of line */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're not inside a command tag or not for us, ignore the line */
|
||||
if (inCommand <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* attr value */
|
||||
if (1 == inCommand) { /* default, always name value pairs */
|
||||
char *value;
|
||||
value = line + strcspn (line, " \t=");
|
||||
if (value != line) {
|
||||
*value++ = 0; /* terminate name */
|
||||
value += strspn(value, " \t=");
|
||||
|
||||
string_tolower(line);
|
||||
value = string_unquote(value);
|
||||
|
||||
/*D_PRINTF (stderr, "DEFAULT: name='%s' value='%s'\n",
|
||||
line, value);*/
|
||||
paramListAdd (g_default_params, line, value);
|
||||
} else {
|
||||
D_PRINTF (stderr, "DEFAULT: Cound not find 'NAME VALUE...', line %d\n",
|
||||
lineNumber);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* store body for protocol parsing */
|
||||
stringListAdd (param_list, line);
|
||||
}
|
||||
return (total_weight);
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
# Marcel DePaolis <marcel@netcape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
/* these are protocol dependent timers for Pop, Imap, Smtp, Http*/
|
||||
typedef struct pish_stats {
|
||||
event_timer_t connect;
|
||||
event_timer_t banner;
|
||||
event_timer_t login;
|
||||
event_timer_t cmd;
|
||||
event_timer_t msgread;
|
||||
event_timer_t msgwrite;
|
||||
event_timer_t logout;
|
||||
|
||||
/* protocol dependent local storage */
|
||||
/* should have local ranges too */
|
||||
range_t loginRange; /* login range for this thread */
|
||||
unsigned long lastLogin;
|
||||
range_t domainRange; /* domain range for this thread */
|
||||
unsigned long lastDomain;
|
||||
range_t addressRange; /* address range for this thread */
|
||||
unsigned long lastAddress;
|
||||
} pish_stats_t;
|
||||
|
||||
/* These are common to POP, IMAP, SMTP, HTTP */
|
||||
typedef struct pish_command {
|
||||
resolved_addr_t hostInfo; /* should be a read only cache */
|
||||
|
||||
/* These are common to SMTP, POP, IMAP */
|
||||
char * loginFormat;
|
||||
range_t loginRange; /* login range for all threads */
|
||||
|
||||
range_t domainRange; /* domain range for all threads */
|
||||
|
||||
char * passwdFormat;
|
||||
|
||||
/* SMTP command attrs */
|
||||
char * addressFormat;
|
||||
range_t addressRange; /* address range for all threads */
|
||||
|
||||
char * smtpMailFrom;
|
||||
char * filename;
|
||||
int numRecipients; /* recpients per message */
|
||||
int msgsize; /* message size without trailing CRLF.CRLF */
|
||||
char * msgMailFrom; /* message mail from (envelope sender) */
|
||||
char * msgdata; /* cache the file in mem */
|
||||
int useEHLO; /* use EHLO instead of HELO */
|
||||
int useAUTHLOGIN; /* use AUTH LOGIN to authenticate */
|
||||
int useAUTHPLAIN; /* use AUTH PLAIN to authenticate */
|
||||
|
||||
/* POP/IMAP flag to leave mail on server */
|
||||
int leaveMailOnServer; /* IMAP > 2: leave unseen */
|
||||
|
||||
/* IMAP command attrs */
|
||||
char * imapSearchFolder;
|
||||
char * imapSearchPattern;
|
||||
int imapSearchRate;
|
||||
} pish_command_t;
|
||||
|
||||
/* TRANSITION functions */
|
||||
extern int pishParseNameValue (pmail_command_t cmd, char *name, char *tok);
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
@ -44,6 +44,9 @@ typedef struct _doPOP3_state {
|
|||
int msgCounter; /* count in download */
|
||||
} doPOP3_state_t;
|
||||
|
||||
/* POP3 flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
|
||||
static void doPop3Exit (ptcx_t ptcx, doPOP3_state_t *me);
|
||||
|
||||
|
||||
|
@ -58,7 +61,11 @@ PopParseNameValue (pmail_command_t cmd,
|
|||
if (pishParseNameValue(cmd, name, tok) == 0)
|
||||
; /* done */
|
||||
else if (strcmp(name, "leavemailonserver") == 0)
|
||||
pish->leaveMailOnServer = atoi(tok);
|
||||
if (atoi(tok) > 0) {
|
||||
pish->flags |= leaveMailOnServer;
|
||||
} else {
|
||||
pish->flags &= ~leaveMailOnServer;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -365,7 +372,7 @@ doPop3Loop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
|||
}
|
||||
|
||||
/* if we're not told to leave mail on server, delete the message */
|
||||
if (!pish->leaveMailOnServer) {
|
||||
if (!(pish->flags & leaveMailOnServer)) {
|
||||
/* send the DELE command */
|
||||
sprintf(command, "DELE %d%s", me->msgCounter, CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
@ -37,15 +37,320 @@
|
|||
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include <glob.h> /* for glob, globfree */
|
||||
|
||||
#define MAXCOMMANDLEN 256
|
||||
#define MAXCOMMANDLEN 256 /* parse buffer length */
|
||||
|
||||
/* SMTP protocol line to send after a message */
|
||||
#define MSG_TRAILER CRLF "." CRLF
|
||||
|
||||
/* run time state */
|
||||
typedef struct _doSMTP_state {
|
||||
int nothing;
|
||||
} doSMTP_state_t;
|
||||
|
||||
/* info on files/messages to send */
|
||||
typedef struct {
|
||||
char * filename; /* file name */
|
||||
int offset; /* where to start sending from */
|
||||
char * msgMailFrom; /* message mail from (envelope sender) */
|
||||
} smtp_file_t;
|
||||
|
||||
/* flags definitions */
|
||||
#define useEHLO 0x01 /* use EHLO instead of HELO */
|
||||
#define useAUTHLOGIN 0x02 /* use AUTH LOGIN to authenticate */
|
||||
#define useAUTHPLAIN 0x04 /* use AUTH PLAIN to authenticate */
|
||||
|
||||
static void doSMTPExit (ptcx_t ptcx, doSMTP_state_t *me);
|
||||
|
||||
/* ================ Support routines ================ */
|
||||
/*
|
||||
Handle the initial look at the specified file
|
||||
*/
|
||||
static int
|
||||
SmtpFileInit (pmail_command_t cmd, /* command being checked */
|
||||
param_list_t *defparm, /* default parameters */
|
||||
smtp_file_t *fileEntry) /* file entry to fill in */
|
||||
{
|
||||
/*pish_command_t *pish = (pish_command_t *)cmd->data;*/
|
||||
int fd;
|
||||
int bytesRead;
|
||||
struct stat statbuf;
|
||||
char *msgdata; /* temp buffer */
|
||||
int msgsize; /* message size without trailing CRLF.CRLF */
|
||||
|
||||
|
||||
/* Handle multiple files. This means that the file contents
|
||||
(starting from an offset) are read when the block is executed.
|
||||
The start of the file is scanned here for special commands. */
|
||||
|
||||
D_PRINTF (stderr, "SmtpFileInit: %s\n", fileEntry->filename);
|
||||
|
||||
/* read the contents of file into struct */
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
if (stat(fileEntry->filename, &statbuf) != 0) {
|
||||
return returnerr(stderr,"Couldn't stat file %s: errno=%d: %s\n",
|
||||
fileEntry->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* open file */
|
||||
if ((fd = open(fileEntry->filename, O_RDONLY)) <= 0) {
|
||||
return returnerr(stderr, "Cannot open file %s: errno=%d: %s\n",
|
||||
fileEntry->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* We don't really need much of the file, but it warms up the
|
||||
* cache. Limit at 1Mb */
|
||||
msgsize = MIN (statbuf.st_size, 1024*1024);
|
||||
msgdata = (char *) mycalloc(msgsize+strlen(MSG_TRAILER)+1);
|
||||
|
||||
if ((bytesRead = read(fd, msgdata, msgsize)) <= 0) {
|
||||
close(fd);
|
||||
return returnerr(stderr, "Cannot read file %s: errno=%d: %s\n",
|
||||
fileEntry->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
if (bytesRead != msgsize) {
|
||||
returnerr(stderr, "Error reading file %s, got %d expected %d\n",
|
||||
fileEntry->filename, bytesRead, msgsize);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msgdata[msgsize] = 0;
|
||||
|
||||
/* If the file starts with SMTP, then it has extra info in it */
|
||||
/* clean up message to rfc822 style */
|
||||
|
||||
#define PROTO_HEADER "SMTP"
|
||||
#define PROTO_MAIL_FROM "\nMAIL FROM:"
|
||||
#define PROTO_DATA "\nDATA\n"
|
||||
|
||||
if (strncmp(msgdata, PROTO_HEADER, strlen(PROTO_HEADER)) == 0) {
|
||||
char *cp, *cp2;
|
||||
int off;
|
||||
|
||||
D_PRINTF(stderr, "found PROTO_HEADER [%s]\n", PROTO_HEADER);
|
||||
cp = strstr(msgdata, PROTO_MAIL_FROM);
|
||||
if (cp != NULL) { /* copy out FROM field */
|
||||
cp += strlen(PROTO_MAIL_FROM);
|
||||
cp2 = strchr(cp, '\n');
|
||||
off = cp2 - cp;
|
||||
fileEntry->msgMailFrom = (char *) mycalloc(off+1);
|
||||
memcpy(fileEntry->msgMailFrom, cp, off);
|
||||
fileEntry->msgMailFrom[off] = 0;
|
||||
D_PRINTF(stderr, "got PROTO_MAIL_FROM:%s\n",
|
||||
fileEntry->msgMailFrom);
|
||||
}
|
||||
|
||||
cp = strstr(msgdata, PROTO_DATA);
|
||||
if (cp != NULL) { /* DATA marks the real message, copy up */
|
||||
off = cp - msgdata;
|
||||
off += strlen(PROTO_DATA);
|
||||
fileEntry->offset = off;
|
||||
D_PRINTF(stderr, "found PROTO_DATA at off=%d\n", off);
|
||||
} else {
|
||||
D_PRINTF(stderr,
|
||||
"WARNING: PROTO_HEADER [%s] given, but PROTO_DATA [%s] never found\n",
|
||||
PROTO_HEADER, PROTO_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
myfree (msgdata);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Handle file expansion for the given file pattern
|
||||
*/
|
||||
static int
|
||||
SmtpFilePrep (pmail_command_t cmd, /* command being checked */
|
||||
param_list_t *defparm) /* default parameters */
|
||||
{
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
int ii;
|
||||
glob_t globs;
|
||||
smtp_file_t *fileEntry;
|
||||
|
||||
/* We randomly pick files, so dont bother to sort them */
|
||||
if (glob (pish->filePattern, GLOB_NOSORT | GLOB_MARK, NULL, &globs) < 0) {
|
||||
globfree (&globs);
|
||||
return returnerr(stderr,"Error globbing '%s': errno=%d: %s\n",
|
||||
pish->filePattern, errno, strerror(errno));
|
||||
}
|
||||
|
||||
pish->fileCount = globs.gl_pathc;
|
||||
D_PRINTF (stderr, "SmtpFilePrep: filePattern='%s' entries=%d\n",
|
||||
pish->filePattern, pish->fileCount);
|
||||
pish->files = mycalloc (pish->fileCount * sizeof (smtp_file_t));
|
||||
fileEntry = pish->files;
|
||||
for (ii = 0; ii < pish->fileCount; ++ii, ++fileEntry) {
|
||||
fileEntry->filename = mystrdup (globs.gl_pathv[ii]);
|
||||
if (SmtpFileInit (cmd, defparm, fileEntry) < 0) {
|
||||
globfree (&globs);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
globfree (&globs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Send a file with leading and trailing text.
|
||||
Currently only used by SMTP.
|
||||
The leading and trailing text may be NULL.
|
||||
For SMTP, put the <CRLF>.<CRLF> in the trailing text.
|
||||
*/
|
||||
static int
|
||||
sendFile (
|
||||
ptcx_t ptcx, /* timer context */
|
||||
SOCKET sock, /* socket to send on */
|
||||
char *leading, /* initial text/headers or NULL */
|
||||
char *fileName, /* filename */
|
||||
int offset, /* offset into file */
|
||||
char *trailing) /* trailing text or NULL */
|
||||
{
|
||||
int leadLen = 0, trailLen = 0;
|
||||
int sentbytes = 0;
|
||||
int sent, todo, done, fd;
|
||||
char buff[16*1024];
|
||||
|
||||
fd = open (fileName, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
snprintf (buff, sizeof (buff),
|
||||
"<sendfile: Error opening '%s' (%s)",
|
||||
fileName, strerror (errno));
|
||||
strcat (ptcx->errMsg, buff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (NULL != leading) leadLen = strlen(leading);
|
||||
if (NULL != trailing) trailLen = strlen(trailing);
|
||||
|
||||
D_PRINTF(debugfile, "Writing file '%s' to server: leadLen=%d trailLen=%d offset=%d\n",
|
||||
fileName, leadLen, trailLen, offset);
|
||||
|
||||
/* Send leading text */
|
||||
todo = leadLen;
|
||||
done = 0;
|
||||
while (todo > 0) {
|
||||
if ((sent = retryWrite(ptcx, sock, leading + done,
|
||||
todo - done)) == -1) {
|
||||
strcat (ptcx->errMsg, "<sendFile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
done += sent;
|
||||
todo -= sent;
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"sendFile() Time expired.\n");
|
||||
sentbytes += done;
|
||||
goto exitFast;
|
||||
}
|
||||
}
|
||||
sentbytes += done;
|
||||
|
||||
/* Send the file */
|
||||
if (offset > 0) { /* skip an initial offset */
|
||||
if (lseek (fd, offset, SEEK_SET) < 0) {
|
||||
strcat (ptcx->errMsg, "<sendFile() seek failed.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while ((todo = read (fd, buff, sizeof (buff))) > 0) {
|
||||
done = 0;
|
||||
while (todo > 0) {
|
||||
if ((sent = retryWrite(ptcx, sock, buff + done,
|
||||
todo - done)) == -1) {
|
||||
strcat (ptcx->errMsg, "<sendFile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
done += sent;
|
||||
todo -= sent;
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"sendFile() Time expired.\n");
|
||||
sentbytes += done;
|
||||
goto exitFast;
|
||||
}
|
||||
}
|
||||
sentbytes += done;
|
||||
}
|
||||
if (todo < 0) {
|
||||
D_PRINTF(debugfile,"sendFile() File read.\n");
|
||||
}
|
||||
close (fd);
|
||||
|
||||
/* Send trailing text */
|
||||
todo = trailLen;
|
||||
done = 0;
|
||||
while (todo > 0) {
|
||||
if ((sent = retryWrite(ptcx, sock, trailing + done,
|
||||
todo - done)) == -1) {
|
||||
strcat (ptcx->errMsg, "<sendFile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
done += sent;
|
||||
todo -= sent;
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"sendFile() Time expired.\n");
|
||||
sentbytes += done;
|
||||
goto exitFast;
|
||||
}
|
||||
}
|
||||
sentbytes += done;
|
||||
|
||||
exitFast:
|
||||
ptcx->byteswritten += sentbytes;
|
||||
return sentbytes;
|
||||
}
|
||||
|
||||
#if 0 /* not currently used */
|
||||
/*
|
||||
Send a message from memory. Currently only used by SMTP.
|
||||
Assumes we already included the <CRLF>.<CRLF> at the end of message
|
||||
*/
|
||||
static int
|
||||
sendMessage(ptcx_t ptcx, SOCKET sock, char *message)
|
||||
{
|
||||
int writelen;
|
||||
int sentbytes = 0;
|
||||
int sent;
|
||||
|
||||
writelen = strlen(message);
|
||||
|
||||
D_PRINTF(debugfile, "Writing message to server: len=%d\n", writelen );
|
||||
|
||||
while (sentbytes < writelen) {
|
||||
if ((sent = retryWrite(ptcx, sock, message + sentbytes,
|
||||
writelen - sentbytes)) == -1) {
|
||||
strcat (ptcx->errMsg, "<sendMessage");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sentbytes += sent;
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"sendMessage() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptcx->byteswritten += sentbytes;
|
||||
|
||||
return sentbytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================ SMTP protocol entry points ================ */
|
||||
/*
|
||||
Set defaults in command structure
|
||||
*/
|
||||
|
@ -80,9 +385,6 @@ SmtpParseEnd (pmail_command_t cmd,
|
|||
param_list_t *defparm)
|
||||
{
|
||||
string_list_t *sp;
|
||||
int fd;
|
||||
int bytesRead;
|
||||
struct stat statbuf;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
|
||||
/* Now parse section lines */
|
||||
|
@ -126,88 +428,12 @@ SmtpParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* check for required attrs */
|
||||
if (!pish->filename) {
|
||||
if (!pish->filePattern) {
|
||||
D_PRINTF(stderr,"missing file for SMTP command");
|
||||
return returnerr(stderr,"missing file for SMTP command\n");
|
||||
}
|
||||
|
||||
/* read the contents of file into struct */
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
if (stat(pish->filename, &statbuf) != 0) {
|
||||
return returnerr(stderr,"Couldn't stat file %s: errno=%d: %s\n",
|
||||
pish->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* open file */
|
||||
if ((fd = open(pish->filename, O_RDONLY)) <= 0) {
|
||||
return returnerr(stderr, "Cannot open file %s: errno=%d: %s\n",
|
||||
pish->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* read into loaded_comm_list */
|
||||
#define MSG_TRAILER CRLF "." CRLF
|
||||
|
||||
pish->msgsize = statbuf.st_size;
|
||||
pish->msgMailFrom = NULL;
|
||||
pish->msgdata = (char *) mycalloc(pish->msgsize+strlen(MSG_TRAILER)+1);
|
||||
|
||||
if ((bytesRead = read(fd, pish->msgdata, pish->msgsize)) <= 0) {
|
||||
close(fd);
|
||||
return returnerr(stderr, "Cannot read file %s: errno=%d: %s\n",
|
||||
pish->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
if (bytesRead != pish->msgsize) {
|
||||
returnerr(stderr, "Error reading file %s, got %d expected %d\n",
|
||||
pish->filename, bytesRead, pish->msgsize);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pish->msgdata[pish->msgsize] = 0;
|
||||
|
||||
/* clean up message to rfc822 style */
|
||||
|
||||
#define PROTO_HEADER "SMTP"
|
||||
#define PROTO_MAIL_FROM "\nMAIL FROM:"
|
||||
#define PROTO_DATA "\nDATA\n"
|
||||
|
||||
D_PRINTF (stderr, "checking for PROTO_HEADER [%s]\n", PROTO_HEADER);
|
||||
if (strncmp(pish->msgdata, PROTO_HEADER, strlen(PROTO_HEADER)) == 0) {
|
||||
char *cp, *cp2;
|
||||
int off;
|
||||
|
||||
D_PRINTF(stderr, "got PROTO_HEADER\n");
|
||||
D_PRINTF(stderr, "find PROTO_MAIL_FROM...\n");
|
||||
cp = strstr(pish->msgdata, PROTO_MAIL_FROM);
|
||||
if (cp != NULL) {
|
||||
cp += strlen(PROTO_MAIL_FROM);
|
||||
cp2 = strchr(cp, '\n');
|
||||
off = cp2 - cp;
|
||||
pish->msgMailFrom = (char *) mycalloc(off+1);
|
||||
memcpy(pish->msgMailFrom, cp, off);
|
||||
pish->msgMailFrom[off] = 0;
|
||||
D_PRINTF(stderr, "got PROTO_MAIL_FROM:%s\n",pish->msgMailFrom);
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "find PROTO_DATA...\n");
|
||||
cp = strstr(pish->msgdata, PROTO_DATA);
|
||||
if (cp != NULL) {
|
||||
off = cp - pish->msgdata;
|
||||
off += strlen(PROTO_DATA);
|
||||
D_PRINTF(stderr, "got past PROTO_DATA at off=%d\n", off);
|
||||
char *newmsg = (char *) mycalloc(pish->msgsize+strlen(MSG_TRAILER)+1-off);
|
||||
memcpy(newmsg, pish->msgdata+off, pish->msgsize-off+1);
|
||||
myfree(pish->msgdata);
|
||||
pish->msgdata = newmsg;
|
||||
D_PRINTF(stderr, "done msg shrink\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strcat(pish->msgdata, MSG_TRAILER);
|
||||
|
||||
close(fd);
|
||||
SmtpFilePrep (cmd, defparm);
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(pish->hostInfo.hostName, "tcp",
|
||||
|
@ -283,7 +509,7 @@ pishParseNameValue (pmail_command_t cmd,
|
|||
else if (strcmp(name, "numrecipients") == 0)
|
||||
pish->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "file") == 0)
|
||||
pish->filename= mystrdup (tok);
|
||||
pish->filePattern = mystrdup (tok);
|
||||
else if (strcmp(name, "passwdformat") == 0)
|
||||
pish->passwdFormat = mystrdup (tok);
|
||||
else if (strcmp(name, "searchfolder") == 0)
|
||||
|
@ -293,11 +519,23 @@ pishParseNameValue (pmail_command_t cmd,
|
|||
else if (strcmp(name, "searchrate") == 0)
|
||||
pish->imapSearchRate = atoi(tok);
|
||||
else if (strcmp(name, "useehlo") == 0)
|
||||
pish->useEHLO = atoi(tok);
|
||||
if (atoi(tok)) {
|
||||
pish->flags |= useEHLO;
|
||||
} else {
|
||||
pish->flags &= ~useEHLO;
|
||||
}
|
||||
else if (strcmp(name, "useauthlogin") == 0)
|
||||
pish->useAUTHLOGIN = atoi(tok);
|
||||
if (atoi(tok) > 0) {
|
||||
pish->flags |= useAUTHLOGIN;
|
||||
} else {
|
||||
pish->flags &= ~useAUTHLOGIN;
|
||||
}
|
||||
else if (strcmp(name, "useauthplain") == 0)
|
||||
pish->useAUTHPLAIN = atoi(tok);
|
||||
if (atoi(tok) > 0) {
|
||||
pish->flags |= useAUTHPLAIN;
|
||||
} else {
|
||||
pish->flags &= ~useAUTHPLAIN;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -774,7 +1012,7 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
D_PRINTF(debugfile,"read connect response\n");
|
||||
|
||||
|
||||
if (pish->useEHLO != 0) {
|
||||
if (pish->flags & useEHLO) {
|
||||
/* send extended EHLO */
|
||||
sprintf(command, "EHLO %s" CRLF, gs_thishostname);
|
||||
} else {
|
||||
|
@ -795,7 +1033,7 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (pish->useAUTHPLAIN) {
|
||||
if (pish->flags & useAUTHPLAIN) {
|
||||
/* look for AUTH PLAIN LOGIN in respBuffer */
|
||||
if (strstr(respBuffer, "AUTH PLAIN LOGIN") != NULL) {
|
||||
/* FIX: time get base64 time and multiple round trips */
|
||||
|
@ -805,7 +1043,7 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
} else if (pish->useAUTHLOGIN) {
|
||||
} else if (pish->flags & useAUTHLOGIN) {
|
||||
/* look for AUTH LOGIN in respBuffer */
|
||||
if (strstr(respBuffer, "AUTH=LOGIN") != NULL) {
|
||||
/* FIX: time get base64 time and multiple round trips */
|
||||
|
@ -836,13 +1074,23 @@ sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystat
|
|||
int numBytes;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
smtp_file_t *fileEntry;
|
||||
|
||||
/* send MAIL FROM:<username> */
|
||||
if (pish->msgMailFrom != NULL) {
|
||||
sprintf(command, "MAIL FROM:%s%s", pish->msgMailFrom, CRLF);
|
||||
if (pish->fileCount > 1) { /* randomly pick file */
|
||||
int ff;
|
||||
ff = (RANDOM() % pish->fileCount);
|
||||
/*D_PRINTF(debugfile,"random file<%d=%d\n", pish->fileCount, ff);*/
|
||||
fileEntry = ((smtp_file_t *)pish->files) + ff;
|
||||
} else {
|
||||
fileEntry = (smtp_file_t *)pish->files;
|
||||
}
|
||||
if (fileEntry->msgMailFrom != NULL) {
|
||||
sprintf(command, "MAIL FROM:%s%s", fileEntry->msgMailFrom, CRLF);
|
||||
} else {
|
||||
sprintf(command, "MAIL FROM:<%s>%s", pish->smtpMailFrom, CRLF);
|
||||
}
|
||||
/*D_PRINTF(debugfile,"%s\n", command);*/
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
|
@ -901,9 +1149,12 @@ sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystat
|
|||
|
||||
D_PRINTF(debugfile, "data response %s\n", respBuffer);
|
||||
|
||||
/* send data as message (we already added the CRLF.CRLF) */
|
||||
/* send message */
|
||||
event_start(ptcx, &stats->msgwrite);
|
||||
numBytes = sendMessage(ptcx, ptcx->sock, pish->msgdata);
|
||||
numBytes = sendFile(ptcx, ptcx->sock,
|
||||
NULL,
|
||||
fileEntry->filename, fileEntry->offset,
|
||||
MSG_TRAILER);
|
||||
if (numBytes == -1) {
|
||||
event_stop(ptcx, &stats->msgwrite);
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
|
@ -1,202 +0,0 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* David Shak
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
#ifndef __SYSDEP_H__
|
||||
#define __SYSDEP_H__
|
||||
|
||||
/* include config.h, output from autoconf */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
/* borrow config.h from gnuplot. Should build our own */
|
||||
#include "gnuplot/config.h"
|
||||
#endif
|
||||
#else
|
||||
/* Modern OSes have these */
|
||||
#define HAVE_SNPRINTF 1
|
||||
#define HAVE_STRERROR 1
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef __OSF1__
|
||||
#include <sys/sysinfo.h> /* for setsysinfo() */
|
||||
#endif
|
||||
|
||||
/* MAXHOSTNAMELEN is undefined on some systems */
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
/* SunOS doesn't define NULL */
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/* encapsulation of minor UNIX/WIN NT differences */
|
||||
#ifdef _WIN32
|
||||
#define NETREAD(sock, buf, len) recv(sock, buf, len, 0)
|
||||
#define NETWRITE(sock, buf, len) send(sock, buf, len, 0)
|
||||
#define NETCLOSE(sock) closesocket(sock)
|
||||
#define OUTPUT_WRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define BADSOCKET(sock) ((sock) == INVALID_SOCKET)
|
||||
#define BADSOCKET_ERRNO(sock) BADSOCKET(sock)
|
||||
#define BADSOCKET_VALUE INVALID_SOCKET
|
||||
#define S_ADDR S_un.S_addr
|
||||
#define GET_ERROR WSAGetLastError()
|
||||
#define SET_ERROR(err) WSASetLastError(err)
|
||||
|
||||
/* NT gettimeofday() doesn't support USE_TIMEZONE (yet) */
|
||||
#include <time.h>
|
||||
#define GETTIMEOFDAY(timeval, tz) gettimeofday(timeval)
|
||||
|
||||
typedef unsigned short NETPORT;
|
||||
#define SRANDOM srand
|
||||
#define RANDOM rand
|
||||
#define PROGPATH "c:\\mailstone\\mailclient"
|
||||
#define FILENAME_SIZE 256
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
#define SIGCHLD 0 /* dummy value */
|
||||
#define SIGALRM 0 /* dummy value */
|
||||
typedef int pid_t;
|
||||
typedef unsigned short ushort;
|
||||
#define MAXPATHLEN 512
|
||||
|
||||
extern void sock_cleanup(void);
|
||||
|
||||
#define THREAD_RET void
|
||||
#define THREAD_ID int
|
||||
|
||||
#else /* not _WIN32 */
|
||||
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
|
||||
#define NETREAD(sock, buf, len) read(sock, buf, len)
|
||||
#define NETWRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define NETCLOSE(sock) close(sock)
|
||||
#define OUTPUT_WRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define BADSOCKET(sock) ((sock) < 0)
|
||||
#define BADSOCKET_ERRNO(sock) (BADSOCKET(sock) || errno)
|
||||
#define BADSOCKET_VALUE (-1)
|
||||
#define S_ADDR s_addr
|
||||
#define GET_ERROR errno
|
||||
#define SET_ERROR(err) (errno = (err))
|
||||
|
||||
#define GETTIMEOFDAY(timeval,tz) gettimeofday(timeval, NULL)
|
||||
|
||||
typedef unsigned short NETPORT;
|
||||
|
||||
#if defined (USE_LRAND48_R)
|
||||
extern void osf_srand48_r(unsigned int seed);
|
||||
extern long osf_lrand48_r(void);
|
||||
#define SRANDOM osf_srand48_r
|
||||
#define RANDOM osf_lrand48_r
|
||||
|
||||
#elif defined (USE_LRAND48)
|
||||
|
||||
#define SRANDOM srand48
|
||||
#define RANDOM lrand48
|
||||
|
||||
#else /* !USE_LRAND48 */
|
||||
|
||||
#define SRANDOM srandom
|
||||
#define RANDOM random
|
||||
|
||||
#endif /* USE_LRAND48_R */
|
||||
|
||||
#define PROGPATH "/mailstone/mailclient"
|
||||
#define FILENAME_SIZE 1024
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
typedef int SOCKET;
|
||||
#define min(a,b) (((a) < (b)) ? a : b)
|
||||
#define max(a,b) (((a) > (b)) ? a : b)
|
||||
|
||||
#define THREAD_RET void *
|
||||
#ifdef USE_PTHREADS
|
||||
#define THREAD_ID pthread_t
|
||||
#else
|
||||
#define THREAD_ID int
|
||||
#endif
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
|
||||
typedef THREAD_RET (*thread_fn_t)(void *);
|
||||
|
||||
/* function prototypes */
|
||||
|
||||
extern void crank_limits(void);
|
||||
extern int sysdep_thread_create(THREAD_ID *id, thread_fn_t tfn, void *arg);
|
||||
extern int sysdep_thread_join(THREAD_ID id, int *pstatus);
|
||||
extern void setup_signal_handlers (void);
|
||||
|
||||
#ifdef _WIN32
|
||||
int getopt(int argc, char ** argv, char *opts);
|
||||
int getpid(void);
|
||||
int gettimeofday(struct timeval *curTimeP);
|
||||
int random_number(int max);
|
||||
SOCKET rexec(const char **hostname, NETPORT port, char *username, char *password,
|
||||
char *command, SOCKET *sockerr);
|
||||
|
||||
#else
|
||||
#ifdef NO_REXEC
|
||||
extern int rexec(char **, int, char *, char *, char *, int *);
|
||||
#endif
|
||||
#endif /* _WIN32 */
|
||||
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
/* strerror() is not available on SunOS 4.x and others */
|
||||
char *strerror(int errnum);
|
||||
|
||||
#endif
|
||||
/* strerror() */
|
||||
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE -1
|
||||
#endif
|
||||
|
||||
#endif /* !__SYSDEP_H__ */
|
|
@ -1,73 +0,0 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
/*
|
||||
Stuff that deals with timevals.
|
||||
*/
|
||||
#include "bench.h"
|
||||
|
||||
double
|
||||
timevaldouble(struct timeval *tin)
|
||||
{
|
||||
return ((double)tin->tv_sec + ((double)tin->tv_usec / USECINSEC));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
doubletimeval(const double tin, struct timeval *tout)
|
||||
{
|
||||
tout->tv_sec = (long)floor(tin);
|
||||
tout->tv_usec = (long)((tin - tout->tv_sec) * USECINSEC );
|
||||
}
|
||||
|
||||
/* Difference two timevals and return as a double (in seconds) */
|
||||
/* Could be a macro */
|
||||
double
|
||||
compdifftime_double(struct timeval *EndTime, struct timeval *StartTime)
|
||||
{
|
||||
/* doing the integeger differences first is supposed to prevent
|
||||
any loss in resolution (more important if we returned float instead) */
|
||||
double d = (EndTime->tv_sec - StartTime->tv_sec)
|
||||
+ ((double)(EndTime->tv_usec - StartTime->tv_usec)*(1.0/USECINSEC));
|
||||
|
||||
if (d < 0.0) {
|
||||
D_PRINTF (stderr, "Woa! compdifftime negative start %lu.%06lu end %lu.%06lu\n",
|
||||
StartTime->tv_sec, StartTime->tv_usec,
|
||||
EndTime->tv_sec, EndTime->tv_usec);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
|
||||
/* -*- Mode: C; c-file-style: "stroustrup"; comment-column: 40 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
|
Загрузка…
Ссылка в новой задаче