mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Many of these were real bugs, like: if (cond); do_something etc... Others were just cosmetic - like placing the ';' on a separate line to make the intention clear.
856 lines
21 KiB
C
856 lines
21 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
*+SNOTICE
|
|
*
|
|
* $TOG: DtMailServer.C /main/23 1999/01/29 14:46:18 mgreess $
|
|
*
|
|
* RESTRICTED CONFIDENTIAL INFORMATION:
|
|
*
|
|
* The information in this document is subject to special
|
|
* restrictions in a confidential disclosure agreement between
|
|
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
* document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
* Sun's specific written approval. This document and all copies
|
|
* and derivative works thereof must be returned or destroyed at
|
|
* Sun's request.
|
|
*
|
|
* Copyright 1993, 1995, 1995 Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
*+ENOTICE
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <pwd.h>
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include <DtMail/DtMailError.hh>
|
|
#include <DtMail/DtMailServer.hh>
|
|
#include <DtMail/IO.hh>
|
|
|
|
#if defined(USE_ITIMER_REAL)
|
|
#define SIGNAL_TYPE SIGALRM
|
|
#define ITIMER_TYPE ITIMER_REAL
|
|
#else
|
|
#define SIGNAL_TYPE SIGVTALRM
|
|
#define ITIMER_TYPE ITIMER_VIRTUAL
|
|
#endif
|
|
|
|
#define dtmasTAGCLR() *_transtag = '\0'; _transnum=0;
|
|
#define dtmasTAGGEN() (sprintf(_transtag, "a%04d", ++_transnum), _transtag)
|
|
#define dtmasTAGGET() (_transtag)
|
|
|
|
static jmp_buf restart;
|
|
|
|
DtMailServer::DtMailServer(
|
|
char *folder,
|
|
DtMail::Session *session,
|
|
DtMail::MailBox *mailbox,
|
|
DtMailAppendCallback append_mailbox_cb,
|
|
void *append_mailbox_cb_data)
|
|
{
|
|
struct passwd pw;
|
|
|
|
GetPasswordEntry(pw);
|
|
|
|
if (folder)
|
|
_folder = strdup(folder);
|
|
else
|
|
_folder = "INBOX";
|
|
_session = session;
|
|
_mailbox = mailbox;
|
|
|
|
_append_mailbox_cb = append_mailbox_cb;
|
|
_append_mailbox_cb_data
|
|
= append_mailbox_cb_data;
|
|
_protologging = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_PROTOLOGGING,
|
|
(Boolean) False);
|
|
_protologgingplus = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_PROTOLOGGINGPLUS,
|
|
(Boolean) False);
|
|
_errorstring = NULL;
|
|
_password = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_PASSWORD,
|
|
NULL, DTM_TRUE);
|
|
_removeafterdelivery
|
|
= get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_REMOVEAFTERDELIVERY,
|
|
True);
|
|
_retrieveold = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_RETRIEVEOLD,
|
|
True);
|
|
_retrieveerrors = 0;
|
|
_servername = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_SERVERNAME,
|
|
DTMAS_PROPDFLT_SERVERNAME);
|
|
_shroud = NULL;
|
|
_sizelimit = 0;
|
|
_sockfp = NULL;
|
|
dtmasTAGCLR();
|
|
_transnum = 0;
|
|
_timeout = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_TIMEOUT,
|
|
DTMAS_TIMEOUT);
|
|
_username = get_mailrc_value(
|
|
_session, _folder,
|
|
DTMAS_PROPKEY_USERNAME,
|
|
pw.pw_name);
|
|
}
|
|
|
|
DtMailServer::~DtMailServer()
|
|
{
|
|
if (_errorstring) free(_errorstring);
|
|
if (_folder) free(_folder);
|
|
if (_password) free(_password);
|
|
if (_servername) free(_servername);
|
|
if (_shroud) free(_shroud);
|
|
if (_username) free(_username);
|
|
}
|
|
|
|
void
|
|
DtMailServer::set_password(char *password)
|
|
{
|
|
if (NULL == password) return;
|
|
|
|
if (NULL != _password) free(_password);
|
|
_password = NULL;
|
|
if (NULL != password) _password = strdup(password);
|
|
}
|
|
|
|
//
|
|
// Read message content and append to mailbox
|
|
//
|
|
// len - Length of message.
|
|
//
|
|
#define SA_HANDLER_TYPE void (*)(int)
|
|
|
|
DTMailError_t
|
|
DtMailServer::ptrans_retrieve_readandappend(
|
|
DtMailEnv &error,
|
|
long len)
|
|
{
|
|
static char *pname = "DtMailServer::ptrans_retrieve_readandappend";
|
|
static char *from = "From ";
|
|
struct sigaction action, o_action;
|
|
int from_done = FALSE;
|
|
int done = FALSE;
|
|
size_t nread = 0;
|
|
char *s, *t;
|
|
|
|
memset((char*) &action, 0, sizeof(struct sigaction));
|
|
memset((char*) &o_action, 0, sizeof(struct sigaction));
|
|
action.sa_handler = (SA_HANDLER_TYPE) SIG_IGN;
|
|
sigaction(SIGINT, (const struct sigaction *) &action, &o_action);
|
|
|
|
while (! done)
|
|
{
|
|
size_t nbytes;
|
|
|
|
if (nread < len)
|
|
{
|
|
if (DTMAS_MSGBUFSIZE - 1 > len - nread)
|
|
nbytes = (size_t) len - nread;
|
|
else
|
|
nbytes = DTMAS_MSGBUFSIZE - 1;
|
|
|
|
if (0 == (nbytes=SockRead(_msgbuf, 1, nbytes, _sockfp)))
|
|
{
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
"Failed to retrieve %d bytes.",
|
|
len);
|
|
return DTME_MailServerAccess_SocketIOError;
|
|
}
|
|
_msgbuf[nbytes] = '\0';
|
|
}
|
|
else
|
|
{
|
|
if (NULL == SockGets(_msgbuf, DTMAS_MSGBUFSIZE, _sockfp))
|
|
{
|
|
_logger.logError(DTM_FALSE, "Failed to retrieve %d bytes", len);
|
|
return DTME_MailServerAccess_SocketIOError;
|
|
}
|
|
nbytes = strlen(_msgbuf);
|
|
}
|
|
|
|
nread += nbytes;
|
|
|
|
// Delete all carriage returns
|
|
for (s = t = _msgbuf; *s; s++)
|
|
if (*s != '\r') *t++ = *s;
|
|
*t = '\0';
|
|
|
|
if (_protologgingplus)
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
"INFO: read %d of %d octets %d remaining\n%s< %s\n",
|
|
nbytes, len, len-nread, proto_name(), _msgbuf);
|
|
|
|
// Determine if we are done with this message.
|
|
if (proto_is_delimited())
|
|
{
|
|
char *s = const_cast<char *> (strrchr((const char *) _msgbuf, (int) '.'));
|
|
|
|
if (s &&
|
|
(s == _msgbuf || *(s-1) == '\n') &&
|
|
(*s == '.') &&
|
|
(*(s+1) == '\n'))
|
|
{
|
|
*s = '\0';
|
|
done = TRUE;
|
|
}
|
|
}
|
|
else if (nread >= len)
|
|
done = TRUE;
|
|
|
|
if (0 < (nbytes = strlen(_msgbuf)))
|
|
{
|
|
if (! from_done && strncmp(_msgbuf, from, strlen(from)))
|
|
{
|
|
time_t clock;
|
|
char buffer[BUFSIZ];
|
|
|
|
clock = time(&clock);
|
|
sprintf(buffer, "%s %s %s",
|
|
from, _servername, ctime((const time_t *) &clock));
|
|
_append_mailbox_cb(
|
|
error, buffer, strlen(buffer),
|
|
_append_mailbox_cb_data);
|
|
}
|
|
|
|
from_done = TRUE;
|
|
_append_mailbox_cb(error, _msgbuf, nbytes, _append_mailbox_cb_data);
|
|
}
|
|
|
|
if (error.isSet())
|
|
{
|
|
error.logError(
|
|
DTM_TRUE,
|
|
"%s: Failed to append mailbox %s: %s.\n",
|
|
pname, _folder, error.errnoMessage());
|
|
return DTME_AppendMailboxFile_Error;
|
|
}
|
|
}
|
|
|
|
// Message separation.
|
|
_append_mailbox_cb(error, "\n", 1, _append_mailbox_cb_data);
|
|
|
|
// Sink the file pointer.
|
|
sigaction(SIGINT, (const struct sigaction *) &o_action, NULL);
|
|
return DTME_NoError;
|
|
}
|
|
|
|
//
|
|
// Assemble command in printf(3) style and send to the server.
|
|
//
|
|
|
|
DTMailError_t
|
|
DtMailServer::do_send(char *fmt, ... )
|
|
{
|
|
static char *pname = "DtMailServer::do_send";
|
|
char *buf = new char[DTMAS_POPBUFSIZE+1];
|
|
int nbytes;
|
|
va_list ap;
|
|
DtMailEnv error;
|
|
|
|
if (proto_is_tagged())
|
|
{
|
|
dtmasTAGGEN();
|
|
(void) sprintf(buf, "%s ", dtmasTAGGET());
|
|
}
|
|
else
|
|
{
|
|
dtmasTAGCLR();
|
|
buf[0] = '\0';
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
vsprintf(buf + strlen(buf), fmt, ap);
|
|
va_end(ap);
|
|
|
|
strcat(buf, "\r\n");
|
|
nbytes = SockWrite(buf, 1, strlen(buf), _sockfp);
|
|
if (nbytes != strlen(buf))
|
|
{
|
|
_logger.logError(DTM_FALSE, "Socket Error: writing '%s'", buf);
|
|
delete [] buf;
|
|
return DTME_MailServerAccess_SocketIOError;
|
|
}
|
|
|
|
if (_protologging)
|
|
{
|
|
char *cp;
|
|
if (_shroud && (cp = strstr(buf, _shroud)))
|
|
memset(cp, '*', strlen(_shroud));
|
|
buf[strlen(buf)-1] = '\0';
|
|
|
|
_logger.logError(DTM_FALSE, "%s> %s", proto_name(), buf);
|
|
}
|
|
delete [] buf;
|
|
return DTME_NoError;
|
|
}
|
|
|
|
//
|
|
// Assemble command in printf(3) style, send to server, accept a response.
|
|
//
|
|
#if defined(__hpux)
|
|
#define DTMAS_COMMAND_TERMINATOR "\n"
|
|
#else
|
|
#define DTMAS_COMMAND_TERMINATOR "\r\n"
|
|
#endif
|
|
DTMailError_t
|
|
DtMailServer::do_transaction(char *fmt, ... )
|
|
{
|
|
static char *pname = "DtMailServer::do_transaction";
|
|
DTMailError_t ok;
|
|
char *buf = new char[DTMAS_POPBUFSIZE+1];
|
|
int nbytes;
|
|
va_list ap;
|
|
|
|
if (proto_is_tagged())
|
|
{
|
|
dtmasTAGGEN();
|
|
(void) sprintf(buf, "%s ", dtmasTAGGET());
|
|
}
|
|
else
|
|
{
|
|
dtmasTAGCLR();
|
|
buf[0] = '\0';
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
vsprintf(buf + strlen(buf), fmt, ap);
|
|
va_end(ap);
|
|
|
|
strcat(buf, DTMAS_COMMAND_TERMINATOR);
|
|
nbytes = SockWrite(buf, 1, strlen(buf), _sockfp);
|
|
if (nbytes != strlen(buf))
|
|
{
|
|
_logger.logError(DTM_FALSE, "Socket Error: writing '%s'", buf);
|
|
delete [] buf;
|
|
return DTME_MailServerAccess_SocketIOError;
|
|
}
|
|
|
|
if (_protologging)
|
|
{
|
|
char *cp;
|
|
if (_shroud && (cp = strstr(buf, _shroud)))
|
|
memset(cp, '*', strlen(_shroud));
|
|
buf[strlen(buf)-1] = '\0';
|
|
|
|
_logger.logError(DTM_FALSE, "%s> %s", proto_name(), buf);
|
|
}
|
|
|
|
/* we presume this does its own response echoing */
|
|
ok = ptrans_parse_response(buf);
|
|
if (ok != DTME_NoError)
|
|
{
|
|
if (NULL == _errorstring)
|
|
_errorstring = strdup(buf);
|
|
}
|
|
delete [] buf;
|
|
return ok;
|
|
}
|
|
|
|
//
|
|
// Get the specified mailrc value interpreted as an integer
|
|
//
|
|
int
|
|
DtMailServer::get_mailrc_value(
|
|
DtMail::Session *ssn,
|
|
char *pfx,
|
|
char *id,
|
|
int dflt)
|
|
{
|
|
char *string = NULL;
|
|
int value = 0;
|
|
|
|
string = get_mailrc_value(ssn, pfx, id, (char*) NULL);
|
|
if (NULL == string)
|
|
return dflt;
|
|
|
|
value = atoi(string);
|
|
return value;
|
|
}
|
|
|
|
//
|
|
// Get the specified mailrc value interpreted as an string
|
|
//
|
|
char *
|
|
DtMailServer::get_mailrc_value(
|
|
DtMail::Session *ssn,
|
|
char *pfx,
|
|
char *id,
|
|
char *dflt,
|
|
DtMailBoolean decrypt)
|
|
{
|
|
DtMailEnv error;
|
|
DtMail::MailRc *mailrc = ssn->mailRc(error);
|
|
const char *value = NULL;
|
|
static char idbuf[DTMAS_IDSIZE+1];
|
|
char *charval = NULL;
|
|
|
|
DTMAS_CONCAT_MAILRC_KEY(idbuf, pfx, id);
|
|
mailrc->getValue(error, idbuf, &value, decrypt);
|
|
if (error.isSet())
|
|
{
|
|
if (NULL != dflt)
|
|
charval = strdup(dflt);
|
|
}
|
|
else
|
|
charval = strdup(value);
|
|
|
|
if (NULL != value) free((void*) value);
|
|
return charval;
|
|
}
|
|
|
|
//
|
|
// Get the specified mailrc value interpreted as an string
|
|
//
|
|
Boolean
|
|
DtMailServer::get_mailrc_value(
|
|
DtMail::Session *ssn,
|
|
char *pfx,
|
|
char *id,
|
|
Boolean dflt)
|
|
{
|
|
DtMailEnv error;
|
|
DtMail::MailRc *mailrc = ssn->mailRc(error);
|
|
const char *value = NULL;
|
|
static char idbuf[DTMAS_IDSIZE+1];
|
|
Boolean boolval = FALSE;
|
|
|
|
DTMAS_CONCAT_MAILRC_KEY(idbuf, pfx, id);
|
|
mailrc->getValue(error, idbuf, &value);
|
|
if (error.isSet())
|
|
boolval = dflt;
|
|
else
|
|
boolval = TRUE;
|
|
|
|
if (NULL != value) free((void*) value);
|
|
return boolval;
|
|
}
|
|
|
|
//
|
|
// Returns TRUE if the folder being accessed is the inbox.
|
|
//
|
|
Boolean
|
|
DtMailServer::is_inbox()
|
|
{
|
|
if (NULL==_folder || 0==strncmp(_folder, DTMAS_INBOX, strlen(DTMAS_INBOX)))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Send message to the front end for display in the status line.
|
|
//
|
|
void
|
|
DtMailServer::send_info_message(DtMailCallbackOp op)
|
|
{
|
|
const char *errmsg = (const char *) _info;
|
|
|
|
#if defined(SEPARATE_FRONT_AND_BACK_END)
|
|
DtMailEnv error;
|
|
DtMailEventPacket event;
|
|
|
|
event.key = _mailbox->getObjectKey();
|
|
event.target = DTM_TARGET_MAILBOX;
|
|
event.target_object = _mailbox;
|
|
event.operation = (void*) op;
|
|
if (NULL != errmsg)
|
|
event.argument = strdup(errmsg);
|
|
else
|
|
event.argument = NULL;
|
|
event.event_time = time(NULL);
|
|
|
|
_session->writeEventData(error, &event, sizeof(event));
|
|
#else
|
|
_mailbox->callCallback(op, strdup(errmsg));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Retrieve messages from server using given protocol method table
|
|
//
|
|
void
|
|
DtMailServer::retrieve_messages(DtMailEnv &error)
|
|
{
|
|
DTMailError_t ok = DTME_NoError;
|
|
int js;
|
|
struct sigaction action, o_action;
|
|
int *msgsizes = (int*) NULL;
|
|
int *msgisold = (int*) NULL;
|
|
|
|
_transnum = 0;
|
|
|
|
/* set up the server-nonresponse timeout */
|
|
memset((char*) &action, 0, sizeof(struct sigaction));
|
|
memset((char*) &o_action, 0, sizeof(struct sigaction));
|
|
action.sa_handler = (SA_HANDLER_TYPE) vtalarm_handler;
|
|
|
|
sigaction(SIGNAL_TYPE, (const struct sigaction *) &action, &o_action);
|
|
|
|
if ((js = setjmp(restart)) == 1)
|
|
{
|
|
_logger.logError(
|
|
DTM_TRUE,
|
|
"Timeout after %d seconds waiting for %s.\n",
|
|
_timeout, _servername);
|
|
ok = DTME_MailServerAccess_Error;
|
|
}
|
|
else if (js == 2)
|
|
{
|
|
/* error message printed at point of longjmp */
|
|
ok = DTME_MailServerAccess_Error;
|
|
}
|
|
else
|
|
{
|
|
char buf[DTMAS_POPBUFSIZE+1];
|
|
int len, num, count, numnew;
|
|
int deletions = 0;
|
|
int sockfd = -1;
|
|
|
|
if (proto_requires_password() && NULL == _password)
|
|
{
|
|
ok = DTME_MailServerAccess_MissingPassword;
|
|
goto restoreSignal;
|
|
}
|
|
|
|
vtalarm_setitimer(_timeout);
|
|
_info.vSetError(DTME_MailServerAccessInfo_SocketOpen,
|
|
DTM_FALSE, NULL, _username, _servername);
|
|
send_info_message(DTMC_SERVERACCESSINFO);
|
|
if (NULL != _errorstring)
|
|
{
|
|
free(_errorstring);
|
|
_errorstring = NULL;
|
|
}
|
|
_sockfp = SockOpen(_servername, proto_port(), &_errorstring);
|
|
if (NULL == _sockfp)
|
|
{
|
|
if (NULL == _errorstring)
|
|
_errorstring = strdup(_logger.errnoMessage());
|
|
ok = DTME_MailServerAccess_SocketIOError;
|
|
goto restoreSignal;
|
|
}
|
|
else if (_protologging)
|
|
{
|
|
_logger.logError(DTM_FALSE, "%s> %s", proto_name(), "SockOpen");
|
|
}
|
|
|
|
/* accept greeting message from mail server */
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_parse_response(buf);
|
|
if (ok != DTME_NoError) goto closeServer;
|
|
|
|
/* try to get authorized to fetch mail */
|
|
vtalarm_setitimer(_timeout);
|
|
_shroud = _password;
|
|
ok = ptrans_authorize(buf);
|
|
_shroud = (char*) NULL;
|
|
if (ok != DTME_NoError) goto closeServer;
|
|
|
|
/* compute number of messages and number of new messages waiting */
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_fldstate_read(&count, &numnew);
|
|
if (ok != DTME_NoError) goto closeServer;
|
|
|
|
/* show user how many messages we downloaded */
|
|
if (_protologging)
|
|
{
|
|
if (count == 0)
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
"INFO: No mail from %s@%s",
|
|
_username, _servername);
|
|
else
|
|
{
|
|
if (numnew != -1 && (count - numnew) > 0)
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
"INFO: %d message%s (%d seen) from %s@%s.",
|
|
count, count > 1 ? "s" : "", count-numnew,
|
|
_username, _servername);
|
|
else
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
"INFO: %d message%s from %s@%s.",
|
|
count, count > 1 ? "s" : "",
|
|
_username, _servername);
|
|
}
|
|
}
|
|
|
|
if (count > 0)
|
|
{
|
|
int nmsgtofetch = 0;
|
|
int fetched = 0;
|
|
|
|
/* we may need to get sizes in order to check message limits */
|
|
if (_sizelimit)
|
|
{
|
|
msgsizes = (int *)malloc(sizeof(int) * count);
|
|
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_msgsizes(count, msgsizes);
|
|
if (ok != DTME_NoError) goto closeServer;
|
|
}
|
|
|
|
if (! _retrieveold)
|
|
{
|
|
msgisold = (int*) malloc(sizeof(int) * count);
|
|
|
|
for (num = 1; num <= count; num++)
|
|
{
|
|
vtalarm_setitimer(_timeout);
|
|
msgisold[num-1] = ptrans_msgisold(num);
|
|
}
|
|
}
|
|
|
|
for (num = 1; num <= count; num++)
|
|
{
|
|
int toolarge = msgsizes && (msgsizes[num-1] > _sizelimit);
|
|
int ignoreold = msgisold && msgisold[num-1];
|
|
|
|
if (! (toolarge || ignoreold)) nmsgtofetch++;
|
|
}
|
|
|
|
if (! nmsgtofetch)
|
|
{
|
|
_info.vSetError(DTME_MailServerAccessInfo_NoMessages,
|
|
DTM_FALSE, NULL, _username, _servername);
|
|
send_info_message(DTMC_SERVERACCESSINFO);
|
|
}
|
|
|
|
/*
|
|
* In IMAP4 you can retrieve a message without marking it as
|
|
* having been seen while in POP3 and IMAP2BIS this is NOT
|
|
* possible. The proto_is_peek_capable encapsulates this
|
|
* capability.
|
|
*
|
|
* The problem is when there is any kind of transient error
|
|
* (DNS lookup failure, or sendmail refusing delivery due to
|
|
* process-table limits) during retrieval, the message will
|
|
* be marked "seen" on the server without having been retrieved
|
|
* by dtmail.
|
|
*
|
|
* We need to keep track of any errors which take place in a
|
|
* given retrieval pass (_retrieveerrors). If there were any
|
|
* errors during the previous pass, all messages which were new
|
|
* at that time will be delivered.
|
|
*/
|
|
|
|
/* read, forward, and delete messages */
|
|
_retrieveerrors = 0;
|
|
for (num = 1, fetched = 0; nmsgtofetch && num <= count; num++)
|
|
{
|
|
int toolarge = msgsizes && (msgsizes[num-1] > _sizelimit);
|
|
int ignoreold = msgisold && msgisold[num-1];
|
|
|
|
/*
|
|
* We may want to reject this message if it is
|
|
* too large or old
|
|
*/
|
|
if (toolarge || ignoreold)
|
|
{
|
|
if (_protologging)
|
|
{
|
|
_logger.logError(DTM_FALSE,"skipping message %d",num);
|
|
if (toolarge)
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
" (oversized, %d bytes)",
|
|
msgsizes[num-1]);
|
|
}
|
|
if (toolarge)
|
|
{
|
|
_info.vSetError(
|
|
DTME_MailServerAccessInfo_MessageTooLarge,
|
|
DTM_FALSE, NULL, msgsizes[num-1]);
|
|
send_info_message(DTMC_SERVERACCESSINFOERROR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vtalarm_setitimer(_timeout);
|
|
|
|
/*
|
|
* Fetch a message from the server.
|
|
*/
|
|
fetched++;
|
|
_info.vSetError(DTME_MailServerAccessInfo_RetrievingMessage,
|
|
DTM_FALSE, NULL,
|
|
fetched, nmsgtofetch,
|
|
_username, _servername);
|
|
send_info_message(DTMC_SERVERACCESSINFO);
|
|
|
|
ok = ptrans_retrieve_start(num, &len);
|
|
if (ok != DTME_NoError)
|
|
{
|
|
_retrieveerrors++;
|
|
goto closeServer;
|
|
}
|
|
|
|
if (_protologging)
|
|
_logger.logError(
|
|
DTM_FALSE,
|
|
"INFO: reading message %d (%d bytes)",
|
|
num, len);
|
|
|
|
/* Read the message and append it to the mailbox. */
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_retrieve_readandappend(error, len);
|
|
if (ok != DTME_NoError)
|
|
{
|
|
_retrieveerrors++;
|
|
goto closeServer;
|
|
}
|
|
|
|
/* Tell the server we got it OK and resynchronize. */
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_retrieve_end(num);
|
|
if (ok != DTME_NoError)
|
|
{
|
|
_retrieveerrors++;
|
|
goto closeServer;
|
|
}
|
|
|
|
/* Mark the message seen and remove it from the server. */
|
|
if (_removeafterdelivery)
|
|
{
|
|
deletions++;
|
|
if (_protologging)
|
|
_logger.logError(DTM_FALSE, " deleted\n");
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_delete(num);
|
|
if (ok != DTME_NoError) goto closeServer;
|
|
}
|
|
else if (_protologging)
|
|
_logger.logError(DTM_FALSE, " not deleted\n");
|
|
}
|
|
}
|
|
|
|
/* Remove all messages flagged for deletion. */
|
|
if (deletions > 0)
|
|
{
|
|
vtalarm_setitimer(_timeout);
|
|
ok = ptrans_fldstate_expunge();
|
|
if (ok != DTME_NoError) goto closeServer;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_info.vSetError(DTME_MailServerAccessInfo_NoMessages,
|
|
DTM_FALSE, NULL, _username, _servername);
|
|
send_info_message(DTMC_SERVERACCESSINFO);
|
|
}
|
|
|
|
closeServer:
|
|
vtalarm_setitimer(_timeout);
|
|
if (ok != DTME_MailServerAccess_SocketIOError)
|
|
if (ok == DTME_NoError)
|
|
ok = ptrans_quit();
|
|
else {
|
|
(void) ptrans_quit();
|
|
}
|
|
vtalarm_setitimer(0);
|
|
SockClose(_sockfp);
|
|
_sockfp = NULL;
|
|
dtmasTAGCLR();
|
|
}
|
|
|
|
restoreSignal:
|
|
_sockfp = NULL;
|
|
if (ok != DTME_NoError)
|
|
{
|
|
if (NULL == _errorstring)
|
|
_errorstring = strdup("");
|
|
error.vSetError(
|
|
ok, DTM_TRUE, NULL,
|
|
_username, _servername, proto_name(), _errorstring);
|
|
_logger.logError(
|
|
DTM_TRUE,
|
|
"Error while fetching from '%s': \n%s\n",
|
|
_servername, (const char*) error);
|
|
|
|
}
|
|
else
|
|
error.clear();
|
|
|
|
if (_errorstring)
|
|
{
|
|
free(_errorstring);
|
|
_errorstring = NULL;
|
|
}
|
|
if (msgsizes != NULL) free(msgsizes);
|
|
if (msgisold != NULL) free(msgisold);
|
|
sigaction(SIGNAL_TYPE, (const struct sigaction *) &o_action, NULL);
|
|
}
|
|
|
|
//
|
|
// Reset the nonresponse-timeout
|
|
//
|
|
#if defined(__hpux)
|
|
#define TV_USEC_TYPE long
|
|
#else
|
|
#define TV_USEC_TYPE int
|
|
#endif
|
|
void
|
|
DtMailServer::vtalarm_setitimer(int timeout_seconds)
|
|
{
|
|
struct itimerval ntimeout;
|
|
|
|
ntimeout.it_interval.tv_sec = (time_t) 0;
|
|
ntimeout.it_interval.tv_usec = (TV_USEC_TYPE) 0;
|
|
ntimeout.it_value.tv_sec = (time_t) timeout_seconds;
|
|
ntimeout.it_value.tv_usec = (TV_USEC_TYPE) 0;
|
|
setitimer(ITIMER_TYPE, &ntimeout, (struct itimerval*) NULL);
|
|
}
|
|
|
|
//
|
|
// Handle server-timeout ALARM signal
|
|
//
|
|
void
|
|
DtMailServer::vtalarm_handler(int)
|
|
{
|
|
longjmp(restart, 1);
|
|
}
|