/*
- * sock_read_to() - input binary data from socket, with a settable timeout.
- * Returns the number of bytes read, or -1 for error.
- * If keep_reading_until_full is nonzero, we keep reading until we get the number of requested bytes
+ * Read data from the client socket.
+ *
+ * sock socket fd to read from
+ * buf buffer to read into
+ * bytes number of bytes to read
+ * timeout Number of seconds to wait before timing out
+ *
+ * Possible return values:
+ * 1 Requested number of bytes has been read.
+ * 0 Request timed out.
+ * -1 Connection is broken, or other error.
*/
-int sock_read_to(int sock, char *buf, int bytes, int timeout, int keep_reading_until_full)
+int socket_read_blob(int *Socket,
+ StrBuf *Target,
+ int bytes,
+ int timeout)
{
- int len,rlen;
- fd_set rfds;
- struct timeval tv;
- int retval;
+ CitContext *CCC=CC;
+ const char *Error;
+ int retval = 0;
+
+
+ retval = StrBufReadBLOBBuffered(Target,
+ CCC->sReadBuf,
+ &CCC->sPos,
+ Socket,
+ 1,
+ bytes,
+ O_TERM,
+ &Error);
+ if (retval < 0) {
+ CtdlLogPrintf(CTDL_CRIT,
+ "%s failed: %s\n",
+ __FUNCTION__,
+ Error);
+ }
+ return retval;
+}
- len = 0;
- while (len<bytes) {
- FD_ZERO(&rfds);
- FD_SET(sock, &rfds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- retval = select(sock+1, &rfds, NULL, NULL, &tv);
+int sock_read_to(int *sock, char *buf, int bytes, int timeout, int keep_reading_until_full)
+{
+ CitContext *CCC=CC;
+ int rc;
+
+ rc = socket_read_blob(sock,
+ CCC->sMigrateBuf,
+ bytes,
+ timeout);
+ if (rc < 0)
+ {
+ *buf = '\0';
+ return rc;
+ }
+ else
+ {
+ if (StrLength(CCC->MigrateBuf) < bytes)
+ bytes = StrLength(CCC->MigrateBuf);
+ memcpy(buf,
+ ChrPtr(CCC->MigrateBuf),
+ bytes);
+
+ FlushStrBuf(CCC->MigrateBuf);
+ return rc;
+ }
+}
- if (FD_ISSET(sock, &rfds) == 0) { /* timed out */
- CtdlLogPrintf(CTDL_ERR, "sock_read() timed out.\n");
- return(-1);
- }
- rlen = read(sock, &buf[len], bytes-len);
- if (rlen<1) {
- CtdlLogPrintf(CTDL_ERR, "sock_read() failed: %s\n",
- strerror(errno));
- return(-1);
- }
- len = len + rlen;
- if (!keep_reading_until_full) return(len);
+int CtdlSockGetLine(int *sock, StrBuf *Target)
+{
+ CitContext *CCC=CC;
+ const char *Error;
+ int rc;
+
+ rc = StrBufTCP_read_buffered_line_fast(Target,
+ CCC->sReadBuf,
+ &CCC->sPos,
+ sock,
+ 5,
+ 1,
+ &Error);
+ if ((rc < 0) && (Error != NULL))
+ CtdlLogPrintf(CTDL_CRIT,
+ "%s failed: %s\n",
+ __FUNCTION__,
+ Error);
+ return rc;
+}
+
+
+/*
+ * client_getln() ... Get a LF-terminated line of text from the client.
+ * (This is implemented in terms of client_read() and could be
+ * justifiably moved out of sysdep.c)
+ */
+int sock_getln(int *sock, char *buf, int bufsize)
+{
+ int i, retval;
+ CitContext *CCC=CC;
+ const char *pCh;
+
+ retval = CtdlSockGetLine(sock, CCC->sMigrateBuf);
+
+ i = StrLength(CCC->sMigrateBuf);
+ pCh = ChrPtr(CCC->sMigrateBuf);
+ /* Strip the trailing LF, and the trailing CR if present.
+ */
+ if (bufsize <= i)
+ i = bufsize - 1;
+ while ( (i > 0)
+ && ( (pCh[i - 1]==13)
+ || ( pCh[i - 1]==10)) ) {
+ i--;
+ }
+ memcpy(buf, pCh, i);
+ buf[i] = 0;
+
+ FlushStrBuf(CCC->sMigrateBuf);
+ if (retval < 0) {
+ safestrncpy(&buf[i], "000", bufsize - i);
}
- return(bytes);
+ return(retval >= 0);
}
* sock_read() - input binary data from socket.
* Returns the number of bytes read, or -1 for error.
*/
-INLINE int sock_read(int sock, char *buf, int bytes, int keep_reading_until_full)
+INLINE int sock_read(int *sock, char *buf, int bytes, int keep_reading_until_full)
{
return sock_read_to(sock, buf, bytes, CLIENT_TIMEOUT, keep_reading_until_full);
}
}
-
-/*
- * Input string from socket - implemented in terms of sock_read()
- *
- */
-int sock_getln(int sock, char *buf, int bufsize)
-{
- int i;
-
- /* Read one character at a time.
- */
- for (i = 0;; i++) {
- if (sock_read(sock, &buf[i], 1, 1) < 0) return(-1);
- if (buf[i] == '\n' || i == (bufsize-1))
- break;
- }
-
- /* If we got a long line, discard characters until the newline.
- */
- if (i == (bufsize-1))
- while (buf[i] != '\n')
- if (sock_read(sock, &buf[i], 1, 1) < 0) return(-1);
-
- /* Strip any trailing CR and LF characters.
- */
- buf[i] = 0;
- while ( (i > 0)
- && ( (buf[i - 1]==13)
- || ( buf[i - 1]==10)) ) {
- i--;
- buf[i] = 0;
- }
- return(i);
-}
-
/*
* Multiline version of sock_gets() ... this is a convenience function for
* client side protocol implementations. It only returns the first line of
* a multiline response, discarding the rest.
*/
-int ml_sock_gets(int sock, char *buf) {
+int ml_sock_gets(int *sock, char *buf) {
char bigbuf[1024];
int g;
*/
int sock_connect(char *host, char *service, char *protocol);
-int sock_read_to(int sock, char *buf, int bytes, int timeout, int keep_reading_until_full);
-int sock_read(int sock, char *buf, int bytes, int keep_reading_until_full);
+int sock_read_to(int *sock, char *buf, int bytes, int timeout, int keep_reading_until_full);
+int sock_read(int *sock, char *buf, int bytes, int keep_reading_until_full);
int sock_write(int sock, char *buf, int nbytes);
-int ml_sock_gets(int sock, char *buf);
-int sock_getln(int sock, char *buf, int bufsize);
+int ml_sock_gets(int *sock, char *buf);
+int sock_getln(int *sock, char *buf, int bufsize);
+int CtdlSockGetLine(int *sock, StrBuf *Target);
int sock_puts(int sock, char *buf);
const char *Pos; /* Our read position inside of the ReadBuf */
StrBuf *ReadBuf; /* Our block buffered read buffer */
StrBuf *MigrateBuf; /* Our block buffered read buffer */
+
+ const char *sPos; /* Our read position inside of the ReadBuf */
+ StrBuf *sReadBuf; /* Our block buffered read buffer */
+ StrBuf *sMigrateBuf; /* Our block buffered read buffer */
int client_socket;
int is_local_socket; /* set to 1 if client is on unix domain sock */
/* Redirect this session's output to a memory buffer? */
sock_write(sock, buf, strlen(buf));
CtdlLogPrintf(CTDL_DEBUG, "Waiting for PORT number\n");
- if (sock_getln(sock, buf, sizeof buf) < 0) {
+ if (sock_getln(&sock, buf, sizeof buf) < 0) {
goto bail;
}
/* Response */
CtdlLogPrintf(CTDL_DEBUG, "Awaiting response\n");
- if (sock_getln(sock, buf, sizeof buf) < 0) {
+ if (sock_getln(&sock, buf, sizeof buf) < 0) {
goto bail;
}
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
/*
* receive network spool from the remote system
*/
-void receive_spool(int sock, char *remote_nodename) {
+void receive_spool(int *sock, char *remote_nodename) {
size_t siz;
long download_len = 0L;
long bytes_received = 0L;
FILE *fp, *newfp;
CtdlMakeTempFileName(tempfilename, sizeof tempfilename);
- if (sock_puts(sock, "NDOP") < 0) return;
+ if (sock_puts(*sock, "NDOP") < 0) return;
if (sock_getln(sock, buf, sizeof buf) < 0) return;
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (buf[0] != '2') {
bytes_received,
((download_len - bytes_received > IGNET_PACKET_SIZE)
? IGNET_PACKET_SIZE : (download_len - bytes_received)));
- if (sock_puts(sock, buf) < 0) {
+ if (sock_puts(*sock, buf) < 0) {
fclose(fp);
unlink(tempfilename);
return;
unlink(tempfilename);
return;
}
- if (sock_puts(sock, "CLOS") < 0) {
+ if (sock_puts(*sock, "CLOS") < 0) {
unlink(tempfilename);
return;
}
/*
* transmit network spool to the remote system
*/
-void transmit_spool(int sock, char *remote_nodename)
+void transmit_spool(int *sock, char *remote_nodename)
{
char buf[SIZ];
char pbuf[4096];
int fd;
char sfname[128];
- if (sock_puts(sock, "NUOP") < 0) return;
+ if (sock_puts(*sock, "NUOP") < 0) return;
if (sock_getln(sock, buf, sizeof buf) < 0) return;
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (buf[0] != '2') {
}
snprintf(buf, sizeof buf, "WRIT %ld", bytes_to_write);
- if (sock_puts(sock, buf) < 0) {
+ if (sock_puts(*sock, buf) < 0) {
close(fd);
return;
}
}
thisblock = atol(&buf[4]);
if (buf[0] == '7') {
- if (sock_write(sock, pbuf,
+ if (sock_write(*sock, pbuf,
(int) thisblock) < 0) {
close(fd);
return;
if(CtdlThreadCheckStop())
return;
- if (sock_puts(sock, "UCLS 1") < 0) return;
+ if (sock_puts(*sock, "UCLS 1") < 0) return;
/**
* From here on we must complete or messages will get lost
*/
CtdlLogPrintf(CTDL_DEBUG, "Connected!\n");
/* Read the server greeting */
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
/* Check that the remote is who we think it is and warn the Aide if not */
snprintf(buf, sizeof buf, "NETP %s|%s", config.c_nodename, secret);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (buf[0] != '2') goto bail;
/* At this point we are authenticated. */
if (!CtdlThreadCheckStop())
- receive_spool(sock, node);
+ receive_spool(&sock, node);
if (!CtdlThreadCheckStop())
- transmit_spool(sock, node);
+ transmit_spool(&sock, node);
}
sock_puts(sock, "QUIT");
CtdlLogPrintf(CTDL_DEBUG, "Connected!\n");
/* Read the server greeting */
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (strncasecmp(buf, "+OK", 3)) goto bail;
snprintf(buf, sizeof buf, "USER %s\r", pop3user);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (strncasecmp(buf, "+OK", 3)) goto bail;
snprintf(buf, sizeof buf, "PASS %s\r", pop3pass);
CtdlLogPrintf(CTDL_DEBUG, "<PASS <password>\n");
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (strncasecmp(buf, "+OK", 3)) goto bail;
snprintf(buf, sizeof buf, "LIST\r");
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (strncasecmp(buf, "+OK", 3)) goto bail;
if (CtdlThreadCheckStop())
goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
msg_to_fetch = atoi(buf);
if (msg_to_fetch > 0) {
snprintf(buf, sizeof buf, "UIDL %d\r", msglist[i]);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (strncasecmp(buf, "+OK", 3)) goto bail;
extract_token(this_uidl, buf, 2, ' ', sizeof this_uidl);
snprintf(buf, sizeof buf, "RETR %d\r", msglist[i]);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
if (strncasecmp(buf, "+OK", 3)) goto bail;
goto bail;
/* If we get to this point, the message is on its way. Read it. */
- body = CtdlReadMessageBody(HKEY("."), config.c_maxmsglen, NULL, 1, sock);
+ body = CtdlReadMessageBody(HKEY("."), config.c_maxmsglen, NULL, 1, &sock);
if (body == NULL) goto bail;
CtdlLogPrintf(CTDL_DEBUG, "Converting message...\n");
snprintf(buf, sizeof buf, "DELE %d\r", msglist[i]);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); /* errors here are non-fatal */
}
snprintf(buf, sizeof buf, "QUIT\r");
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (sock_puts(sock, buf) <0) goto bail;
- if (sock_getln(sock, buf, sizeof buf) < 0) goto bail;
+ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf);
bail: sock_close(sock);
if (msglist) free(msglist);
*/
void smtp_data(void) {
StrBuf *body;
+ char *defbody; //TODO: remove me
struct CtdlMessage *msg = NULL;
long msgnum = (-1L);
char nowstamp[SIZ];
cprintf("354 Transmit message now - terminate with '.' by itself\r\n");
datestring(nowstamp, sizeof nowstamp, time(NULL), DATESTRING_RFC822);
- body = malloc(4096);
+ defbody = malloc(4096);
if (body != NULL) {
if (sSMTP->is_lmtp && (CC->cs_UDSclientUID != -1)) {
- snprintf(body, 4096,
- "Received: from %s (Citadel from userid %ld)\n"
- " by %s; %s\n",
- sSMTP->helo_node,
- (long int) CC->cs_UDSclientUID,
- config.c_fqdn,
- nowstamp);
+ snprintf(defbody, 4096,
+ "Received: from %s (Citadel from userid %ld)\n"
+ " by %s; %s\n",
+ sSMTP->helo_node,
+ (long int) CC->cs_UDSclientUID,
+ config.c_fqdn,
+ nowstamp);
}
else {
- snprintf(body, 4096,
+ snprintf(defbody, 4096,
"Received: from %s (%s [%s])\n"
" by %s; %s\n",
sSMTP->helo_node,
nowstamp);
}
}
- body = CtdlReadMessageBodyBuf(HKEY("."), config.c_maxmsglen, body, 1, 0);
+ body = CtdlReadMessageBodyBuf(HKEY("."), config.c_maxmsglen, defbody, 1, NULL);
if (body == NULL) {
cprintf("550 Unable to save message: internal error.\r\n");
return;
}
/* Process the SMTP greeting from the server */
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP conversation");
goto bail;
snprintf(buf, sizeof buf, "EHLO %s\r\n", config.c_fqdn);
CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
sock_write(sock, buf, strlen(buf));
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP HELO");
goto bail;
snprintf(buf, sizeof buf, "HELO %s\r\n", config.c_fqdn);
CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
sock_write(sock, buf, strlen(buf));
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP HELO");
goto bail;
snprintf(buf, sizeof buf, "AUTH PLAIN %s\r\n", encoded);
CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
sock_write(sock, buf, strlen(buf));
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP AUTH");
goto bail;
snprintf(buf, sizeof buf, "MAIL FROM:<%s>\r\n", envelope_from);
CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
sock_write(sock, buf, strlen(buf));
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP MAIL");
goto bail;
snprintf(buf, sizeof buf, "RCPT TO:<%s@%s>\r\n", user, node);
CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
sock_write(sock, buf, strlen(buf));
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP RCPT");
goto bail;
/* RCPT succeeded, now try the DATA command */
CtdlLogPrintf(CTDL_DEBUG, ">DATA\n");
sock_write(sock, "DATA\r\n", 6);
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP DATA");
goto bail;
}
sock_write(sock, ".\r\n", 3);
- if (ml_sock_gets(sock, buf) < 0) {
+ if (ml_sock_gets(&sock, buf) < 0) {
*status = 4;
strcpy(dsn, "Connection broken during SMTP message transmit");
goto bail;
CtdlLogPrintf(CTDL_DEBUG, ">QUIT\n");
sock_write(sock, "QUIT\r\n", 6);
- ml_sock_gets(sock, buf);
+ ml_sock_gets(&sock, buf);
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
CtdlLogPrintf(CTDL_INFO, "SMTP client: delivery to <%s> @ <%s> (%s) succeeded\n",
user, node, name);
/* Response */
CtdlLogPrintf(CTDL_DEBUG, "Awaiting response\n");
- if (sock_getln(sock, buf, sizeof buf) < 0) {
+ if (sock_getln(&sock, buf, sizeof buf) < 0) {
goto bail;
}
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
if (strncasecmp(buf, "SPAMD", 5)) {
goto bail;
}
- if (sock_getln(sock, buf, sizeof buf) < 0) {
+ if (sock_getln(&sock, buf, sizeof buf) < 0) {
goto bail;
}
CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
char *exist, /* if non-null, append to it;
exist is ALWAYS freed */
int crlf, /* CRLF newlines instead of LF */
- int sock /* socket handle or 0 for this session's client socket */
+ int *sock /* socket handle or 0 for this session's client socket */
)
{
StrBuf *Message;
/* read in the lines of message text one by one */
do {
- if (sock > 0) {
- if (sock_getln(sock, buf, (sizeof buf - 3)) < 0) finished = 1;
+ if (sock != NULL) {
+ if ((CtdlSockGetLine(sock, LineBuf) < 0) ||
+ (*sock == -1))
+ finished = 1;
}
else {
if (CtdlClientGetLine(LineBuf) < 0) finished = 1;
char *exist, /* if non-null, append to it;
exist is ALWAYS freed */
int crlf, /* CRLF newlines instead of LF */
- int sock /* socket handle or 0 for this session's client socket */
+ int *sock /* socket handle or 0 for this session's client socket */
)
{
StrBuf *Message;
int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs,
int do_repl_check, struct CtdlMessage *supplied_msg);
int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int do_repl_check, struct CtdlMessage *msg);
-char *CtdlReadMessageBody(char *terminator, long tlen, size_t maxlen, char *exist, int crlf, int sock);
+char *CtdlReadMessageBody(char *terminator, long tlen, size_t maxlen, char *exist, int crlf, int *sock);
StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */
long tlen,
size_t maxlen, /* maximum message length */
char *exist, /* if non-null, append to it;
exist is ALWAYS freed */
int crlf, /* CRLF newlines instead of LF */
- int sock /* socket handle or 0 for this session's client socket */
+ int *sock /* socket handle or 0 for this session's client socket */
);
int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */
return 0;
}
#endif
+ if (Ctx->client_socket == -1) return -1;
fdflags = fcntl(Ctx->client_socket, F_GETFL);
- while (bytes_written < nbytes) {
+ while ((bytes_written < nbytes) && (Ctx->client_socket != -1)){
if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
FD_ZERO(&wset);
FD_SET(Ctx->client_socket, &wset);