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 <string.h>
22 #include <errno.h>
23
24 #include <mailutils/types.h>
25 #include <mailutils/alloc.h>
26 #include <mailutils/errno.h>
27
28 #include <mailutils/nls.h>
29 #include <mailutils/stream.h>
30 #include <mailutils/sys/stream.h>
31 #include <mailutils/sys/iostream.h>
32
33 static int
_iostream_read(struct _mu_stream * str,char * buf,size_t bufsize,size_t * pnread)34 _iostream_read (struct _mu_stream *str, char *buf, size_t bufsize,
35 size_t *pnread)
36 {
37 struct _mu_iostream *sp = (struct _mu_iostream *)str;
38 int rc = mu_stream_read (sp->transport[_MU_STREAM_INPUT], buf, bufsize,
39 pnread);
40 if (rc)
41 sp->last_err_str = _MU_STREAM_INPUT;
42 return rc;
43 }
44
45 static int
_iostream_write(struct _mu_stream * str,const char * buf,size_t bufsize,size_t * pnwrite)46 _iostream_write (struct _mu_stream *str, const char *buf, size_t bufsize,
47 size_t *pnwrite)
48 {
49 struct _mu_iostream *sp = (struct _mu_iostream *)str;
50 int rc = mu_stream_write (sp->transport[_MU_STREAM_OUTPUT], buf, bufsize,
51 pnwrite);
52 if (rc)
53 sp->last_err_str = _MU_STREAM_OUTPUT;
54 return rc;
55 }
56
57 static int
_iostream_flush(struct _mu_stream * str)58 _iostream_flush (struct _mu_stream *str)
59 {
60 struct _mu_iostream *sp = (struct _mu_iostream *)str;
61 int rc = mu_stream_flush (sp->transport[_MU_STREAM_INPUT]);
62 if (rc)
63 {
64 sp->last_err_str = _MU_STREAM_INPUT;
65 return rc;
66 }
67 if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT])
68 {
69 rc = mu_stream_flush (sp->transport[_MU_STREAM_OUTPUT]);
70 if (rc)
71 sp->last_err_str = _MU_STREAM_OUTPUT;
72 }
73 return rc;
74 }
75
76 static int
_iostream_open(struct _mu_stream * str)77 _iostream_open (struct _mu_stream *str)
78 {
79 struct _mu_iostream *sp = (struct _mu_iostream *)str;
80 int rc;
81 rc = mu_stream_open (sp->transport[_MU_STREAM_INPUT]);
82 if (rc)
83 {
84 sp->last_err_str = _MU_STREAM_INPUT;
85 return rc;
86 }
87 if (sp->transport[_MU_STREAM_INPUT] != sp->transport[_MU_STREAM_OUTPUT])
88 {
89 rc = mu_stream_open (sp->transport[_MU_STREAM_OUTPUT]);
90 if (rc)
91 {
92 sp->last_err_str = _MU_STREAM_OUTPUT;
93 mu_stream_close (sp->transport[_MU_STREAM_INPUT]);
94 }
95 }
96 return rc;
97 }
98
99 static int
_iostream_close(struct _mu_stream * str)100 _iostream_close (struct _mu_stream *str)
101 {
102 struct _mu_iostream *sp = (struct _mu_iostream *)str;
103 mu_stream_close (sp->transport[_MU_STREAM_INPUT]);
104 mu_stream_close (sp->transport[_MU_STREAM_OUTPUT]);
105 return 0;
106 }
107
108 static void
_iostream_done(struct _mu_stream * str)109 _iostream_done (struct _mu_stream *str)
110 {
111 struct _mu_iostream *sp = (struct _mu_iostream *)str;
112 mu_stream_unref (sp->transport[_MU_STREAM_INPUT]);
113 mu_stream_unref (sp->transport[_MU_STREAM_OUTPUT]);
114 }
115
116 static int
_iostream_ctl(struct _mu_stream * str,int code,int opcode,void * arg)117 _iostream_ctl (struct _mu_stream *str, int code, int opcode, void *arg)
118 {
119 struct _mu_iostream *sp = (struct _mu_iostream *)str;
120
121 switch (code)
122 {
123 case MU_IOCTL_TRANSPORT:
124 if (!arg)
125 return EINVAL;
126 else
127 {
128 mu_transport_t *ptrans = arg;
129
130 switch (opcode)
131 {
132 case MU_IOCTL_OP_GET:
133 ptrans[0] = (mu_transport_t) sp->transport[_MU_STREAM_INPUT];
134 ptrans[1] = (mu_transport_t) sp->transport[_MU_STREAM_OUTPUT];
135 break;
136
137 case MU_IOCTL_OP_SET:
138 ptrans = arg;
139 sp->transport[_MU_STREAM_INPUT] = (mu_stream_t) ptrans[0];
140 sp->transport[_MU_STREAM_OUTPUT] = (mu_stream_t) ptrans[1];
141 break;
142
143 default:
144 return EINVAL;
145 }
146 }
147 break;
148
149 case MU_IOCTL_SUBSTREAM:
150 case MU_IOCTL_TOPSTREAM:
151 if (!arg)
152 return EINVAL;
153 else
154 {
155 mu_stream_t *pstr = arg;
156 switch (opcode)
157 {
158 case MU_IOCTL_OP_GET:
159 pstr[0] = sp->transport[0];
160 mu_stream_ref (pstr[0]);
161 pstr[1] = sp->transport[1];
162 mu_stream_ref (pstr[1]);
163 break;
164
165 case MU_IOCTL_OP_SET:
166 mu_stream_unref (sp->transport[0]);
167 sp->transport[0] = pstr[0];
168 mu_stream_ref (sp->transport[0]);
169
170 mu_stream_unref (sp->transport[1]);
171 sp->transport[1] = pstr[1];
172 mu_stream_ref (sp->transport[1]);
173 break;
174
175 default:
176 return EINVAL;
177 }
178 }
179 break;
180
181 case MU_IOCTL_TRANSPORT_BUFFER:
182 if (!arg)
183 return EINVAL;
184 else
185 {
186 struct mu_buffer_query *qp = arg;
187 if (!MU_TRANSPORT_VALID_TYPE (qp->type) || !sp->transport[qp->type])
188 return EINVAL;
189 return mu_stream_ioctl (sp->transport[qp->type], code, opcode, arg);
190 }
191
192 case MU_IOCTL_TCPSTREAM:
193 return mu_stream_ioctl (sp->transport[0], code, opcode, arg);
194
195 default:
196 return ENOSYS;
197 }
198 return 0;
199 }
200
201 static int
_iostream_wait(struct _mu_stream * str,int * pflags,struct timeval * tvp)202 _iostream_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp)
203 {
204 struct _mu_iostream *sp = (struct _mu_iostream *)str;
205 int rc = EINVAL;
206
207 if (*pflags == MU_STREAM_READY_RD)
208 {
209 rc = mu_stream_wait (sp->transport[_MU_STREAM_INPUT], pflags, tvp);
210 if (rc)
211 sp->last_err_str = _MU_STREAM_INPUT;
212 }
213 else if (*pflags == MU_STREAM_READY_WR)
214 {
215 rc = mu_stream_wait (sp->transport[_MU_STREAM_OUTPUT], pflags, tvp);
216 if (rc)
217 sp->last_err_str = _MU_STREAM_OUTPUT;
218 }
219 return rc;
220 }
221
222 static int
_iostream_shutdown(struct _mu_stream * str,int how)223 _iostream_shutdown (struct _mu_stream *str, int how)
224 {
225 struct _mu_iostream *sp = (struct _mu_iostream *)str;
226 int rc = EINVAL;
227 switch (how)
228 {
229 case MU_STREAM_READ:
230 rc = mu_stream_shutdown (sp->transport[_MU_STREAM_INPUT], how);
231 if (rc)
232 sp->last_err_str = _MU_STREAM_INPUT;
233 break;
234
235 case MU_STREAM_WRITE:
236 rc = mu_stream_shutdown (sp->transport[_MU_STREAM_OUTPUT], how);
237 if (rc)
238 sp->last_err_str = _MU_STREAM_OUTPUT;
239 }
240 return rc;
241 }
242
243 static const char *
_iostream_error_string(struct _mu_stream * str,int rc)244 _iostream_error_string (struct _mu_stream *str, int rc)
245 {
246 struct _mu_iostream *sp = (struct _mu_iostream *)str;
247 mu_stream_t transport = sp->transport[sp->last_err_str];
248 if (transport)
249 return mu_stream_strerror (transport, rc);
250 return mu_strerror (rc);
251 }
252
253 int
mu_iostream_create(mu_stream_t * pref,mu_stream_t in,mu_stream_t out)254 mu_iostream_create (mu_stream_t *pref, mu_stream_t in, mu_stream_t out)
255 {
256 struct _mu_iostream *sp;
257
258 sp = (struct _mu_iostream *)
259 _mu_stream_create (sizeof (*sp),
260 MU_STREAM_READ | MU_STREAM_WRITE);
261 if (!sp)
262 return ENOMEM;
263
264 sp->stream.flags |= _MU_STR_OPEN;
265 sp->stream.read = _iostream_read;
266 sp->stream.write = _iostream_write;
267 sp->stream.flush = _iostream_flush;
268 sp->stream.open = _iostream_open;
269 sp->stream.close = _iostream_close;
270 sp->stream.done = _iostream_done;
271 sp->stream.ctl = _iostream_ctl;
272 sp->stream.wait = _iostream_wait;
273 sp->stream.shutdown = _iostream_shutdown;
274 sp->stream.error_string = _iostream_error_string;
275
276 mu_stream_ref (in);
277 sp->transport[_MU_STREAM_INPUT] = in;
278 mu_stream_ref (out);
279 sp->transport[_MU_STREAM_OUTPUT] = out;
280
281 mu_stream_set_buffer ((mu_stream_t) sp, mu_buffer_line, 0);
282 *pref = (mu_stream_t) sp;
283 return 0;
284 }
285
286
287