aboutsummaryrefslogtreecommitdiff
path: root/src/smtpap/io.c
blob: f45e5cf3c87201ff4584b6591aca0410d367c414 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <sys/time.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../common/log.h"
#include "../common/utils.h"

#include "smtpap.h"
#include "io.h"

/* connection timeout */
extern struct timeval *conn_toutp;

/* printf-like function used to send messages to a socket */
int sendmessage(int s, char *buf, size_t buflen, const char *format, ...)
{
  int retval = 0;
  va_list ap;
  
  if (!buf)
    return -1;
  
  va_start(ap,format);
  retval = vsnprintf(buf,buflen, format, ap);
  va_end(ap);
  
  if (retval < 0) 
  {
    log(LOG_DEBUG,"sendmessage() : could not print to buffer");
    return -1;
  }

  log(LOG_DEBUG,"sendmessage() : printed this to buffer : %s",buf);
  
  retval = write_tout(s,buf,(size_t)retval, conn_toutp);
  if (retval < 0)
  {
    log(LOG_DEBUG,"sendmessage() : could not send");
    return -1;
  }
  
  return retval;
}

/* receive a response from the recipient SMTP server into *op_in
 * Can handle multi-line responses. */
int receive(int s, char **inbuf,size_t *inbuflen, int flags)
{
  int inputlen = 0; /* running total length of the input */
  int inputerror = 0; /* has an error occured? */
  int retval = 0; /* used for saving function return values */
  
  /* for processing multi-line responses */
  int i=0;
  
  /* storing old values of *inbuf and *inbuflen */
  char *inbuf_old = NULL;
  size_t inbuflen_old=0;
  
  if ((!inbuf) || (!*inbuf) || (!inbuflen))
    return -1;

  /* saving old values in case we need to restore them */
  inbuf_old = *inbuf;
  inbuflen_old = *inbuflen;

  do
  {
    if (inputlen == *inbuflen-1) /* we need to increase the buffer size */
    {
      /* increase the size of the buffer */
      *inbuflen += 512;
      
      *inbuf = (char *)realloc(*inbuf,(size_t)*inbuflen);
      if (!*inbuf)
      {
	log(LOG_ERR,"Could not allocate memory.");
	*inbuf = inbuf_old;
	*inbuflen = inbuflen_old;
	inputerror = 1;
	break;
      }
    }
    
    retval=read_tout(s,*inbuf+inputlen,(size_t)(*inbuflen-inputlen-1),flags, conn_toutp); /* subtract 1 from inbuflen to leave space for \0 */
    if (retval <= 0)
    {
      log(LOG_ERR,"Error occured while receiving data.");
      inputerror = 1;
      break;
    }
    else
    {
      inputerror = 0;
      inputlen += retval;

      /* exit clause if we have received CRLF, otherwise we need to keep reading*/
      /* also keep on reading if it's a multi-line response */
      if (inputlen >= SMTPAP_CRLF_LEN)
      {
	if (!strncmp(*inbuf+inputlen-SMTPAP_CRLF_LEN,SMTPAP_CRLF,SMTPAP_CRLF_LEN)) /* entire line received */
	{
	  /* now check wether we should expect more lines */
	  /* find the <CRLF> sequence which occurs one before last */
	  for(i=inputlen-SMTPAP_CRLF_LEN-1; i > 0; i--) /* move backwards, start just before the final CRLF */
	  {
	    if ((*inbuf)[i] == SMTPAP_LF) /* got a LF */
	    {
	      /* check for a CR preceding it */
	      if ((*inbuf)[i-1] == SMTPAP_CR) /* got a CR */
		break;
	    }
	  }
	  if (i==0) /* correct the offset if no CRLF found */
	    i=-1;

	  /* check the 4th character after the <CRLF> to see if it is - or <SP> */
	  if ((*inbuf)[i+4] != '-') /* no more lines */
	    break;
	}
      }
    }
  } while(1); 
  
  if (!inputerror)
  {
    (*inbuf)[inputlen]=0; /* add the terminating NULL character */
    return inputlen;
  }

  return -1;
}