1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
4
* Michael Zucchi <notzed@ximian.com>
6
* Copyright 2002 Ximian, Inc. (www.ximian.com)
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of version 2 of the GNU Lesser General Public
10
* License as published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23
/* This is *identical* to the camel-nntp-stream, so should probably
24
work out a way to merge them */
37
#include "camel-pop3-stream.h"
39
extern int camel_verbose_debug;
40
#define dd(x) (camel_verbose_debug?(x):0)
42
static CamelObjectClass *parent_class = NULL;
44
/* Returns the class for a CamelStream */
45
#define CS_CLASS(so) CAMEL_POP3_STREAM_CLASS(CAMEL_OBJECT_GET_CLASS(so))
47
#define CAMEL_POP3_STREAM_SIZE (4096)
48
#define CAMEL_POP3_STREAM_LINE (1024) /* maximum line size */
51
stream_fill(CamelPOP3Stream *is)
56
left = is->end - is->ptr;
57
memcpy(is->buf, is->ptr, left);
58
is->end = is->buf + left;
60
left = camel_stream_read(is->source, (char*) is->end, CAMEL_POP3_STREAM_SIZE - (is->end - is->buf));
64
return is->end - is->ptr;
66
pop3_debug ("POP3_STREAM_FILL(ERROR): '%s'\n", strerror (errno));
75
stream_read(CamelStream *stream, char *buffer, size_t n)
77
CamelPOP3Stream *is = (CamelPOP3Stream *)stream;
79
unsigned char *p, *e, c;
82
if (is->mode != CAMEL_POP3_STREAM_DATA || n == 0)
89
/* Need to copy/strip '.'s and whatnot */
95
case 0: /* start of line, always read at least 3 chars */
98
if (stream_fill(is) == -1)
104
if (p[1] == '\r' && p[2] == '\n') {
106
is->mode = CAMEL_POP3_STREAM_EOD;
108
pop3_debug ("POP3_STREAM_READ %d bytes:\n", (int)(o-buffer));
115
case 1: /* looking for next sol */
119
/* end of input sentinal check */
122
if (stream_fill(is) == -1)
131
} else if (c != '\r') {
141
pop3_debug ("POP3_STREAM_READ %d bytes\n", (int)(o-buffer));
147
stream_write(CamelStream *stream, const char *buffer, size_t n)
149
CamelPOP3Stream *is = (CamelPOP3Stream *)stream;
151
if (strncmp (buffer, "PASS ", 5) != 0) {
152
pop3_debug("POP3_STREAM_WRITE(%d):\n%.*s\n", (int)n, (int)n, buffer);
154
pop3_debug("POP3_STREAM_WRITE(%d):\nPASS xxxxxxxx\n", (int)n);
157
return camel_stream_write(is->source, buffer, n);
161
stream_close(CamelStream *stream)
168
stream_flush(CamelStream *stream)
175
stream_eos(CamelStream *stream)
177
CamelPOP3Stream *is = (CamelPOP3Stream *)stream;
179
return is->mode != CAMEL_POP3_STREAM_DATA;
183
stream_reset(CamelStream *stream)
185
/* nop? reset literal mode? */
190
camel_pop3_stream_class_init (CamelStreamClass *camel_pop3_stream_class)
192
CamelStreamClass *camel_stream_class = (CamelStreamClass *)camel_pop3_stream_class;
194
parent_class = camel_type_get_global_classfuncs( CAMEL_OBJECT_TYPE );
196
/* virtual method definition */
197
camel_stream_class->read = stream_read;
198
camel_stream_class->write = stream_write;
199
camel_stream_class->close = stream_close;
200
camel_stream_class->flush = stream_flush;
201
camel_stream_class->eos = stream_eos;
202
camel_stream_class->reset = stream_reset;
206
camel_pop3_stream_init(CamelPOP3Stream *is, CamelPOP3StreamClass *isclass)
208
/* +1 is room for appending a 0 if we need to for a line */
209
is->ptr = is->end = is->buf = g_malloc(CAMEL_POP3_STREAM_SIZE+1);
210
is->lineptr = is->linebuf = g_malloc(CAMEL_POP3_STREAM_LINE+1);
211
is->lineend = is->linebuf + CAMEL_POP3_STREAM_LINE;
217
is->mode = CAMEL_POP3_STREAM_LINE;
221
camel_pop3_stream_finalise(CamelPOP3Stream *is)
226
camel_object_unref((CamelObject *)is->source);
230
camel_pop3_stream_get_type (void)
232
static CamelType camel_pop3_stream_type = CAMEL_INVALID_TYPE;
234
if (camel_pop3_stream_type == CAMEL_INVALID_TYPE) {
235
camel_pop3_stream_type = camel_type_register( camel_stream_get_type(),
237
sizeof( CamelPOP3Stream ),
238
sizeof( CamelPOP3StreamClass ),
239
(CamelObjectClassInitFunc) camel_pop3_stream_class_init,
241
(CamelObjectInitFunc) camel_pop3_stream_init,
242
(CamelObjectFinalizeFunc) camel_pop3_stream_finalise );
245
return camel_pop3_stream_type;
249
* camel_pop3_stream_new:
251
* Returns a NULL stream. A null stream is always at eof, and
252
* always returns success for all reads and writes.
254
* Return value: the stream
257
camel_pop3_stream_new(CamelStream *source)
261
is = (CamelPOP3Stream *)camel_object_new(camel_pop3_stream_get_type ());
262
camel_object_ref((CamelObject *)source);
265
return (CamelStream *)is;
268
/* Get one line from the pop3 stream */
270
camel_pop3_stream_line(CamelPOP3Stream *is, unsigned char **data, unsigned int *len)
272
register unsigned char c, *p, *o, *oe;
276
if (is->mode == CAMEL_POP3_STREAM_EOD) {
283
oe = is->lineend - 1;
287
/* Data mode, convert leading '..' to '.', and stop when we reach a solitary '.' */
288
if (is->mode == CAMEL_POP3_STREAM_DATA) {
289
/* need at least 3 chars in buffer */
292
if (stream_fill(is) == -1)
298
/* check for isolated '.\r\n' or begging of line '.' */
300
if (p[1] == '\r' && p[2] == '\n') {
302
is->mode = CAMEL_POP3_STREAM_EOD;
307
dd(printf("POP3_STREAM_LINE(END)\n"));
322
if (stream_fill(is) == -1)
329
*len = o - is->linebuf;
332
dd(printf("POP3_STREAM_LINE(%d): '%s'\n", *len, *data));
336
} else if (c != '\r') {
341
/* limit this for bad server data? */
342
oldlen = o - is->linebuf;
343
newlen = (is->lineend - is->linebuf) * 3 / 2;
344
is->lineptr = is->linebuf = g_realloc(is->linebuf, newlen);
345
is->lineend = is->linebuf + newlen;
346
oe = is->lineend - 1;
347
o = is->linebuf + oldlen;
353
/* returns -1 on error, 0 if last lot of data, >0 if more remaining */
354
int camel_pop3_stream_gets(CamelPOP3Stream *is, unsigned char **start, unsigned int *len)
361
max = is->end - is->ptr;
363
max = stream_fill(is);
369
end = memchr(is->ptr, '\n', max);
371
max = (end - is->ptr) + 1;
376
dd(printf("POP3_STREAM_GETS(%s,%d): '%.*s'\n", end==NULL?"more":"last", *len, (int)*len, *start));
378
return end == NULL?1:0;
381
void camel_pop3_stream_set_mode(CamelPOP3Stream *is, camel_pop3_stream_mode_t mode)
386
/* returns -1 on erorr, 0 if last data, >0 if more data left */
387
int camel_pop3_stream_getd(CamelPOP3Stream *is, unsigned char **start, unsigned int *len)
389
unsigned char *p, *e, *s;
394
if (is->mode == CAMEL_POP3_STREAM_EOD)
397
if (is->mode == CAMEL_POP3_STREAM_LINE) {
398
g_warning("pop3_stream reading data in line mode\n");
408
if (stream_fill(is) == -1)
419
/* check leading '.', ... */
421
if (p[1] == '\r' && p[2] == '\n') {
425
is->mode = CAMEL_POP3_STREAM_EOD;
428
dd(printf("POP3_STREAM_GETD(%s,%d): '%.*s'\n", "last", *len, (int)*len, *start));
433
/* If at start, just skip '.', else return data upto '.' but skip it */
443
dd(printf("POP3_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start));
450
/* Scan for sentinal */
461
} while ((e-p) >= 3);
468
dd(printf("POP3_STREAM_GETD(%s,%d): '%.*s'\n", "more", *len, (int)*len, *start));