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