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 <string.h>
23 #include <mailutils/types.h>
24 #include <mailutils/stream.h>
25 #include <mailutils/errno.h>
26 #include <mailutils/sys/nullstream.h>
27 #include <mailutils/stream.h>
28 #include <mailutils/cctype.h>
29
30 static int
_nullstream_read(struct _mu_stream * str,char * buf,size_t bufsize,size_t * pnread)31 _nullstream_read (struct _mu_stream *str, char *buf, size_t bufsize,
32 size_t *pnread)
33 {
34 struct _mu_nullstream *np = (struct _mu_nullstream *)str;
35 size_t i;
36 mu_off_t off;
37
38 if (np->pattern == NULL)
39 {
40 *pnread = 0;
41 return 0;
42 }
43
44 off = np->base.offset + np->base.pos;
45 for (i = 0; i < bufsize; i++, off++)
46 {
47 if ((np->mode & MU_NULLSTREAM_SIZE) && off >= np->size)
48 break;
49 *buf++ = np->pattern[off % np->patsize];
50 }
51 *pnread = i;
52 return 0;
53 }
54
55 static int
_nullstream_write(struct _mu_stream * str,const char * buf,size_t bufsize,size_t * pnwrite)56 _nullstream_write (struct _mu_stream *str, const char *buf, size_t bufsize,
57 size_t *pnwrite)
58 {
59 *pnwrite = bufsize;
60 return 0;
61 }
62
63 static void
_nullstream_free_pattern(struct _mu_nullstream * np)64 _nullstream_free_pattern (struct _mu_nullstream *np)
65 {
66 if (!(np->mode & MU_NULLSTREAM_PATSTAT))
67 {
68 free (np->pattern);
69 np->mode &= ~MU_NULLSTREAM_PATSTAT;
70 }
71 np->pattern = NULL;
72 np->patsize = 0;
73 }
74
75 static void
_nullstream_done(struct _mu_stream * str)76 _nullstream_done (struct _mu_stream *str)
77 {
78 struct _mu_nullstream *np = (struct _mu_nullstream *)str;
79 _nullstream_free_pattern (np);
80 }
81
82 static int
_nullstream_seek(struct _mu_stream * str,mu_off_t off,mu_off_t * ppos)83 _nullstream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *ppos)
84 {
85 struct _mu_nullstream *np = (struct _mu_nullstream *)str;
86 if ((np->mode & MU_NULLSTREAM_SIZE) && off >= np->size)
87 return ESPIPE;
88 *ppos = off;
89 return 0;
90 }
91
92 static int
_nullstream_size(struct _mu_stream * str,mu_off_t * psize)93 _nullstream_size (struct _mu_stream *str, mu_off_t *psize)
94 {
95 struct _mu_nullstream *np = (struct _mu_nullstream *)str;
96 *psize = (np->mode & MU_NULLSTREAM_SIZE) ? np->size : 0;
97 return 0;
98 }
99
100 static int
_nullstream_truncate(struct _mu_stream * str,mu_off_t size)101 _nullstream_truncate (struct _mu_stream *str, mu_off_t size)
102 {
103 struct _mu_nullstream *np = (struct _mu_nullstream *)str;
104 np->base.size = _nullstream_size;
105 np->size = size;
106 np->mode |= MU_NULLSTREAM_SIZE;
107 return 0;
108 }
109
110 static int
_nullstream_ctl(struct _mu_stream * str,int code,int opcode,void * arg)111 _nullstream_ctl (struct _mu_stream *str, int code, int opcode, void *arg)
112 {
113 struct _mu_nullstream *np = (struct _mu_nullstream *)str;
114
115 if (code != MU_IOCTL_NULLSTREAM)
116 /* Only this code is supported */
117 return ENOSYS;
118 switch (opcode)
119 {
120 case MU_IOCTL_NULLSTREAM_SET_PATTERN:
121 if (!arg)
122 _nullstream_free_pattern (np);
123 else
124 {
125 struct mu_nullstream_pattern *pat = arg;
126 char *p;
127
128 p = malloc (pat->size);
129 if (!p)
130 return ENOMEM;
131 memcpy (p, pat->pattern, pat->size);
132 _nullstream_free_pattern (np);
133 np->pattern = p;
134 np->patsize = pat->size;
135 }
136 break;
137
138 case MU_IOCTL_NULLSTREAM_SET_PATCLASS:
139 if (!arg)
140 return EINVAL;
141 else
142 {
143 char buf[256];
144 int cnt = 0, i;
145 int class = *(int*)arg;
146 char *p;
147
148 for (i = 0; i < 256; i++)
149 {
150 if (mu_c_is_class (i, class))
151 buf[cnt++] = i;
152 }
153
154 p = malloc (cnt);
155 if (!p)
156 return ENOMEM;
157 memcpy (p, buf, cnt);
158 _nullstream_free_pattern (np);
159 np->pattern = p;
160 np->patsize = cnt;
161 }
162 break;
163
164 case MU_IOCTL_NULLSTREAM_SETSIZE:
165 if (!arg)
166 return EINVAL;
167 else
168 return _nullstream_truncate (str, *(mu_off_t*)arg);
169 break;
170
171 case MU_IOCTL_NULLSTREAM_CLRSIZE:
172 np->mode &= ~MU_NULLSTREAM_SIZE;
173 np->base.size = NULL;
174 break;
175
176 default:
177 return ENOSYS;
178 }
179 return 0;
180 }
181
182 int
mu_nullstream_create(mu_stream_t * pref,int flags)183 mu_nullstream_create (mu_stream_t *pref, int flags)
184 {
185 struct _mu_nullstream *np;
186
187 np = (struct _mu_nullstream *)
188 _mu_stream_create (sizeof (*np),
189 flags | MU_STREAM_SEEK | _MU_STR_OPEN);
190 if (!np)
191 return ENOMEM;
192 np->base.read = _nullstream_read;
193 np->base.write = _nullstream_write;
194 np->base.seek = _nullstream_seek;
195 np->base.ctl = _nullstream_ctl;
196 np->base.truncate = _nullstream_truncate;
197 np->base.done = _nullstream_done;
198
199 np->pattern = "\0";
200 np->patsize = 1;
201 np->mode = MU_NULLSTREAM_PATSTAT;
202
203 *pref = (mu_stream_t) np;
204
205 mu_stream_set_buffer (*pref, mu_buffer_full, 0);
206 return 0;
207 }
208