meillo@0: /*  MasqMail
meillo@0:     Copyright (C) 2000 Oliver Kurth
meillo@0: 
meillo@0:     This program is free software; you can redistribute it and/or modify
meillo@0:     it under the terms of the GNU General Public License as published by
meillo@0:     the Free Software Foundation; either version 2 of the License, or
meillo@0:     (at your option) any later version.
meillo@0: 
meillo@0:     This program is distributed in the hope that it will be useful,
meillo@0:     but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
meillo@0:     GNU General Public License for more details.
meillo@0: 
meillo@0:     You should have received a copy of the GNU General Public License
meillo@0:     along with this program; if not, write to the Free Software
meillo@0:     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
meillo@0: */
meillo@0: 
meillo@0: #include <signal.h>
meillo@0: #include <stdio.h>
meillo@0: #include <stdlib.h>
meillo@0: #include <setjmp.h>
meillo@0: #include <unistd.h>
meillo@0: #include <ctype.h>
meillo@15: 
meillo@0: #include "readsock.h"
meillo@15: /*#include "masqmail.h"*/
meillo@0: 
meillo@0: jmp_buf jmp_timeout;
meillo@0: 
meillo@10: static void
meillo@10: sig_timeout_handler(int sig)
meillo@0: {
meillo@10: 	longjmp(jmp_timeout, 1);
meillo@0: }
meillo@0: 
meillo@0: static struct sigaction old_sa_alrm;
meillo@0: 
meillo@10: static void
meillo@10: alarm_on(int timeout)
meillo@0: {
meillo@10: 	struct sigaction sa;
meillo@0: 
meillo@10: 	sa.sa_handler = sig_timeout_handler;
meillo@10: 	sigemptyset(&(sa.sa_mask));
meillo@10: 	sa.sa_flags = 0;
meillo@10: 	sigaction(SIGALRM, &sa, &old_sa_alrm);
meillo@0: 
meillo@10: 	if (timeout > 0)
meillo@10: 		alarm(timeout);
meillo@0: }
meillo@0: 
meillo@10: static void
meillo@10: alarm_off()
meillo@0: {
meillo@10: 	alarm(0);
meillo@0: 
meillo@10: 	sigaction(SIGALRM, &old_sa_alrm, NULL);
meillo@0: }
meillo@0: 
meillo@10: static void
meillo@10: _read_chug(FILE * in)
meillo@0: {
meillo@10: 	int c = 0;
meillo@0: 
meillo@10: 	c = fgetc(in);
meillo@10: 	while (isspace(c) && (c != EOF))
meillo@10: 		c = fgetc(in);
meillo@10: 	ungetc(c, in);
meillo@0: }
meillo@0: 
meillo@10: static int
meillo@10: _read_line(FILE * in, char *buf, int buf_len, int timeout)
meillo@0: {
meillo@10: 	int p = 0;
meillo@10: 	int c = 0;
meillo@0: 
meillo@10: 	c = fgetc(in);
meillo@10: 	while ((c != '\n') && (c != EOF) && (p < buf_len - 1)) {
meillo@10: 		buf[p++] = c;
meillo@10: 		c = fgetc(in);
meillo@10: 	}
meillo@0: 
meillo@15: 	buf[p] = '\0';
meillo@0: 
meillo@10: 	if (c == EOF)
meillo@10: 		return -1;
meillo@10: 	else if (p >= buf_len) {
meillo@10: 		ungetc(c, in);
meillo@10: 		return -2;
meillo@10: 	}
meillo@0: 
meillo@10: 	buf[p++] = c;  /* \n */
meillo@15: 	buf[p] = '\0';
meillo@0: 
meillo@10: 	return p;
meillo@0: }
meillo@0: 
meillo@10: int
meillo@10: read_sockline(FILE * in, char *buf, int buf_len, int timeout, unsigned int flags)
meillo@0: {
meillo@10: 	int p = 0;
meillo@0: 
meillo@10: 	if (setjmp(jmp_timeout) != 0) {
meillo@10: 		alarm_off();
meillo@10: 		return -3;
meillo@10: 	}
meillo@0: 
meillo@10: 	alarm_on(timeout);
meillo@0: 
meillo@10: 	/* strip leading spaces */
meillo@10: 	if (flags & READSOCKL_CHUG) {
meillo@10: 		_read_chug(in);
meillo@10: 	}
meillo@0: 
meillo@10: 	p = _read_line(in, buf, buf_len, timeout);
meillo@0: 
meillo@10: 	alarm_off();
meillo@0: 
meillo@10: 	if (p > 1) {
meillo@10: 		/* here we are sure that buf[p-1] == '\n' */
meillo@10: 		if (flags & READSOCKL_CVT_CRLF) {
meillo@10: 			if ((buf[p - 2] == '\r') && (buf[p - 1] == '\n')) {
meillo@10: 				buf[p - 2] = '\n';
meillo@10: 				buf[p - 1] = 0;
meillo@10: 				p--;
meillo@10: 			}
meillo@10: 		}
meillo@10: 	}
meillo@10: 	return p;
meillo@0: }
meillo@0: 
meillo@10: int
meillo@10: read_sockline1(FILE * in, char **pbuf, int *buf_len, int timeout, unsigned int flags)
meillo@0: {
meillo@10: 	int p = 0, size = *buf_len;
meillo@10: 	char *buf;
meillo@0: 
meillo@10: 	if (setjmp(jmp_timeout) != 0) {
meillo@10: 		alarm_off();
meillo@10: 		return -3;
meillo@10: 	}
meillo@0: 
meillo@10: 	alarm_on(timeout);
meillo@0: 
meillo@10: 	/* strip leading spaces */
meillo@10: 	if (flags & READSOCKL_CHUG) {
meillo@10: 		_read_chug(in);
meillo@10: 	}
meillo@0: 
meillo@10: 	if (!*pbuf)
meillo@27: 		*pbuf = g_malloc(size);
meillo@10: 	buf = *pbuf;
meillo@0: 
meillo@10: 	while (1) {
meillo@10: 		int pp;
meillo@0: 
meillo@10: 		pp = _read_line(in, buf, size, timeout);
meillo@10: 		if (pp == -2) {
meillo@10: 			*pbuf = realloc(*pbuf, *buf_len + size);
meillo@10: 			buf = *pbuf + *buf_len;
meillo@10: 			*buf_len += size;
meillo@10: 			p += size;
meillo@10: 		} else {
meillo@10: 			if (pp > 0)
meillo@10: 				p += pp;
meillo@10: 			else
meillo@10: 				p = pp;
meillo@10: 			break;
meillo@10: 		}
meillo@10: 	}
meillo@0: 
meillo@10: 	alarm_off();
meillo@10: 
meillo@10: 	if (p > 1) {
meillo@10: 		buf = *pbuf;
meillo@10: 		/* here we are sure that buf[p-1] == '\n' */
meillo@10: 		if (flags & READSOCKL_CVT_CRLF) {
meillo@10: 			if ((buf[p - 2] == '\r') && (buf[p - 1] == '\n')) {
meillo@10: 				buf[p - 2] = '\n';
meillo@15: 				buf[p - 1] = '\0';
meillo@10: 				p--;
meillo@10: 			}
meillo@10: 		}
meillo@10: 	}
meillo@10: 	return p;
meillo@0: }