Commit 727d451f 727d451f2332707b06067e68aa7c4948297f9271 by Sergey Poznyakoff

Functions for escape variable handling.

1 parent 31c149ce
Showing 1 changed file with 494 additions and 0 deletions
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 }