Functions for escape variable handling.
Showing
1 changed file
with
494 additions
and
0 deletions
mail/var.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2001 Free Software Foundation, Inc. | ||
3 | |||
4 | This program 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 | This program 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 this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | /* Functions for handling escape variables */ | ||
19 | |||
20 | #include "mail.h" | ||
21 | #include <sys/stat.h> | ||
22 | |||
23 | static void | ||
24 | var_continue() | ||
25 | { | ||
26 | fprintf(stdout, "(continue)\n"); | ||
27 | } | ||
28 | |||
29 | /* ~![shell-command] */ | ||
30 | int | ||
31 | var_shell(int argc, char **argv, struct send_environ *env) | ||
32 | { | ||
33 | int status; | ||
34 | ofile = env->ofile; | ||
35 | status = mail_shell (argc, argv); | ||
36 | ofile = env->file; | ||
37 | return status; | ||
38 | } | ||
39 | |||
40 | /* ~:[mail-command] */ | ||
41 | /* ~-[mail-command] */ | ||
42 | int | ||
43 | var_command(int argc, char **argv, struct send_environ *env) | ||
44 | { | ||
45 | struct mail_command_entry entry; | ||
46 | int status; | ||
47 | |||
48 | if (argv[1][0] == '#') | ||
49 | return 0; | ||
50 | entry = util_find_entry (mail_command_table, argv[1]); | ||
51 | if (!entry.func) | ||
52 | { | ||
53 | util_error("Unknown command: %s", argv[1]); | ||
54 | return 1; | ||
55 | } | ||
56 | if (entry.flags & (EF_FLOW|EF_SEND)) | ||
57 | { | ||
58 | util_error("Command not allowed in an escape sequence\n"); | ||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | ofile = env->ofile; | ||
63 | status = (*entry.func)(argc-1, argv+1); | ||
64 | ofile = env->file; | ||
65 | return status; | ||
66 | } | ||
67 | |||
68 | /* ~? */ | ||
69 | int | ||
70 | var_help(int argc, char **argv, struct send_environ *env) | ||
71 | { | ||
72 | if (argc < 2) | ||
73 | return util_help (mail_escape_table, NULL); | ||
74 | else | ||
75 | { | ||
76 | int status = 0; | ||
77 | |||
78 | while (--argc) | ||
79 | status |= util_help (mail_escape_table, *++argv); | ||
80 | |||
81 | return status; | ||
82 | } | ||
83 | return 1; | ||
84 | } | ||
85 | |||
86 | /* ~A */ | ||
87 | /* ~a */ | ||
88 | int | ||
89 | var_sign(int argc, char **argv, struct send_environ *env) | ||
90 | { | ||
91 | struct mail_env_entry *p; | ||
92 | if (isupper(argv[0][0])) | ||
93 | p = util_find_env("Sign"); | ||
94 | else | ||
95 | p = util_find_env("sign"); | ||
96 | if (p->set) | ||
97 | fprintf (ofile, "%s", p->value); | ||
98 | else | ||
99 | util_error("\"sign\" not set"); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* ~b[bcc-list] */ | ||
104 | int | ||
105 | var_bcc(int argc, char **argv, struct send_environ *env) | ||
106 | { | ||
107 | while (--argc) | ||
108 | util_strcat(&env->bcc, *++argv); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* ~c[cc-list] */ | ||
113 | int | ||
114 | var_cc(int argc, char **argv, struct send_environ *env) | ||
115 | { | ||
116 | while (--argc) | ||
117 | util_strcat(&env->cc, *++argv); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* ~d */ | ||
122 | int | ||
123 | var_deadletter(int argc, char **argv, struct send_environ *env) | ||
124 | { | ||
125 | FILE *dead = fopen (getenv("DEAD"), "r"); | ||
126 | int c; | ||
127 | |||
128 | while ((c = fgetc(dead)) != EOF) | ||
129 | fputc (c, ofile); | ||
130 | fclose (dead); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int | ||
135 | var_run_editor(char *ed, int argc, char **argv, struct send_environ *env) | ||
136 | { | ||
137 | fclose (env->file); | ||
138 | ofile = env->ofile; | ||
139 | util_do_command ("!%s %s", ed, env->filename); | ||
140 | env->file = fopen (env->filename, "a+"); | ||
141 | ofile = env->file; | ||
142 | var_continue(); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* ~e */ | ||
147 | int | ||
148 | var_editor(int argc, char **argv, struct send_environ *env) | ||
149 | { | ||
150 | return var_run_editor(getenv("EDITOR"), argc, argv, env); | ||
151 | } | ||
152 | |||
153 | /* ~v */ | ||
154 | int | ||
155 | var_visual(int argc, char **argv, struct send_environ *env) | ||
156 | { | ||
157 | return var_run_editor(getenv("VISUAL"), argc, argv, env); | ||
158 | } | ||
159 | |||
160 | /* ~f[mesg-list] */ | ||
161 | /* ~F[mesg-list] */ | ||
162 | int | ||
163 | var_print(int argc, char **argv, struct send_environ *env) | ||
164 | { | ||
165 | return mail_print(argc, argv); | ||
166 | } | ||
167 | |||
168 | /* ~h */ | ||
169 | int | ||
170 | var_headers(int argc, char **argv, struct send_environ *env) | ||
171 | { | ||
172 | ml_reread("To:", &env->to); | ||
173 | ml_reread("Cc:", &env->cc); | ||
174 | ml_reread("Bcc:", &env->bcc); | ||
175 | ml_reread("Subject:", &env->subj); | ||
176 | var_continue(); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | /* ~i[var-name] */ | ||
181 | int | ||
182 | var_insert(int argc, char **argv, struct send_environ *env) | ||
183 | { | ||
184 | fprintf (ofile, "%s", util_find_env(argv[1])->value); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | /* ~m[mesg-list] */ | ||
189 | /* ~M[mesg-list] */ | ||
190 | int | ||
191 | var_quote(int argc, char **argv, struct send_environ *env) | ||
192 | { | ||
193 | if (argc > 1) | ||
194 | return util_msglist_command (var_quote, argc, argv, 0); | ||
195 | else | ||
196 | { | ||
197 | message_t mesg; | ||
198 | header_t hdr; | ||
199 | body_t body; | ||
200 | stream_t stream; | ||
201 | char buffer[512]; | ||
202 | off_t off = 0; | ||
203 | size_t n = 0; | ||
204 | char *prefix = util_find_env ("indentprefix")->value; | ||
205 | |||
206 | if (mailbox_get_message (mbox, cursor, &mesg) != 0) | ||
207 | return 1; | ||
208 | |||
209 | fprintf(stdout, "Interpolating: %d\n", cursor); | ||
210 | |||
211 | if (islower(argv[0][0])) | ||
212 | { | ||
213 | size_t i, num = 0; | ||
214 | char buffer[512]; | ||
215 | |||
216 | message_get_header (mesg, &hdr); | ||
217 | header_get_field_count (hdr, &num); | ||
218 | |||
219 | for (i = 1; i <= num; i++) | ||
220 | { | ||
221 | header_get_field_name (hdr, i, buffer, sizeof(buffer), NULL); | ||
222 | if (mail_header_is_visible (buffer)) | ||
223 | { | ||
224 | fprintf (ofile, "%s%s: ", prefix, buffer); | ||
225 | header_get_field_value (hdr, i, buffer, sizeof(buffer), | ||
226 | NULL); | ||
227 | fprintf (ofile, "%s\n", buffer); | ||
228 | } | ||
229 | } | ||
230 | fprintf (ofile, "\n"); | ||
231 | message_get_body (mesg, &body); | ||
232 | body_get_stream (body, &stream); | ||
233 | } | ||
234 | else | ||
235 | message_get_stream (mesg, &stream); | ||
236 | |||
237 | while (stream_readline(stream, buffer, sizeof(buffer) - 1, off, &n) == 0 | ||
238 | && n != 0) | ||
239 | { | ||
240 | buffer[n] = '\0'; | ||
241 | fprintf (ofile, "%s%s", prefix, buffer); | ||
242 | off += n; | ||
243 | } | ||
244 | var_continue(); | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* ~p */ | ||
250 | int | ||
251 | var_type_input(int argc, char **argv, struct send_environ *env) | ||
252 | { | ||
253 | char buf[512]; | ||
254 | |||
255 | fprintf(env->ofile, "Message contains:\n"); | ||
256 | |||
257 | if (env->to) | ||
258 | fprintf(env->ofile, "To: %s\n", env->to); | ||
259 | if (env->cc) | ||
260 | fprintf(env->ofile, "Cc: %s\n", env->cc); | ||
261 | if (env->bcc) | ||
262 | fprintf(env->ofile, "Bcc: %s\n", env->bcc); | ||
263 | if (env->subj) | ||
264 | fprintf(env->ofile, "Subject: %s\n\n", env->subj); | ||
265 | |||
266 | rewind(env->file); | ||
267 | while (fgets(buf, sizeof(buf), env->file)) | ||
268 | fputs(buf, env->ofile); | ||
269 | |||
270 | var_continue(); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /* ~r[filename] */ | ||
276 | int | ||
277 | var_read(int argc, char **argv, struct send_environ *env) | ||
278 | { | ||
279 | char *filename = util_fullpath(argv[1]); | ||
280 | FILE *inf = fopen(filename, "r"); | ||
281 | size_t size, lines; | ||
282 | char buf[512]; | ||
283 | |||
284 | if (!inf) | ||
285 | { | ||
286 | util_error("can't open %s: %s\n", filename, strerror(errno)); | ||
287 | free(filename); | ||
288 | return 1; | ||
289 | } | ||
290 | |||
291 | size = lines = 0; | ||
292 | while (fgets(buf, sizeof(buf), inf)) | ||
293 | { | ||
294 | lines++; | ||
295 | size += strlen(buf); | ||
296 | fputs(buf, ofile); | ||
297 | } | ||
298 | fclose(inf); | ||
299 | fprintf(stdout, "\"%s\" %d/%d\n", filename, lines, size); | ||
300 | free(filename); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* ~s[string] */ | ||
305 | int | ||
306 | var_subj(int argc, char **argv, struct send_environ *env) | ||
307 | { | ||
308 | free(env->subj); | ||
309 | env->subj = strdup(argv[1]); | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | /* ~t[name-list] */ | ||
314 | int | ||
315 | var_to(int argc, char **argv, struct send_environ *env) | ||
316 | { | ||
317 | while (--argc) | ||
318 | util_strcat(&env->to, *++argv); | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* ~w[filename] */ | ||
323 | int | ||
324 | var_write(int argc, char **argv, struct send_environ *env) | ||
325 | { | ||
326 | char *filename = util_fullpath(argv[1]); | ||
327 | FILE *fp = fopen(filename, "w"); /*FIXME: check for the existence first */ | ||
328 | size_t size, lines; | ||
329 | char buf[512]; | ||
330 | |||
331 | if (!fp) | ||
332 | { | ||
333 | util_error("can't open %s: %s\n", filename, strerror(errno)); | ||
334 | free(filename); | ||
335 | return 1; | ||
336 | } | ||
337 | |||
338 | rewind(env->file); | ||
339 | size = lines = 0; | ||
340 | while (fgets(buf, sizeof(buf), env->file)) | ||
341 | { | ||
342 | lines++; | ||
343 | size += strlen(buf); | ||
344 | fputs(buf, fp); | ||
345 | } | ||
346 | fclose(fp); | ||
347 | fprintf(stdout, "\"%s\" %d/%d\n", filename, lines, size); | ||
348 | free(filename); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* ~x */ | ||
353 | int | ||
354 | var_exit(int argc, char **argv, struct send_environ *env) | ||
355 | { | ||
356 | return util_do_command ("quit"); | ||
357 | } | ||
358 | |||
359 | /* ~|[shell-command] */ | ||
360 | int | ||
361 | var_pipe(int argc, char **argv, struct send_environ *env) | ||
362 | { | ||
363 | int p[2]; | ||
364 | pid_t pid; | ||
365 | int fd; | ||
366 | |||
367 | if (pipe(p)) | ||
368 | { | ||
369 | util_error("pipe: %s", strerror(errno)); | ||
370 | return 1; | ||
371 | } | ||
372 | |||
373 | fd = util_tempfile(NULL); | ||
374 | if (fd == -1) | ||
375 | return 1; | ||
376 | |||
377 | if ((pid = fork()) < 0) | ||
378 | { | ||
379 | close(p[0]); | ||
380 | close(p[1]); | ||
381 | close(fd); | ||
382 | util_error("fork: %s", strerror(errno)); | ||
383 | return 1; | ||
384 | } | ||
385 | else if (pid == 0) | ||
386 | { | ||
387 | /* Child */ | ||
388 | int i; | ||
389 | char **xargv; | ||
390 | |||
391 | /* Attache the pipes */ | ||
392 | close(0); | ||
393 | dup(p[0]); | ||
394 | close(p[0]); | ||
395 | close(p[1]); | ||
396 | |||
397 | close(1); | ||
398 | dup(fd); | ||
399 | close(fd); | ||
400 | |||
401 | /* Execute the process */ | ||
402 | xargv = calloc(argc, sizeof(xargv[0])); | ||
403 | if (!xargv) | ||
404 | { | ||
405 | util_error("not enough memory"); | ||
406 | exit(1); | ||
407 | } | ||
408 | for (i = 0; i < argc-1; i++) | ||
409 | xargv[i] = argv[i+1]; | ||
410 | xargv[i] = NULL; | ||
411 | execvp(xargv[0], xargv); | ||
412 | util_error("cannot exec process `%s': %s", xargv[0], strerror(errno)); | ||
413 | exit(1); | ||
414 | } | ||
415 | else | ||
416 | { | ||
417 | FILE *fp; | ||
418 | char *buf = NULL; | ||
419 | size_t n; | ||
420 | size_t lines, size; | ||
421 | int rc = 1; | ||
422 | int status; | ||
423 | |||
424 | close(p[0]); | ||
425 | |||
426 | /* Parent */ | ||
427 | fp = fdopen(p[1], "w"); | ||
428 | |||
429 | fclose(env->file); | ||
430 | env->file = fopen(env->filename, "r"); | ||
431 | |||
432 | lines = size = 0; | ||
433 | while (getline (&buf, &n, env->file) > 0) | ||
434 | { | ||
435 | lines++; | ||
436 | size += n; | ||
437 | fputs(buf, fp); | ||
438 | } | ||
439 | fclose(env->file); | ||
440 | fclose(fp); /* Closes p[1] */ | ||
441 | |||
442 | waitpid(pid, &status, 0); | ||
443 | if (!WIFEXITED(status)) | ||
444 | { | ||
445 | util_error("child terminated abnormally: %d", WEXITSTATUS(status)); | ||
446 | } | ||
447 | else | ||
448 | { | ||
449 | struct stat st; | ||
450 | if (fstat(fd, &st)) | ||
451 | { | ||
452 | util_error("can't stat output file: %s", strerror(errno)); | ||
453 | } | ||
454 | else if (st.st_size > 0) | ||
455 | rc = 0; | ||
456 | } | ||
457 | |||
458 | fprintf(stdout, "\"|%s\" out: %d/%d ", argv[1], lines, size); | ||
459 | if (rc) | ||
460 | { | ||
461 | fprintf(stdout, "no lines in\n"); | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | /* Ok, replace the old tempfile */ | ||
466 | fp = fdopen(fd, "r"); | ||
467 | rewind(fp); | ||
468 | |||
469 | env->file = fopen(env->filename, "w+"); | ||
470 | |||
471 | lines = size = 0; | ||
472 | while (getline (&buf, &n, fp) > 0) | ||
473 | { | ||
474 | lines++; | ||
475 | size += n; | ||
476 | fputs(buf, env->file); | ||
477 | } | ||
478 | fclose(env->file); | ||
479 | |||
480 | fprintf(stdout, "in: %d/%d\n", lines, size); | ||
481 | } | ||
482 | |||
483 | /* Clean up the things */ | ||
484 | if (buf) | ||
485 | free(buf); | ||
486 | |||
487 | env->file = fopen(env->filename, "a+"); | ||
488 | ofile = env->file; | ||
489 | } | ||
490 | |||
491 | close(fd); | ||
492 | |||
493 | return 0; | ||
494 | } |
-
Please register or sign in to post a comment