|
|
1.1 root 1: /* sendmail-like interface to /bin/mail for system V,
2: Copyright (C) 1985 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU Emacs General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU Emacs, but only under the conditions described in the
15: GNU Emacs General Public License. A copy of this license is
16: supposed to have been given to you along with GNU Emacs so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and 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)
26: /* This program isnot used in BSD, so just avoid loader complaints. */
27: main ()
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:
60: struct line_record
61: {
62: char *string;
63: struct line_record *continuation;
64: };
65: typedef struct line_record *line_list;
66:
67: struct header_record
68: {
69: line_list text;
70: struct header_record *next;
71: struct header_record *previous;
72: };
73: typedef struct header_record *header;
74:
75: struct stream_record
76: {
77: FILE *handle;
78: int (*action)();
79: struct stream_record *rest_streams;
80: };
81: typedef 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:
88: struct linebuffer
89: {
90: long size;
91: char *buffer;
92: };
93:
94: struct 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:
118: static char *my_name;
119: static char *the_date;
120: static char *the_user;
121: static line_list file_preface;
122: static stream_list the_streams;
123: static boolean no_problems = true;
124:
125: extern FILE *popen ();
126: extern int fclose (), pclose ();
127: extern char *malloc (), *realloc ();
128:
129: #ifdef CURRENT_USER
130: extern struct passwd *getpwuid ();
131: extern unsigned short geteuid ();
132: static 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:
142: static void
143: error (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:
154: static void
155: fatal (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:
164: static char *
165: xmalloc (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:
174: static char *
175: xrealloc (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:
187: void
188: init_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:
199: long
200: readline (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:
230: char *
231: get_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:
253: boolean
254: has_keyword (field)
255: char *field;
256: {
257: char *ignored;
258: return (get_keyword (field, &ignored) != ((char *) NULL));
259: }
260:
261: char *
262: add_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: *where++ = ((c == ',') ? ' ' : c);
272: if (the_list == NIL) break;
273: field = the_list->string;
274: the_list = the_list->continuation;
275: }
276: return where;
277: }
278:
279: line_list
280: make_file_preface ()
281: {
282: char *the_string, *temp;
283: long idiotic_interface;
284: long prefix_length;
285: long user_length;
286: long date_length;
287: line_list result;
288:
289: prefix_length = strlen (FROM_PREFIX);
290: time (&idiotic_interface);
291: the_date = ctime (&idiotic_interface);
292: /* the_date has an unwanted newline at the end */
293: date_length = strlen (the_date) - 1;
294: the_date[date_length] = '\0';
295: temp = cuserid ((char *) NULL);
296: user_length = strlen (temp);
297: the_user = alloc_string (user_length + 1);
298: strcpy (the_user, temp);
299: the_string = alloc_string (3 + prefix_length +
300: user_length +
301: date_length);
302: temp = the_string;
303: strcpy (temp, FROM_PREFIX);
304: temp = &temp[prefix_length];
305: *temp++ = ' ';
306: strcpy (temp, the_user);
307: temp = &temp[user_length];
308: *temp++ = ' ';
309: strcpy (temp, the_date);
310: result = new_list ();
311: result->string = the_string;
312: result->continuation = ((line_list) NULL);
313: return result;
314: }
315:
316: void
317: write_line_list (the_list, the_stream)
318: register line_list the_list;
319: FILE *the_stream;
320: {
321: for ( ;
322: the_list != ((line_list) NULL) ;
323: the_list = the_list->continuation)
324: {
325: fputs (the_list->string, the_stream);
326: putc ('\n', the_stream);
327: }
328: return;
329: }
330:
331: int
332: close_the_streams ()
333: {
334: register stream_list rem;
335: for (rem = the_streams;
336: rem != ((stream_list) NULL);
337: rem = rem->rest_streams)
338: no_problems = (no_problems &&
339: ((*rem->action) (rem->handle) == 0));
340: the_streams = ((stream_list) NULL);
341: return (no_problems ? 0 : 1);
342: }
343:
344: void
345: add_a_stream (the_stream, closing_action)
346: FILE *the_stream;
347: int (*closing_action)();
348: {
349: stream_list old = the_streams;
350: the_streams = new_stream ();
351: the_streams->handle = the_stream;
352: the_streams->action = closing_action;
353: the_streams->rest_streams = old;
354: return;
355: }
356:
357: int
358: my_fclose (the_file)
359: FILE *the_file;
360: {
361: putc ('\n', the_file);
362: fflush (the_file);
363: return fclose (the_file);
364: }
365:
366: boolean
367: open_a_file (name)
368: char *name;
369: {
370: FILE *the_stream = fopen (name, "a");
371: if (the_stream != ((FILE *) NULL))
372: {
373: add_a_stream (the_stream, my_fclose);
374: if (the_user == ((char *) NULL))
375: file_preface = make_file_preface ();
376: write_line_list (file_preface, the_stream);
377: return true;
378: }
379: return false;
380: }
381:
382: void
383: put_string (s)
384: char *s;
385: {
386: register stream_list rem;
387: for (rem = the_streams;
388: rem != ((stream_list) NULL);
389: rem = rem->rest_streams)
390: fputs (s, rem->handle);
391: return;
392: }
393:
394: void
395: put_line (s)
396: char *s;
397: {
398: register stream_list rem;
399: for (rem = the_streams;
400: rem != ((stream_list) NULL);
401: rem = rem->rest_streams)
402: {
403: fputs (s, rem->handle);
404: putc ('\n', rem->handle);
405: }
406: return;
407: }
408:
409: #define mail_error error
410:
411: void
412: setup_files (the_list, field)
413: register line_list the_list;
414: register char *field;
415: {
416: register char *start;
417: register char c;
418: while (true)
419: {
420: while (((c = *field) != '\0') &&
421: ((c == ' ') ||
422: (c == '\t') ||
423: (c == ',')))
424: field += 1;
425: if (c != '\0')
426: {
427: start = field;
428: while (((c = *field) != '\0') &&
429: (c != ' ') &&
430: (c != '\t') &&
431: (c != ','))
432: field += 1;
433: *field = '\0';
434: if (!open_a_file (start))
435: mail_error ("Could not open file %s", start);
436: *field = c;
437: if (c != '\0') continue;
438: }
439: if (the_list == ((line_list) NULL)) return;
440: field = the_list->string;
441: the_list = the_list->continuation;
442: }
443: }
444:
445: int
446: args_size (the_header)
447: header the_header;
448: {
449: register header old = the_header;
450: register line_list rem;
451: register int size = 0;
452: do
453: {
454: char *field;
455: register char *keyword = get_keyword (the_header->text->string, &field);
456: if ((strcmp (keyword, "TO") == 0) ||
457: (strcmp (keyword, "CC") == 0) ||
458: (strcmp (keyword, "BCC") == 0))
459: {
460: size += 1 + strlen (field);
461: for (rem = the_header->text->continuation;
462: rem != NIL;
463: rem = rem->continuation)
464: size += 1 + strlen (rem->string);
465: }
466: the_header = the_header->next;
467: } while (the_header != old);
468: return size;
469: }
470:
471: parse_header (the_header, where)
472: header the_header;
473: register char *where;
474: {
475: register header old = the_header;
476: do
477: {
478: char *field;
479: register char *keyword = get_keyword (the_header->text->string, &field);
480: if (strcmp (keyword, "TO") == 0)
481: where = add_field (the_header->text->continuation, field, where);
482: else if (strcmp (keyword, "CC") == 0)
483: where = add_field (the_header->text->continuation, field, where);
484: else if (strcmp (keyword, "BCC") == 0)
485: {
486: where = add_field (the_header->text->continuation, field, where);
487: the_header->previous->next = the_header->next;
488: the_header->next->previous = the_header->previous;
489: }
490: else if (strcmp (keyword, "FCC") == 0)
491: setup_files (the_header->text->continuation, field);
492: the_header = the_header->next;
493: } while (the_header != old);
494: *where = '\0';
495: return;
496: }
497:
498: header
499: read_header ()
500: {
501: register header the_header = ((header) NULL);
502: register line_list *next_line = ((line_list *) NULL);
503:
504: init_linebuffer (&lb);
505:
506: do
507: {
508: long length;
509: register char *line;
510:
511: readline (&lb, stdin);
512: line = lb.buffer;
513: length = strlen (line);
514: if (length == 0) break;
515:
516: if (has_keyword (line))
517: {
518: register header old = the_header;
519: the_header = new_header ();
520: if (old == ((header) NULL))
521: {
522: the_header->next = the_header;
523: the_header->previous = the_header;
524: }
525: else
526: {
527: the_header->previous = old;
528: the_header->next = old->next;
529: old->next = the_header;
530: }
531: next_line = &(the_header->text);
532: }
533:
534: if (next_line == ((line_list *) NULL))
535: {
536: /* Not a valid header */
537: exit (1);
538: }
539: *next_line = new_list ();
540: (*next_line)->string = alloc_string (length);
541: strcpy (((*next_line)->string), line);
542: next_line = &((*next_line)->continuation);
543: *next_line = NIL;
544:
545: } while (true);
546:
547: return the_header->next;
548: }
549:
550: void
551: write_header (the_header)
552: header the_header;
553: {
554: register header old = the_header;
555: do
556: {
557: register line_list the_list;
558: for (the_list = the_header->text;
559: the_list != NIL;
560: the_list = the_list->continuation)
561: put_line (the_list->string);
562: the_header = the_header->next;
563: } while (the_header != old);
564: put_line ("");
565: return;
566: }
567:
568: void
569: main (argc, argv)
570: int argc;
571: char **argv;
572: {
573: char *command_line;
574: header the_header;
575: long name_length = strlen (MAIL_PROGRAM_NAME);
576: char buf[BUFLEN + 1];
577: register int size;
578: FILE *the_pipe;
579:
580: my_name = MY_NAME;
581: the_streams = ((stream_list) NULL);
582: the_date = ((char *) NULL);
583: the_user = ((char *) NULL);
584:
585: the_header = read_header ();
586: command_line = alloc_string (name_length + args_size (the_header));
587: strcpy (command_line, MAIL_PROGRAM_NAME);
588: parse_header (the_header, &command_line[name_length]);
589:
590: the_pipe = popen (command_line, "w");
591: if (the_pipe == ((FILE *) NULL))
592: fatal ("cannot open pipe to real mailer");
593:
594: add_a_stream (the_pipe, pclose);
595:
596: write_header (the_header);
597:
598: /* Dump the message itself */
599:
600: while (!feof (stdin))
601: {
602: size = fread (buf, 1, BUFLEN, stdin);
603: buf[size] = '\0';
604: put_string (buf);
605: }
606:
607: exit (close_the_streams ());
608: }
609:
610: #endif /* not BSD 4.2 (or newer) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.