1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <mailutils/types.h>
23 #include <mailutils/stream.h>
24 #include <mailutils/errno.h>
25 #include <mailutils/sys/streamref.h>
26
27 static int
_streamref_read(struct _mu_stream * str,char * buf,size_t bufsize,size_t * pnread)28 _streamref_read (struct _mu_stream *str, char *buf, size_t bufsize,
29 size_t *pnread)
30 {
31 struct _mu_streamref *sp = (struct _mu_streamref *)str;
32 int rc;
33 size_t nread;
34 mu_off_t off;
35
36 rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, &off);
37 if (rc == 0)
38 {
39 if (sp->end)
40 {
41 size_t size = sp->end - off + 1;
42 if (size < bufsize)
43 bufsize = size;
44 }
45 rc = mu_stream_read (sp->transport, buf, bufsize, &nread);
46 if (rc == 0)
47 {
48 sp->offset += nread;
49 *pnread = nread;
50 }
51 }
52 else if (rc == ESPIPE)
53 {
54 *pnread = 0;
55 mu_stream_clearerr (sp->transport);
56 return 0;
57 }
58 return rc;
59 }
60
61 static int
_streamref_write(struct _mu_stream * str,const char * buf,size_t bufsize,size_t * pnwrite)62 _streamref_write (struct _mu_stream *str, const char *buf, size_t bufsize,
63 size_t *pnwrite)
64 {
65 struct _mu_streamref *sp = (struct _mu_streamref *)str;
66 int rc;
67 size_t nwrite;
68 rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, NULL);
69 if (rc == 0)
70 {
71 rc = mu_stream_write (sp->transport, buf, bufsize, &nwrite);
72 if (rc == 0)
73 {
74 sp->offset += nwrite;
75 *pnwrite = nwrite;
76 }
77 }
78 return rc;
79 }
80
81 static int
_streamref_flush(struct _mu_stream * str)82 _streamref_flush (struct _mu_stream *str)
83 {
84 struct _mu_streamref *sp = (struct _mu_streamref *)str;
85 return mu_stream_flush (sp->transport);
86 }
87
88 static int
_streamref_open(struct _mu_stream * str)89 _streamref_open (struct _mu_stream *str)
90 {
91 struct _mu_streamref *sp = (struct _mu_streamref *)str;
92 return mu_stream_open (sp->transport);
93 }
94
95 static int
_streamref_close(struct _mu_stream * str)96 _streamref_close (struct _mu_stream *str)
97 {
98 struct _mu_streamref *sp = (struct _mu_streamref *)str;
99 return mu_stream_close (sp->transport);
100 }
101
102 static void
_streamref_done(struct _mu_stream * str)103 _streamref_done (struct _mu_stream *str)
104 {
105 struct _mu_streamref *sp = (struct _mu_streamref *)str;
106 mu_stream_unref (sp->transport);
107 }
108
109 static int
_streamref_seek(struct _mu_stream * str,mu_off_t off,mu_off_t * ppos)110 _streamref_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
111 {
112 struct _mu_streamref *sp = (struct _mu_streamref *)str;
113 mu_off_t size;
114 int rc;
115
116 if (sp->end)
117 size = sp->end - sp->start + 1;
118 else
119 {
120 rc = mu_stream_size (sp->transport, &size);
121 if (rc)
122 return rc;
123 size -= sp->start;
124 }
125
126 if (off < 0 || off > size)
127 return sp->stream.last_err = ESPIPE;
128 rc = mu_stream_seek (sp->transport, sp->start + off, MU_SEEK_SET,
129 &sp->offset);
130 if (rc)
131 return rc;
132 *ppos = sp->offset - sp->start;
133 return 0;
134 }
135
136 static int
_streamref_size(struct _mu_stream * str,mu_off_t * psize)137 _streamref_size (struct _mu_stream *str, mu_off_t *psize)
138 {
139 struct _mu_streamref *sp = (struct _mu_streamref *)str;
140 mu_off_t size;
141 int rc = 0;
142
143 if (sp->end)
144 size = sp->end - sp->start + 1;
145 else
146 {
147 rc = mu_stream_size (sp->transport, &size);
148 if (rc)
149 return rc;
150 size -= sp->start;
151 }
152 if (rc == 0)
153 *psize = size;
154 return rc;
155 }
156
157 static int
_streamref_ctl(struct _mu_stream * str,int code,int opcode,void * arg)158 _streamref_ctl (struct _mu_stream *str, int code, int opcode, void *arg)
159 {
160 struct _mu_streamref *sp = (struct _mu_streamref *)str;
161
162 switch (code)
163 {
164 case MU_IOCTL_SEEK_LIMITS:
165 if (!arg)
166 return EINVAL;
167 else
168 {
169 mu_off_t *lim = arg;
170
171 switch (opcode)
172 {
173 case MU_IOCTL_OP_GET:
174 lim[0] = sp->start;
175 lim[1] = sp->end;
176 return 0;
177
178 case MU_IOCTL_OP_SET:
179 sp->start = lim[0];
180 sp->end = lim[1];
181 return 0;
182
183 default:
184 return EINVAL;
185 }
186 }
187 }
188 return mu_stream_ioctl (sp->transport, code, opcode, arg);
189 }
190
191 static int
_streamref_wait(struct _mu_stream * str,int * pflags,struct timeval * tvp)192 _streamref_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
193 {
194 struct _mu_streamref *sp = (struct _mu_streamref *)str;
195 return mu_stream_wait (sp->transport, pflags, tvp);
196 }
197
198 static int
_streamref_truncate(struct _mu_stream * str,mu_off_t size)199 _streamref_truncate (struct _mu_stream *str, mu_off_t size)
200 {
201 struct _mu_streamref *sp = (struct _mu_streamref *)str;
202 return mu_stream_truncate (sp->transport, size);
203 }
204
205 static int
_streamref_shutdown(struct _mu_stream * str,int how)206 _streamref_shutdown (struct _mu_stream *str, int how)
207 {
208 struct _mu_streamref *sp = (struct _mu_streamref *)str;
209 return mu_stream_shutdown (sp->transport, how);
210 }
211
212 static const char *
_streamref_error_string(struct _mu_stream * str,int rc)213 _streamref_error_string (struct _mu_stream *str, int rc)
214 {
215 struct _mu_streamref *sp = (struct _mu_streamref *)str;
216 const char *p = mu_stream_strerror (sp->transport, rc);
217 if (!p)
218 p = mu_strerror (rc);
219 return p;
220 }
221
222 int
mu_streamref_create_abridged(mu_stream_t * pref,mu_stream_t str,mu_off_t start,mu_off_t end)223 mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str,
224 mu_off_t start, mu_off_t end)
225 {
226 int flags;
227 struct _mu_streamref *sp;
228
229 mu_stream_get_flags (str, &flags);
230 sp = (struct _mu_streamref *)
231 _mu_stream_create (sizeof (*sp), flags | _MU_STR_OPEN);
232 if (!sp)
233 return ENOMEM;
234
235 mu_stream_ref (str);
236
237 sp->stream.read = _streamref_read;
238 sp->stream.write = _streamref_write;
239 sp->stream.flush = _streamref_flush;
240 sp->stream.open = _streamref_open;
241 sp->stream.close = _streamref_close;
242 sp->stream.done = _streamref_done;
243 sp->stream.seek = _streamref_seek;
244 sp->stream.size = _streamref_size;
245 sp->stream.ctl = _streamref_ctl;
246 sp->stream.wait = _streamref_wait;
247 sp->stream.truncate = _streamref_truncate;
248 sp->stream.shutdown = _streamref_shutdown;
249 sp->stream.error_string = _streamref_error_string;
250
251 sp->transport = str;
252 sp->start = start;
253 sp->end = end;
254 sp->offset = start;
255 *pref = (mu_stream_t) sp;
256
257 mu_stream_set_buffer (*pref, mu_buffer_full, 0);
258
259 return 0;
260 }
261
262 int
mu_streamref_create(mu_stream_t * pref,mu_stream_t str)263 mu_streamref_create (mu_stream_t *pref, mu_stream_t str)
264 {
265 return mu_streamref_create_abridged (pref, str, 0, 0);
266 }
267
268