Commit bb12e617 bb12e6174bcff633960289781d58a34503e8cb2a by Sergey Poznyakoff

New program

1 parent 344611f5
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 GNU Mailutils 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 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 MA 02110-1301 USA */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <sys/stat.h>
23 #include <mailutils/mailutils.h>
24
25 char *file;
26 mu_header_t header;
27
28 char *ps[] = { "> ", ". " };
29 int interactive;
30
31 static void
32 prompt(int l)
33 {
34 if (interactive)
35 {
36 printf ("%s", ps[l]);
37 fflush (stdout);
38 }
39 }
40
41 static int
42 load_file (const char *name)
43 {
44 struct stat st;
45 size_t nread;
46 char *buf;
47 FILE *fp;
48 int status;
49
50 if (stat (name, &st))
51 {
52 mu_error ("cannot stat %s: %s", name, mu_strerror (errno));
53 return 1;
54 }
55
56 buf = malloc (st.st_size + 2);
57 if (!buf)
58 {
59 mu_error ("not enough memory");
60 return 1;
61 }
62
63 fp = fopen (name, "r");
64 if (!fp)
65 {
66 mu_error ("cannot open file %s: %s", name, mu_strerror (errno));
67 free (buf);
68 return 1;
69 }
70
71 nread = fread (buf, 1, st.st_size, fp);
72 fclose (fp);
73 if (nread != st.st_size)
74 {
75 mu_error ("short read on file %s", name);
76 free (buf);
77 return 1;
78 }
79
80 buf[st.st_size] = '\n';
81 buf[st.st_size+1] = 0;
82 status = mu_header_create (&header, buf, st.st_size + 1, NULL);
83 free (buf);
84 if (status)
85 {
86 mu_error ("cannot create header: %s", mu_strerror (status));
87 return 1;
88 }
89 return 0;
90 }
91
92 unsigned line_num = 0;
93
94 static int
95 check_args (char const *cmdname, int argc, int amin, int amax)
96 {
97 if (argc < amin)
98 {
99 mu_error ("%u: %s: too few arguments",
100 line_num, cmdname);
101 return 1;
102 }
103 if (amax > 0 && argc > amax)
104 {
105 mu_error ("%u: %s: too many arguments",
106 line_num, cmdname);
107 return 1;
108 }
109 return 0;
110 }
111
112 void
113 cmd_quit (int argc, char **argv)
114 {
115 exit (0);
116 }
117
118 void
119 cmd_load (int argc, char **argv)
120 {
121 if (check_args (argv[0], argc, 2, 2))
122 return;
123 mu_header_destroy (&header, NULL);
124 load_file (argv[1]);
125 }
126
127 void
128 cmd_free (int argc, char **argv)
129 {
130 if (check_args (argv[0], argc, 1, 1))
131 return;
132 mu_header_destroy (&header, NULL);
133 }
134
135 void
136 cmd_print (int argc, char **argv)
137 {
138 char *fn;
139 int num = 1;
140 int status;
141 const char *str;
142
143 if (check_args (argv[0], argc, 2, 3))
144 return;
145 fn = argv[1];
146 if (argc == 3)
147 num = atoi (argv[2]);
148
149 status = mu_header_sget_value_n (header, fn, num, &str);
150 if (status == 0)
151 printf ("%s: %s\n", fn, str);
152 else
153 mu_error ("%u: %s", line_num, mu_strerror (status));
154 }
155
156 void
157 cmd_dump (int argc, char **argv)
158 {
159 mu_off_t off = 0;
160 size_t n;
161 mu_stream_t stream;
162 char buf[512];
163 int status;
164
165 if (check_args (argv[0], argc, 1, 2))
166 return;
167
168 if (argc == 2)
169 off = strtoul (argv[1], NULL, 0);
170
171 status = mu_header_get_stream (header, &stream);
172 if (status)
173 {
174 mu_error ("%u: cannot get stream: %s", line_num, mu_strerror (status));
175 return;
176 }
177
178 status = mu_stream_seek (stream, off, SEEK_SET);
179 if (status)
180 {
181 mu_error ("%u: cannot seek: %s", line_num, mu_strerror (status));
182 return;
183 }
184
185 while (mu_stream_sequential_read (stream, buf, sizeof buf, &n) == 0
186 && n > 0)
187 {
188 fwrite (buf, 1, n, stdout);
189 }
190 }
191
192 void
193 cmd_remove (int argc, char **argv)
194 {
195 char *fn;
196 int num = 1;
197 int status;
198
199 if (check_args (argv[0], argc, 2, 3))
200 return;
201 fn = argv[1];
202 if (argc == 3)
203 num = atoi (argv[2]);
204 status = mu_header_remove (header, fn, num);
205 if (status)
206 mu_error ("%u: %s: %s", line_num, argv[0], mu_strerror (status));
207 }
208
209 /* insert header value [ref [num] [before|after] [replace]] */
210 void
211 cmd_insert (int argc, char **argv)
212 {
213 int status;
214 int flags = 0;
215 char *ref = NULL;
216 int num = 1;
217 int n;
218
219 if (check_args (argv[0], argc, 3, 7))
220 return;
221
222 if (argc >= 4)
223 {
224 ref = argv[3];
225 n = 4;
226 if (n < argc)
227 {
228 char *p;
229 int tmp;
230
231 tmp = strtoul(argv[4], &p, 0);
232 if (*p == 0)
233 {
234 num = tmp;
235 n++;
236 }
237
238 for (; n < argc; n++)
239 {
240 if (strcmp(argv[n], "before") == 0)
241 flags |= MU_HEADER_BEFORE;
242 else if (strcmp(argv[n], "after") == 0)
243 ;
244 else if (strcmp(argv[n], "replace") == 0)
245 flags |= MU_HEADER_REPLACE;
246 else
247 {
248 mu_error("%u: %s: unknown option", line_num, argv[4]);
249 return;
250 }
251 }
252 }
253 }
254 status = mu_header_insert (header, argv[1], argv[2],
255 ref, num, flags);
256 if (status)
257 mu_error ("%u: %s: %s", line_num, argv[0], mu_strerror (status));
258 }
259
260 void
261 cmd_write (int argc, char **argv)
262 {
263 char buf[512];
264 mu_stream_t str;
265 int status;
266
267 if (check_args (argv[0], argc, 1, 1))
268 return;
269
270 status = mu_header_get_stream (header, &str);
271 if (status)
272 {
273 mu_error ("%u: cannot get stream: %s", line_num, mu_strerror (status));
274 return;
275 }
276 mu_stream_seek (str, 0, SEEK_SET);
277 while (prompt (1), fgets(buf, sizeof buf, stdin))
278 {
279 mu_stream_sequential_write (str, buf, strlen (buf));
280 if (buf[0] == '\n')
281 break;
282 }
283 }
284
285 struct cmdtab
286 {
287 char *name;
288 void (*fun) (int argc, char **argv);
289 };
290
291 static struct cmdtab cmdtab[] = {
292 { "quit", cmd_quit },
293 { "load", cmd_load },
294 { "free", cmd_free },
295 { "print", cmd_print },
296 { "dump", cmd_dump },
297 { "remove", cmd_remove },
298 { "insert", cmd_insert },
299 { "write", cmd_write },
300 { NULL }
301 };
302
303 static struct cmdtab *
304 find_cmd (const char *name)
305 {
306 struct cmdtab *p;
307 for (p = cmdtab; p->name; p++)
308 if (strcmp (p->name, name) == 0)
309 return p;
310 return NULL;
311 }
312
313 int
314 main (int argc, char **argv)
315 {
316 int c;
317 char buf[512];
318
319 interactive = isatty (0);
320 while ((c = getopt (argc, argv, "f:h")) != EOF)
321 {
322 switch (c)
323 {
324 case 'f':
325 file = optarg;
326 break;
327
328 case 'h':
329 printf ("usage: header [-f file]\n");
330 exit (0);
331
332 default:
333 exit (1);
334 }
335 }
336
337 if (file)
338 {
339 if (load_file (file))
340 exit (1);
341 }
342
343 while (prompt(0), fgets(buf, sizeof buf, stdin))
344 {
345 int c;
346 char **v;
347 struct cmdtab *cmd;
348 int status;
349
350 line_num++;
351 status = mu_argcv_get (buf, NULL, "#", &c, &v);
352 if (status)
353 {
354 mu_error ("%u: cannot parse: %s",
355 line_num, mu_strerror (status));
356 continue;
357 }
358
359 cmd = find_cmd (v[0]);
360 if (!cmd)
361 {
362 mu_error ("%u: unknown command %s",
363 line_num, v[0]);
364 }
365 else
366 cmd->fun (c, v);
367
368 mu_argcv_free (c, v);
369
370 }
371 exit (0);
372 }
373