diff options
Diffstat (limited to 'maildrop/message.C')
| -rw-r--r-- | maildrop/message.C | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/maildrop/message.C b/maildrop/message.C new file mode 100644 index 0000000..a02f170 --- /dev/null +++ b/maildrop/message.C @@ -0,0 +1,271 @@ +#include "config.h" +#include "message.h" +#include "buffer.h" +#include "xconfig.h" +#include "funcs.h" +#include "varlist.h" + + +Message::Message() : buffer(0), bufptr(0), + extra_headers(0), extra_headersptr(0), msgsize(0) +{ +} + +Message::~Message() +{ + mio.fd(-1); // Either way, it's not our file + if (buffer) delete[] buffer; + if (extra_headers) delete[] extra_headers; +} + +void Message::Init() +{ + if (buffer) + { + delete[] buffer; + buffer=0; + } + if (extra_headers) + { + delete[] extra_headers; + extra_headers=0; + } + extra_headersptr=0; + msgsize=0; + msglines=0; + tempfile.Close(); + mio.fd(-1); +} + +void Message::Init(int fd) +{ + Init(); + // If the file descriptor is seekable, and the message is big + // keep message in the file. + if ( mseek(fd, 0, SEEK_END) >= 0 && + (msgsize=mseek(fd, 0, SEEK_CUR)) >= 0 && msgsize > SMALLMSG) + { + + // BUGFIX 0.55 - mio takes ownership of the file descriptor. When + // ::Init() is called, it will call fd(-1) which will CLOSE this + // descriptor we have now. + // + // This func is invoked from main with STDIN - 0, so we must take + // ownership of a duplicate. + + fd=dup(fd); + if (fd < 0) throw "dup() failed."; + + mio.fd(fd); + if (mio.Rewind() < 0) seekerr(); + + int c; + + while ((c=mio.get()) >= 0) + if (c == '\n') msglines++; + + return; + } + // Well, just read the message, and let Init() figure out what to + // do. + + mseek(fd, 0, SEEK_SET); // Just in case + msgsize=0; + +#ifdef BUFSIZ +char buf[BUFSIZ]; +#else +char buf[512]; +#endif +int n; + + while ((n=read(fd, buf, sizeof(buf))) > 0) + Init(buf, n); + if (n < 0) + throw "Error - read() failed reading message."; +#if CRLF_TERM + msgsize += msglines; +#endif +} + +void Message::Init(const void *data, unsigned cnt) +{ + { + const char *p=(const char*)data; + unsigned n=cnt; + + while (n) + { + if (*p++ == '\n') ++msglines; + --n; + } + } + + if (mio.fd() < 0) // Still trying to save to buffer + { + if (!buffer) + { + buffer=new char[SMALLMSG]; + bufptr=buffer; + msgsize=0; + if (!buffer) outofmem(); + } + + if (SMALLMSG - msgsize >= (off_t)cnt) // Can still do it + { + memcpy(bufptr, data, cnt); + bufptr += cnt; + msgsize += cnt; + return; + } + + int fd; + +#if SHARED_TEMPDIR + + fd=tempfile.Open(); + + if (fd < 0) + throw "Unable to create temporary file."; +#else + while ( (fd=tempfile.Open( TempName(), + O_RDWR | O_CREAT | O_EXCL, 0600)) < 0 && + errno == EEXIST) + ; + if (fd < 0) + throw "Unable to create temporary file - check permissions on $HOME/" TEMPDIR; +#endif + + mio.fd(fd); + + if ((off_t)mio.write(buffer, msgsize) != msgsize) + throw "Unable to write to temporary file - possibly out of disk space."; + + delete[] buffer; + buffer=0; + } + + if ((unsigned)mio.write(data, cnt) != cnt) + throw "Unable to write to temporary file - possibly out of disk space."; + msgsize += cnt; +} + +void Message::ExtraHeaders(const Buffer &buf) +{ + if ( extra_headers ) + { + delete[] extra_headers; + extra_headers=0; + } + extra_headersptr=0; + if (!buf.Length()) return; + + extra_headers=new char[buf.Length()+1]; + if (!extra_headers) outofmem(); + memcpy(extra_headers, (const char *)buf, buf.Length()); + extra_headers[buf.Length()]=0; + extra_headersptr=extra_headers; + if (!*extra_headersptr) extra_headersptr=0; +} + +void Message::RewindIgnore() +{ + extra_headersptr=0; + if (mio.fd() >= 0) + { + if (mio.Rewind() < 0) seekerr(); + return; + } + bufptr=buffer; +} + +void Message::Rewind() +{ + RewindIgnore(); + +off_t n=maildrop.msginfo.msgoffset; + + while (n) + { + (void)get_c(); + --n; + } + extra_headersptr=extra_headers; + if (extra_headersptr && !*extra_headersptr) + extra_headersptr=0; +} + +void Message::readerr() +{ + throw "Read error."; +} + +void Message::seekerr() +{ + throw "Seek error."; +} + +int Message::appendline(Buffer &buf, int stripcr) +{ + if (mio.fd() >= 0 || extra_headersptr) + { + int c; + int eof= 1; + int lastc=0; + + while ((c=get_c()) > 0 && c != '\n') + { + eof=0; + buf.push(c); + lastc=c; + } + if (c < 0 && eof) return (-1); + if (stripcr && lastc == '\r') buf.pop(); + // Drop trailing CRs + buf.push('\n'); + return (0); + } + + if (bufptr >= buffer + msgsize) + { + return (-1); + } + +unsigned cnt=buffer + msgsize - bufptr; +unsigned i; + + for (i=0; i<cnt; i++) + if (bufptr[i] == '\n') + { + if (i > 0 && stripcr && bufptr[i-1] == '\r') + buf.append(bufptr, i-1); + // Drop trailing CRs + else + buf.append(bufptr, i); + buf += '\n'; + bufptr += ++i; + return (0); + } + + if (stripcr && bufptr[i-1] == '\r') + buf.append(bufptr, cnt-1); + // Drop trailing CRs + else + buf.append(bufptr, cnt); + bufptr += cnt; + buf += '\n'; + return (0); +} + +void Message::setmsgsize() +{ +Buffer n,v; + + n="SIZE"; + v.append((unsigned long)MessageSize()); + SetVar(n,v); + n="LINES"; + v.reset(); + v.append((unsigned long)MessageLines()); + SetVar(n,v); +} |
