aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src
diff options
context:
space:
mode:
Diffstat (limited to 'lib-src')
-rw-r--r--lib-src/fakemail.c627
1 files changed, 627 insertions, 0 deletions
diff --git a/lib-src/fakemail.c b/lib-src/fakemail.c
new file mode 100644
index 00000000000..d055c7f38e7
--- /dev/null
+++ b/lib-src/fakemail.c
@@ -0,0 +1,627 @@
1/* sendmail-like interface to /bin/mail for system V,
2 Copyright (C) 1985 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is distributed in the hope that it will be useful,
7but WITHOUT ANY WARRANTY. No author or distributor
8accepts responsibility to anyone for the consequences of using it
9or for whether it serves any particular purpose or works at all,
10unless he says so in writing. Refer to the GNU Emacs General Public
11License for full details.
12
13Everyone is granted permission to copy, modify and redistribute
14GNU Emacs, but only under the conditions described in the
15GNU Emacs General Public License. A copy of this license is
16supposed to have been given to you along with GNU Emacs so you
17can know your rights and responsibilities. It should be in a
18file named COPYING. Among other things, the copyright notice
19and this notice must be preserved on all copies. */
20
21
22#define NO_SHORTNAMES
23#include "../src/config.h"
24
25#if defined (BSD) && !defined (BSD4_1) && !defined (USE_FAKEMAIL)
26/* This program isnot used in BSD, so just avoid loader complaints. */
27main ()
28{
29}
30#else /* not BSD 4.2 (or newer) */
31/* This conditional contains all the rest of the file. */
32
33/* These are defined in config in some versions. */
34
35#ifdef static
36#undef static
37#endif
38
39#ifdef read
40#undef read
41#undef write
42#undef open
43#undef close
44#endif
45
46#include <stdio.h>
47#include <string.h>
48#include <ctype.h>
49#include <time.h>
50#include <pwd.h>
51
52/* Type definitions */
53
54#define boolean int
55#define true 1
56#define false 0
57
58/* Various lists */
59
60struct line_record
61{
62 char *string;
63 struct line_record *continuation;
64};
65typedef struct line_record *line_list;
66
67struct header_record
68{
69 line_list text;
70 struct header_record *next;
71 struct header_record *previous;
72};
73typedef struct header_record *header;
74
75struct stream_record
76{
77 FILE *handle;
78 int (*action)();
79 struct stream_record *rest_streams;
80};
81typedef struct stream_record *stream_list;
82
83/* A `struct linebuffer' is a structure which holds a line of text.
84 * `readline' reads a line from a stream into a linebuffer
85 * and works regardless of the length of the line.
86 */
87
88struct linebuffer
89{
90 long size;
91 char *buffer;
92};
93
94struct linebuffer lb;
95
96#define new_list() \
97 ((line_list) xmalloc (sizeof (struct line_record)))
98#define new_header() \
99 ((header) xmalloc (sizeof (struct header_record)))
100#define new_stream() \
101 ((stream_list) xmalloc (sizeof (struct stream_record)))
102#define alloc_string(nchars) \
103 ((char *) xmalloc ((nchars) + 1))
104
105/* Global declarations */
106
107#define BUFLEN 1024
108#define KEYWORD_SIZE 256
109#define FROM_PREFIX "From"
110#define MY_NAME "fakemail"
111#define NIL ((line_list) NULL)
112#define INITIAL_LINE_SIZE 200
113
114#ifndef MAIL_PROGRAM_NAME
115#define MAIL_PROGRAM_NAME "/bin/mail"
116#endif
117
118static char *my_name;
119static char *the_date;
120static char *the_user;
121static line_list file_preface;
122static stream_list the_streams;
123static boolean no_problems = true;
124
125extern FILE *popen ();
126extern int fclose (), pclose ();
127extern char *malloc (), *realloc ();
128
129#ifdef CURRENT_USER
130extern struct passwd *getpwuid ();
131extern unsigned short geteuid ();
132static struct passwd *my_entry;
133#define cuserid(s) \
134(my_entry = getpwuid (((int) geteuid ())), \
135 my_entry->pw_name)
136#endif
137
138/* Utilities */
139
140/* Print error message. `s1' is printf control string, `s2' is arg for it. */
141
142static void
143error (s1, s2)
144 char *s1, *s2;
145{
146 printf ("%s: ", my_name);
147 printf (s1, s2);
148 printf ("\n");
149 no_problems = false;
150}
151
152/* Print error message and exit. */
153
154static void
155fatal (s1, s2)
156 char *s1, *s2;
157{
158 error (s1, s2);
159 exit (1);
160}
161
162/* Like malloc but get fatal error if memory is exhausted. */
163
164static char *
165xmalloc (size)
166 int size;
167{
168 char *result = malloc (((unsigned) size));
169 if (result == ((char *) NULL))
170 fatal ("virtual memory exhausted", 0);
171 return result;
172}
173
174static char *
175xrealloc (ptr, size)
176 char *ptr;
177 int size;
178{
179 char *result = realloc (ptr, ((unsigned) size));
180 if (result == ((char *) NULL))
181 fatal ("virtual memory exhausted");
182 return result;
183}
184
185/* Initialize a linebuffer for use */
186
187void
188init_linebuffer (linebuffer)
189 struct linebuffer *linebuffer;
190{
191 linebuffer->size = INITIAL_LINE_SIZE;
192 linebuffer->buffer = ((char *) xmalloc (INITIAL_LINE_SIZE));
193}
194
195/* Read a line of text from `stream' into `linebuffer'.
196 * Return the length of the line.
197 */
198
199long
200readline (linebuffer, stream)
201 struct linebuffer *linebuffer;
202 FILE *stream;
203{
204 char *buffer = linebuffer->buffer;
205 char *p = linebuffer->buffer;
206 char *end = p + linebuffer->size;
207
208 while (true)
209 {
210 int c = getc (stream);
211 if (p == end)
212 {
213 linebuffer->size *= 2;
214 buffer = ((char *) xrealloc (buffer, linebuffer->size));
215 p += buffer - linebuffer->buffer;
216 end += buffer - linebuffer->buffer;
217 linebuffer->buffer = buffer;
218 }
219 if (c < 0 || c == '\n')
220 {
221 *p = 0;
222 break;
223 }
224 *p++ = c;
225 }
226
227 return p - buffer;
228}
229
230char *
231get_keyword (field, rest)
232 register char *field;
233 char **rest;
234{
235 static char keyword[KEYWORD_SIZE];
236 register char *ptr;
237 register char c;
238
239 ptr = &keyword[0];
240 c = *field++;
241 if ((isspace (c)) || (c == ':'))
242 return ((char *) NULL);
243 *ptr++ = ((islower (c)) ? (toupper (c)) : c);
244 while (((c = *field++) != ':') && (!(isspace (c))))
245 *ptr++ = ((islower (c)) ? (toupper (c)) : c);
246 *ptr++ = '\0';
247 while (isspace (c)) c = *field++;
248 if (c != ':') return ((char *) NULL);
249 *rest = field;
250 return &keyword[0];
251}
252
253boolean
254has_keyword (field)
255 char *field;
256{
257 char *ignored;
258 return (get_keyword (field, &ignored) != ((char *) NULL));
259}
260
261char *
262add_field (the_list, field, where)
263 line_list the_list;
264 register char *field, *where;
265{
266 register char c;
267 while (true)
268 {
269 *where++ = ' ';
270 while ((c = *field++) != '\0')
271 {
272 if (c == '(')
273 {
274 while (*field && *field != ')') ++field;
275 if (! (*field++)) break; /* no closer */
276 if (! (*field)) break; /* closerNULL */
277 c = *field;
278 }
279 *where++ = ((c == ','||c=='>'||c=='<') ? ' ' : c);
280 }
281 if (the_list == NIL) break;
282 field = the_list->string;
283 the_list = the_list->continuation;
284 }
285 return where;
286}
287
288line_list
289make_file_preface ()
290{
291 char *the_string, *temp;
292 long idiotic_interface;
293 long prefix_length;
294 long user_length;
295 long date_length;
296 line_list result;
297
298 prefix_length = strlen (FROM_PREFIX);
299 time (&idiotic_interface);
300 the_date = ctime (&idiotic_interface);
301 /* the_date has an unwanted newline at the end */
302 date_length = strlen (the_date) - 1;
303 the_date[date_length] = '\0';
304 temp = cuserid ((char *) NULL);
305 user_length = strlen (temp);
306 the_user = alloc_string (user_length + 1);
307 strcpy (the_user, temp);
308 the_string = alloc_string (3 + prefix_length +
309 user_length +
310 date_length);
311 temp = the_string;
312 strcpy (temp, FROM_PREFIX);
313 temp = &temp[prefix_length];
314 *temp++ = ' ';
315 strcpy (temp, the_user);
316 temp = &temp[user_length];
317 *temp++ = ' ';
318 strcpy (temp, the_date);
319 result = new_list ();
320 result->string = the_string;
321 result->continuation = ((line_list) NULL);
322 return result;
323}
324
325void
326write_line_list (the_list, the_stream)
327 register line_list the_list;
328 FILE *the_stream;
329{
330 for ( ;
331 the_list != ((line_list) NULL) ;
332 the_list = the_list->continuation)
333 {
334 fputs (the_list->string, the_stream);
335 putc ('\n', the_stream);
336 }
337 return;
338}
339
340int
341close_the_streams ()
342{
343 register stream_list rem;
344 for (rem = the_streams;
345 rem != ((stream_list) NULL);
346 rem = rem->rest_streams)
347 no_problems = (no_problems &&
348 ((*rem->action) (rem->handle) == 0));
349 the_streams = ((stream_list) NULL);
350 return (no_problems ? 0 : 1);
351}
352
353void
354add_a_stream (the_stream, closing_action)
355 FILE *the_stream;
356 int (*closing_action)();
357{
358 stream_list old = the_streams;
359 the_streams = new_stream ();
360 the_streams->handle = the_stream;
361 the_streams->action = closing_action;
362 the_streams->rest_streams = old;
363 return;
364}
365
366int
367my_fclose (the_file)
368 FILE *the_file;
369{
370 putc ('\n', the_file);
371 fflush (the_file);
372 return fclose (the_file);
373}
374
375boolean
376open_a_file (name)
377 char *name;
378{
379 FILE *the_stream = fopen (name, "a");
380 if (the_stream != ((FILE *) NULL))
381 {
382 add_a_stream (the_stream, my_fclose);
383 if (the_user == ((char *) NULL))
384 file_preface = make_file_preface ();
385 write_line_list (file_preface, the_stream);
386 return true;
387 }
388 return false;
389}
390
391void
392put_string (s)
393 char *s;
394{
395 register stream_list rem;
396 for (rem = the_streams;
397 rem != ((stream_list) NULL);
398 rem = rem->rest_streams)
399 fputs (s, rem->handle);
400 return;
401}
402
403void
404put_line (s)
405 char *s;
406{
407 register stream_list rem;
408 for (rem = the_streams;
409 rem != ((stream_list) NULL);
410 rem = rem->rest_streams)
411 {
412 fputs (s, rem->handle);
413 putc ('\n', rem->handle);
414 }
415 return;
416}
417
418#define mail_error error
419
420void
421setup_files (the_list, field)
422 register line_list the_list;
423 register char *field;
424{
425 register char *start;
426 register char c;
427 while (true)
428 {
429 while (((c = *field) != '\0') &&
430 ((c == ' ') ||
431 (c == '\t') ||
432 (c == ',')))
433 field += 1;
434 if (c != '\0')
435 {
436 start = field;
437 while (((c = *field) != '\0') &&
438 (c != ' ') &&
439 (c != '\t') &&
440 (c != ','))
441 field += 1;
442 *field = '\0';
443 if (!open_a_file (start))
444 mail_error ("Could not open file %s", start);
445 *field = c;
446 if (c != '\0') continue;
447 }
448 if (the_list == ((line_list) NULL)) return;
449 field = the_list->string;
450 the_list = the_list->continuation;
451 }
452}
453
454int
455args_size (the_header)
456 header the_header;
457{
458 register header old = the_header;
459 register line_list rem;
460 register int size = 0;
461 do
462 {
463 char *field;
464 register char *keyword = get_keyword (the_header->text->string, &field);
465 if ((strcmp (keyword, "TO") == 0) ||
466 (strcmp (keyword, "CC") == 0) ||
467 (strcmp (keyword, "BCC") == 0))
468 {
469 size += 1 + strlen (field);
470 for (rem = the_header->text->continuation;
471 rem != NIL;
472 rem = rem->continuation)
473 size += 1 + strlen (rem->string);
474 }
475 the_header = the_header->next;
476 } while (the_header != old);
477 return size;
478}
479
480parse_header (the_header, where)
481 header the_header;
482 register char *where;
483{
484 register header old = the_header;
485 do
486 {
487 char *field;
488 register char *keyword = get_keyword (the_header->text->string, &field);
489 if (strcmp (keyword, "TO") == 0)
490 where = add_field (the_header->text->continuation, field, where);
491 else if (strcmp (keyword, "CC") == 0)
492 where = add_field (the_header->text->continuation, field, where);
493 else if (strcmp (keyword, "BCC") == 0)
494 {
495 where = add_field (the_header->text->continuation, field, where);
496 the_header->previous->next = the_header->next;
497 the_header->next->previous = the_header->previous;
498 }
499 else if (strcmp (keyword, "FCC") == 0)
500 setup_files (the_header->text->continuation, field);
501 the_header = the_header->next;
502 } while (the_header != old);
503 *where = '\0';
504 return;
505}
506
507header
508read_header ()
509{
510 register header the_header = ((header) NULL);
511 register line_list *next_line = ((line_list *) NULL);
512
513 init_linebuffer (&lb);
514
515 do
516 {
517 long length;
518 register char *line;
519
520 readline (&lb, stdin);
521 line = lb.buffer;
522 length = strlen (line);
523 if (length == 0) break;
524
525 if (has_keyword (line))
526 {
527 register header old = the_header;
528 the_header = new_header ();
529 if (old == ((header) NULL))
530 {
531 the_header->next = the_header;
532 the_header->previous = the_header;
533 }
534 else
535 {
536 the_header->previous = old;
537 the_header->next = old->next;
538 old->next = the_header;
539 }
540 next_line = &(the_header->text);
541 }
542
543 if (next_line == ((line_list *) NULL))
544 {
545 /* Not a valid header */
546 exit (1);
547 }
548 *next_line = new_list ();
549 (*next_line)->string = alloc_string (length);
550 strcpy (((*next_line)->string), line);
551 next_line = &((*next_line)->continuation);
552 *next_line = NIL;
553
554 } while (true);
555
556 return the_header->next;
557}
558
559void
560write_header (the_header)
561 header the_header;
562{
563 register header old = the_header;
564 do
565 {
566 register line_list the_list;
567 for (the_list = the_header->text;
568 the_list != NIL;
569 the_list = the_list->continuation)
570 put_line (the_list->string);
571 the_header = the_header->next;
572 } while (the_header != old);
573 put_line ("");
574 return;
575}
576
577void
578main (argc, argv)
579 int argc;
580 char **argv;
581{
582 char *command_line;
583 header the_header;
584 long name_length;
585 char *mail_program_name;
586 char buf[BUFLEN + 1];
587 register int size;
588 FILE *the_pipe;
589
590 extern char *getenv ();
591
592 mail_program_name = getenv ("FAKEMAILER");
593 if (!(mail_program_name && *mail_program_name))
594 mail_program_name = MAIL_PROGRAM_NAME;
595 name_length = strlen (mail_program_name);
596
597 my_name = MY_NAME;
598 the_streams = ((stream_list) NULL);
599 the_date = ((char *) NULL);
600 the_user = ((char *) NULL);
601
602 the_header = read_header ();
603 command_line = alloc_string (name_length + args_size (the_header));
604 strcpy (command_line, mail_program_name);
605 parse_header (the_header, &command_line[name_length]);
606
607 the_pipe = popen (command_line, "w");
608 if (the_pipe == ((FILE *) NULL))
609 fatal ("cannot open pipe to real mailer");
610
611 add_a_stream (the_pipe, pclose);
612
613 write_header (the_header);
614
615 /* Dump the message itself */
616
617 while (!feof (stdin))
618 {
619 size = fread (buf, 1, BUFLEN, stdin);
620 buf[size] = '\0';
621 put_string (buf);
622 }
623
624 exit (close_the_streams ());
625}
626
627#endif /* not BSD 4.2 (or newer) */