summaryrefslogtreecommitdiff
path: root/mh/mh_stream.c
blob: 80d617c6c640bc9273ebd8518546a88cf67152d0 (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
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
/* GNU Mailutils -- a suite of utilities for electronic mail
   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.

   GNU Mailutils is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   GNU Mailutils 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Mailutils; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA  */

/* This file implements an MH draftfile stream: a read-only stream used
   to transparently pass MH draftfiles to the mailers. The only difference
   between the usual RFC822 and MH draft is that the latter allows to use
   a string of dashes to separate the headers from the body. */

#include <mh.h>
#include <mailutils/stream.h>

struct _mhdraft_stream {
  stream_t stream;     /* Actual stream */
  size_t mark_offset;  /* Offset of the header separator */
  size_t mark_length;  /* Length of the header separator (not counting the
			  newline) */
};

static int
_mhdraft_read (stream_t stream, char *optr, size_t osize,
	       off_t offset, size_t *nbytes)
{
  struct _mhdraft_stream *s = stream_get_owner (stream);

  if (offset < s->mark_offset)
    {
      if (offset + osize >= s->mark_offset)
	osize = s->mark_offset - offset;
    }
  else
    offset += s->mark_length;
  return stream_read (s->stream, optr, osize, offset, nbytes);
}
  
static int
_mhdraft_readline (stream_t stream, char *optr, size_t osize,
		   off_t offset, size_t *nbytes)
{
  struct _mhdraft_stream *s = stream_get_owner (stream);
    
  if (offset < s->mark_offset)
    {
      if (offset + osize >= s->mark_offset)
	{
	  int rc;
	  size_t n;
	  size_t rdsize = s->mark_offset - offset;
	  rc = stream_readline (s->stream, optr, rdsize, offset, &n);
	  if (rc == 0)
	    {
	      if (nbytes)
		*nbytes = n;
	    }
	  return rc;
	}
    }
  else
    offset += s->mark_length;

  return stream_readline (s->stream, optr, osize, offset, nbytes);
}
  
static int
_mhdraft_size (stream_t stream, off_t *psize)
{
  struct _mhdraft_stream *s = stream_get_owner (stream);
  int rc = stream_size (s->stream, psize);
  
  if (rc == 0)
    *psize -= s->mark_length;
  return rc;
}
  
static int
_mhdraft_open (stream_t stream)
{
  struct _mhdraft_stream *s = stream_get_owner (stream);
  size_t offset, len;
  char buffer[256];
  int rc;

  offset = 0;
  while ((rc = stream_readline (s->stream, buffer, sizeof buffer,
				offset, &len)) == 0
	 && len > 0)
    {
      if (_mh_delim (buffer))
	{
	  s->mark_offset = offset;
	  s->mark_length = len - 1; /* do not count the terminating newline */
	  break;
	}

      offset += len;
    }
  return 0;
}

static int
_mhdraft_close (stream_t stream)
{
  struct _mhdraft_stream *s = stream_get_owner (stream);
  return stream_close (s->stream);
}

static void
_mhdraft_destroy (stream_t stream)
{
  struct _mhdraft_stream *s = stream_get_owner (stream);
  if (s->stream)
    stream_destroy (&s->stream, stream_get_owner (s->stream));
  free (s);
}
    
int
mhdraft_stream_create (stream_t *stream, stream_t src, int flags)
{
  struct _mhdraft_stream *s;
  int rc;

  if (!flags)
    flags = MU_STREAM_READ;
  if (flags != MU_STREAM_READ)
    return EINVAL;

  s = calloc (1, sizeof (*s));
  if (s == NULL)
    return ENOMEM;

  s->stream = src;
  
  rc = stream_create (stream, flags|MU_STREAM_NO_CHECK, s);
  if (rc)
    {
      free (s);
      return rc;
    }
  
  stream_set_open (*stream, _mhdraft_open, s);
  stream_set_close (*stream, _mhdraft_close, s);
  stream_set_destroy (*stream, _mhdraft_destroy, s);
  stream_set_readline (*stream, _mhdraft_readline, s);
  stream_set_read (*stream, _mhdraft_read, s);
  stream_set_size (*stream, _mhdraft_size, s);
  return 0;  
}


Return to:

Send suggestions and report system problems to the System administrator.