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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
/*
* This file is part of libESMTP, a library for submission of RFC 2822
* formatted electronic mail messages using the SMTP protocol described
* in RFC 2821.
*
* Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Functions to read lines or blocks of text from the message source.
These functions allow the library to interface to the application
using a callback function. This is intended to allow the application
maximum flexibility in managing its message storage. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "message-source.h"
/* This is similar to code in siobuf.c */
struct msg_source
{
/* Callback to fill the input buffer */
const char *(*cb) (void **ctx, int *len, void *arg);
void *arg;
void *ctx;
/* Input buffer */
const char *rp; /* input buffer pointer */
int rn; /* number of bytes unread in buffer */
/* Output buffer (used by msg_gets()) */
char *buf;
size_t nalloc;
};
msg_source_t
msg_source_create (void)
{
msg_source_t source;
if ((source = malloc (sizeof (struct msg_source))) != NULL)
memset (source, 0, sizeof (struct msg_source));
return source;
}
void
msg_source_destroy (msg_source_t source)
{
assert (source != NULL);
if (source->ctx != NULL)
free (source->ctx);
if (source->buf != NULL)
free (source->buf);
free (source);
}
void
msg_source_set_cb (msg_source_t source,
const char *(*cb) (void **ctx, int *len, void *arg),
void *arg)
{
assert (source != NULL);
if (source->ctx != NULL)
{
free (source->ctx);
source->ctx = NULL;
}
source->cb = cb;
source->arg = arg;
}
/* Use the callback to get data from the message source.
*/
static int
msg_fill (msg_source_t source)
{
assert (source != NULL && source->cb != NULL);
source->rp = (*source->cb) (&source->ctx, &source->rn, source->arg);
return source->rn > 0;
}
void
msg_rewind (msg_source_t source)
{
assert (source != NULL && source->cb != NULL);
(*source->cb) (&source->ctx, NULL, source->arg);
}
/* Line oriented reader. An output buffer is allocated as required.
The return value is a pointer to the line and remains valid until the
next call to msg_gets (). The line is guaranteed to be terminated
with a \r\n. Len is set to the number of octets in the buffer.
The line is *not* terminated with a \0.
If concatenate is non-zero, the next line of input is concatenated
with the existing line and the return value points to the original
line in the buffer. In this case *len is the number of octets in
the buffer when called and is updated to the new count on return.
*/
const char *
msg_gets (msg_source_t source, int *len, int concatenate)
{
int lastc, c, buflen;
char *p, *nbuf;
assert (source != NULL && len != NULL);
if (source->rn <= 0 && !msg_fill (source))
return NULL;
if (source->buf == NULL)
{
source->nalloc = 1023; /* RFC 2821 max line length + slack */
source->buf = malloc (source->nalloc + 2);
if (source->buf == NULL)
return NULL;
}
p = source->buf;
buflen = source->nalloc;
if (concatenate)
{
p += *len;
buflen -= *len;
}
lastc = 0;
while (source->rn > 0 || msg_fill (source))
{
c = *source->rp++;
source->rn--;
if (buflen <= 0)
{
buflen = 512;
source->nalloc += buflen;
nbuf = realloc (source->buf, source->nalloc + 2);
if (nbuf == NULL)
{
free (source->buf);
return NULL;
}
p = nbuf + (p - source->buf);
source->buf = nbuf;
}
*p++ = c;
buflen--;
if (c == '\n' && lastc == '\r')
{
*len = p - source->buf;
return source->buf;
}
lastc = c;
}
/* Only get here if the input was not properly terminated with a \r\n.
The handling of the DATA command in protocol.c relies on the \n
so we add it here. This is why there is 2 characters of slack in
malloc and realloc above. */
if (lastc != '\r')
*p++ = '\r';
*p++ = '\n';
*len = p - source->buf;
return source->buf;
}
/* Return the next character in the source, i.e. the first character
that will be returned by the next call to msg_gets(). This is
currently only used to check for RFC 2822 header continuation lines.
It is not safe to use in conjunction with msg_getb().
*/
int
msg_nextc (msg_source_t source)
{
assert (source != NULL);
if (source->rn <= 0 && !msg_fill (source))
return -1;
return *source->rp;
}
/* Block oriented reader. The output buffer is not used for efficiency.
*/
const char *
msg_getb (msg_source_t source, int *len)
{
assert (source != NULL);
if (source->rn <= 0 && !msg_fill (source))
return NULL;
/* Just return whatever is in the input buffer */
*len = source->rn;
source->rn = 0;
return source->rp;
}
|