Mercurial > emacs
annotate lib-src/fakemail.c @ 55434:f88632e54afb
2004-05-08 John Wiegley <johnw@newartisans.com>
* iswitchb.el (iswitchb-use-virtual-buffers): Added support for
"virtual buffers" (off by default), which makes it possible to
switch to the buffers of recently files. When a buffer name
search fails, and this option is on, iswitchb will look at the
list of recently visited files, and permit matching against those
names. When the user hits RET on a match, it will revisit that
file.
(iswitchb-read-buffer): Added two optional arguments, which makes
isearchb.el possible.
(iswitchb-completions, iswitchb-set-matches, iswitchb-prev-match,
iswitchb-next-match): Added support for virtual buffers.
author | John Wiegley <johnw@newartisans.com> |
---|---|
date | Sat, 08 May 2004 13:00:52 +0000 |
parents | 695cf19ef79e |
children | a47704955f8d 375f2633d815 |
rev | line source |
---|---|
18 | 1 /* sendmail-like interface to /bin/mail for system V, |
26083
134b57acef68
Add support for large files. Merge glibc 2.1.2.
Paul Eggert <eggert@twinsun.com>
parents:
25449
diff
changeset
|
2 Copyright (C) 1985, 1994, 1999 Free Software Foundation, Inc. |
18 | 3 |
4 This file is part of GNU Emacs. | |
5 | |
37 | 6 GNU Emacs is free software; you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | |
6109 | 8 the Free Software Foundation; either version 2, or (at your option) |
37 | 9 any later version. |
18 | 10 |
37 | 11 GNU Emacs is distributed in the hope that it will be useful, |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
14186
ee40177f6c68
Update FSF's address in the preamble.
Erik Naggum <erik@naggum.no>
parents:
12840
diff
changeset
|
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
ee40177f6c68
Update FSF's address in the preamble.
Erik Naggum <erik@naggum.no>
parents:
12840
diff
changeset
|
19 Boston, MA 02111-1307, USA. */ |
18 | 20 |
21 #define NO_SHORTNAMES | |
42134
de525d9743c9
Include "config.h", not <../src/config.h>.
Dave Love <fx@gnu.org>
parents:
34951
diff
changeset
|
22 #define _XOPEN_SOURCE 500 /* for cuserid */ |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
23 |
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
24 #ifdef HAVE_CONFIG_H |
42469 | 25 #include <config.h> |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
26 #endif |
18 | 27 |
16218
32f82ca8b41f
Replaced all BSD with BSD_SYSTEM.
Karl Heuer <kwzh@gnu.org>
parents:
16121
diff
changeset
|
28 #if defined (BSD_SYSTEM) && !defined (BSD4_1) && !defined (USE_FAKEMAIL) |
18 | 29 /* This program isnot used in BSD, so just avoid loader complaints. */ |
15683 | 30 int |
18 | 31 main () |
32 { | |
16121 | 33 return 0; |
18 | 34 } |
35 #else /* not BSD 4.2 (or newer) */ | |
5447
6f0905b05218
(main) [MSDOS]: Dummy stub just to make the file compile.
Richard M. Stallman <rms@gnu.org>
parents:
4696
diff
changeset
|
36 #ifdef MSDOS |
15683 | 37 int |
5447
6f0905b05218
(main) [MSDOS]: Dummy stub just to make the file compile.
Richard M. Stallman <rms@gnu.org>
parents:
4696
diff
changeset
|
38 main () |
6f0905b05218
(main) [MSDOS]: Dummy stub just to make the file compile.
Richard M. Stallman <rms@gnu.org>
parents:
4696
diff
changeset
|
39 { |
16121 | 40 return 0; |
5447
6f0905b05218
(main) [MSDOS]: Dummy stub just to make the file compile.
Richard M. Stallman <rms@gnu.org>
parents:
4696
diff
changeset
|
41 } |
6f0905b05218
(main) [MSDOS]: Dummy stub just to make the file compile.
Richard M. Stallman <rms@gnu.org>
parents:
4696
diff
changeset
|
42 #else /* not MSDOS */ |
18 | 43 /* This conditional contains all the rest of the file. */ |
44 | |
45 /* These are defined in config in some versions. */ | |
46 | |
47 #ifdef static | |
48 #undef static | |
49 #endif | |
50 | |
15099
857388330750
[WINDOWSNT]: Include ntlib.h.
Richard M. Stallman <rms@gnu.org>
parents:
14186
diff
changeset
|
51 #ifdef WINDOWSNT |
857388330750
[WINDOWSNT]: Include ntlib.h.
Richard M. Stallman <rms@gnu.org>
parents:
14186
diff
changeset
|
52 #include "ntlib.h" |
857388330750
[WINDOWSNT]: Include ntlib.h.
Richard M. Stallman <rms@gnu.org>
parents:
14186
diff
changeset
|
53 #endif |
857388330750
[WINDOWSNT]: Include ntlib.h.
Richard M. Stallman <rms@gnu.org>
parents:
14186
diff
changeset
|
54 |
18 | 55 #include <stdio.h> |
56 #include <string.h> | |
57 #include <ctype.h> | |
58 #include <time.h> | |
59 #include <pwd.h> | |
18841
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
60 |
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
61 /* This is to declare cuserid. */ |
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
62 #ifdef HAVE_UNISTD_H |
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
63 #include <unistd.h> |
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
64 #endif |
18 | 65 |
66 /* Type definitions */ | |
67 | |
68 #define boolean int | |
69 #define true 1 | |
70 #define false 0 | |
71 | |
72 /* Various lists */ | |
73 | |
74 struct line_record | |
75 { | |
76 char *string; | |
77 struct line_record *continuation; | |
78 }; | |
79 typedef struct line_record *line_list; | |
80 | |
81 struct header_record | |
82 { | |
83 line_list text; | |
84 struct header_record *next; | |
85 struct header_record *previous; | |
86 }; | |
87 typedef struct header_record *header; | |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
88 |
18 | 89 struct stream_record |
90 { | |
91 FILE *handle; | |
92 int (*action)(); | |
93 struct stream_record *rest_streams; | |
94 }; | |
95 typedef struct stream_record *stream_list; | |
96 | |
97 /* A `struct linebuffer' is a structure which holds a line of text. | |
98 * `readline' reads a line from a stream into a linebuffer | |
99 * and works regardless of the length of the line. | |
100 */ | |
101 | |
102 struct linebuffer | |
103 { | |
104 long size; | |
105 char *buffer; | |
106 }; | |
107 | |
108 struct linebuffer lb; | |
109 | |
110 #define new_list() \ | |
111 ((line_list) xmalloc (sizeof (struct line_record))) | |
112 #define new_header() \ | |
113 ((header) xmalloc (sizeof (struct header_record))) | |
114 #define new_stream() \ | |
115 ((stream_list) xmalloc (sizeof (struct stream_record))) | |
116 #define alloc_string(nchars) \ | |
117 ((char *) xmalloc ((nchars) + 1)) | |
118 | |
119 /* Global declarations */ | |
120 | |
121 #define BUFLEN 1024 | |
122 #define KEYWORD_SIZE 256 | |
123 #define FROM_PREFIX "From" | |
124 #define MY_NAME "fakemail" | |
125 #define NIL ((line_list) NULL) | |
126 #define INITIAL_LINE_SIZE 200 | |
127 | |
128 #ifndef MAIL_PROGRAM_NAME | |
129 #define MAIL_PROGRAM_NAME "/bin/mail" | |
130 #endif | |
131 | |
132 static char *my_name; | |
133 static char *the_date; | |
134 static char *the_user; | |
135 static line_list file_preface; | |
136 static stream_list the_streams; | |
137 static boolean no_problems = true; | |
138 | |
139 extern FILE *popen (); | |
140 extern int fclose (), pclose (); | |
141 | |
142 #ifdef CURRENT_USER | |
143 extern struct passwd *getpwuid (); | |
144 extern unsigned short geteuid (); | |
145 static struct passwd *my_entry; | |
146 #define cuserid(s) \ | |
147 (my_entry = getpwuid (((int) geteuid ())), \ | |
148 my_entry->pw_name) | |
149 #endif | |
150 | |
151 /* Utilities */ | |
152 | |
153 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | |
154 | |
155 static void | |
156 error (s1, s2) | |
157 char *s1, *s2; | |
158 { | |
159 printf ("%s: ", my_name); | |
160 printf (s1, s2); | |
161 printf ("\n"); | |
162 no_problems = false; | |
163 } | |
164 | |
165 /* Print error message and exit. */ | |
166 | |
167 static void | |
168 fatal (s1, s2) | |
169 char *s1, *s2; | |
170 { | |
171 error (s1, s2); | |
172 exit (1); | |
173 } | |
174 | |
175 /* Like malloc but get fatal error if memory is exhausted. */ | |
176 | |
12833
25464bf61eb1
(xmalloc, xrealloc): Use return-type long *.
Richard M. Stallman <rms@gnu.org>
parents:
10265
diff
changeset
|
177 static long * |
18 | 178 xmalloc (size) |
179 int size; | |
180 { | |
12833
25464bf61eb1
(xmalloc, xrealloc): Use return-type long *.
Richard M. Stallman <rms@gnu.org>
parents:
10265
diff
changeset
|
181 long *result = (long *) malloc (((unsigned) size)); |
25464bf61eb1
(xmalloc, xrealloc): Use return-type long *.
Richard M. Stallman <rms@gnu.org>
parents:
10265
diff
changeset
|
182 if (result == ((long *) NULL)) |
18 | 183 fatal ("virtual memory exhausted", 0); |
184 return result; | |
185 } | |
186 | |
12833
25464bf61eb1
(xmalloc, xrealloc): Use return-type long *.
Richard M. Stallman <rms@gnu.org>
parents:
10265
diff
changeset
|
187 static long * |
18 | 188 xrealloc (ptr, size) |
12833
25464bf61eb1
(xmalloc, xrealloc): Use return-type long *.
Richard M. Stallman <rms@gnu.org>
parents:
10265
diff
changeset
|
189 long *ptr; |
18 | 190 int size; |
191 { | |
12833
25464bf61eb1
(xmalloc, xrealloc): Use return-type long *.
Richard M. Stallman <rms@gnu.org>
parents:
10265
diff
changeset
|
192 long *result = (long *) realloc (ptr, ((unsigned) size)); |
12840
4e9a14304b8b
(xrealloc): Change cast to match return type.
Karl Heuer <kwzh@gnu.org>
parents:
12833
diff
changeset
|
193 if (result == ((long *) NULL)) |
18 | 194 fatal ("virtual memory exhausted"); |
195 return result; | |
196 } | |
197 | |
198 /* Initialize a linebuffer for use */ | |
199 | |
200 void | |
201 init_linebuffer (linebuffer) | |
202 struct linebuffer *linebuffer; | |
203 { | |
204 linebuffer->size = INITIAL_LINE_SIZE; | |
205 linebuffer->buffer = ((char *) xmalloc (INITIAL_LINE_SIZE)); | |
206 } | |
207 | |
208 /* Read a line of text from `stream' into `linebuffer'. | |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
209 Return the length of the line. */ |
18 | 210 |
211 long | |
212 readline (linebuffer, stream) | |
213 struct linebuffer *linebuffer; | |
214 FILE *stream; | |
215 { | |
216 char *buffer = linebuffer->buffer; | |
217 char *p = linebuffer->buffer; | |
218 char *end = p + linebuffer->size; | |
219 | |
220 while (true) | |
221 { | |
222 int c = getc (stream); | |
223 if (p == end) | |
224 { | |
225 linebuffer->size *= 2; | |
34951
1efc40541908
(readline): Cast buffer to "long *" to pacify
Eli Zaretskii <eliz@gnu.org>
parents:
34609
diff
changeset
|
226 buffer = ((char *) xrealloc ((long *)buffer, linebuffer->size)); |
6992
ed57331fb222
(readline): Fix updating of p when buffer grows.
Richard M. Stallman <rms@gnu.org>
parents:
6954
diff
changeset
|
227 p = buffer + (p - linebuffer->buffer); |
6954
774fdc20d115
(readline): When extending the buffer,
Richard M. Stallman <rms@gnu.org>
parents:
6109
diff
changeset
|
228 end = buffer + linebuffer->size; |
18 | 229 linebuffer->buffer = buffer; |
230 } | |
231 if (c < 0 || c == '\n') | |
232 { | |
233 *p = 0; | |
234 break; | |
235 } | |
236 *p++ = c; | |
237 } | |
238 | |
239 return p - buffer; | |
240 } | |
241 | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
242 /* Extract a colon-terminated keyword from the string FIELD. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
243 Return that keyword as a string stored in a static buffer. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
244 Store the address of the rest of the string into *REST. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
245 |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
246 If there is no keyword, return NULL and don't alter *REST. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
247 |
18 | 248 char * |
249 get_keyword (field, rest) | |
250 register char *field; | |
251 char **rest; | |
252 { | |
253 static char keyword[KEYWORD_SIZE]; | |
254 register char *ptr; | |
34609
cb2667416fa5
(get_keyword): Make sure that isspace and
Gerd Moellmann <gerd@gnu.org>
parents:
26083
diff
changeset
|
255 register int c; |
18 | 256 |
257 ptr = &keyword[0]; | |
34609
cb2667416fa5
(get_keyword): Make sure that isspace and
Gerd Moellmann <gerd@gnu.org>
parents:
26083
diff
changeset
|
258 c = (unsigned char) *field++; |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
259 if (isspace (c) || c == ':') |
18 | 260 return ((char *) NULL); |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
261 *ptr++ = (islower (c) ? toupper (c) : c); |
34609
cb2667416fa5
(get_keyword): Make sure that isspace and
Gerd Moellmann <gerd@gnu.org>
parents:
26083
diff
changeset
|
262 while (((c = (unsigned char) *field++) != ':') && ! isspace (c)) |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
263 *ptr++ = (islower (c) ? toupper (c) : c); |
18 | 264 *ptr++ = '\0'; |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
265 while (isspace (c)) |
34609
cb2667416fa5
(get_keyword): Make sure that isspace and
Gerd Moellmann <gerd@gnu.org>
parents:
26083
diff
changeset
|
266 c = (unsigned char) *field++; |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
267 if (c != ':') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
268 return ((char *) NULL); |
18 | 269 *rest = field; |
270 return &keyword[0]; | |
271 } | |
272 | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
273 /* Nonzero if the string FIELD starts with a colon-terminated keyword. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
274 |
18 | 275 boolean |
276 has_keyword (field) | |
277 char *field; | |
278 { | |
279 char *ignored; | |
280 return (get_keyword (field, &ignored) != ((char *) NULL)); | |
281 } | |
282 | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
283 /* Store the string FIELD, followed by any lines in THE_LIST, |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
284 into the buffer WHERE. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
285 Concatenate lines, putting just a space between them. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
286 Delete everything contained in parentheses. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
287 When a recipient name contains <...>, we discard |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
288 everything except what is inside the <...>. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
289 |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
290 We don't pay attention to overflowing WHERE; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
291 the caller has to make it big enough. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
292 |
18 | 293 char * |
294 add_field (the_list, field, where) | |
295 line_list the_list; | |
296 register char *field, *where; | |
297 { | |
298 register char c; | |
299 while (true) | |
300 { | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
301 char *this_recipient_where; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
302 int in_quotes = 0; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
303 |
18 | 304 *where++ = ' '; |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
305 this_recipient_where = where; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
306 |
18 | 307 while ((c = *field++) != '\0') |
308 { | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
309 if (c == '\\') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
310 *where++ = c; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
311 else if (c == '"') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
312 { |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
313 in_quotes = ! in_quotes; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
314 *where++ = c; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
315 } |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
316 else if (in_quotes) |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
317 *where++ = c; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
318 else if (c == '(') |
18 | 319 { |
320 while (*field && *field != ')') ++field; | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
321 if (! (*field++)) break; /* no close */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
322 continue; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
323 } |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
324 else if (c == ',') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
325 { |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
326 *where++ = ' '; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
327 /* When we get to the end of one recipient, |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
328 don't discard it if the next one has <...>. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
329 this_recipient_where = where; |
18 | 330 } |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
331 else if (c == '<') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
332 /* Discard everything we got before the `<'. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
333 where = this_recipient_where; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
334 else if (c == '>') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
335 /* Discard the rest of this name that follows the `>'. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
336 { |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
337 while (*field && *field != ',') ++field; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
338 if (! (*field++)) break; /* no comma */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
339 continue; |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
340 } |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
341 else |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
342 *where++ = c; |
18 | 343 } |
344 if (the_list == NIL) break; | |
345 field = the_list->string; | |
346 the_list = the_list->continuation; | |
347 } | |
348 return where; | |
349 } | |
350 | |
351 line_list | |
352 make_file_preface () | |
353 { | |
354 char *the_string, *temp; | |
355 long idiotic_interface; | |
356 long prefix_length; | |
357 long user_length; | |
358 long date_length; | |
359 line_list result; | |
360 | |
361 prefix_length = strlen (FROM_PREFIX); | |
362 time (&idiotic_interface); | |
363 the_date = ctime (&idiotic_interface); | |
364 /* the_date has an unwanted newline at the end */ | |
365 date_length = strlen (the_date) - 1; | |
366 the_date[date_length] = '\0'; | |
367 temp = cuserid ((char *) NULL); | |
368 user_length = strlen (temp); | |
369 the_user = alloc_string (user_length + 1); | |
370 strcpy (the_user, temp); | |
18841
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
371 the_string = alloc_string (3 + prefix_length |
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
372 + user_length |
36704f455f32
[HAVE_UNISTD_H]: Include unistd.h.
Richard M. Stallman <rms@gnu.org>
parents:
16218
diff
changeset
|
373 + date_length); |
18 | 374 temp = the_string; |
375 strcpy (temp, FROM_PREFIX); | |
376 temp = &temp[prefix_length]; | |
377 *temp++ = ' '; | |
378 strcpy (temp, the_user); | |
379 temp = &temp[user_length]; | |
380 *temp++ = ' '; | |
381 strcpy (temp, the_date); | |
382 result = new_list (); | |
383 result->string = the_string; | |
384 result->continuation = ((line_list) NULL); | |
385 return result; | |
386 } | |
387 | |
388 void | |
389 write_line_list (the_list, the_stream) | |
390 register line_list the_list; | |
391 FILE *the_stream; | |
392 { | |
393 for ( ; | |
394 the_list != ((line_list) NULL) ; | |
395 the_list = the_list->continuation) | |
396 { | |
397 fputs (the_list->string, the_stream); | |
398 putc ('\n', the_stream); | |
399 } | |
400 return; | |
401 } | |
402 | |
403 int | |
404 close_the_streams () | |
405 { | |
406 register stream_list rem; | |
407 for (rem = the_streams; | |
408 rem != ((stream_list) NULL); | |
409 rem = rem->rest_streams) | |
410 no_problems = (no_problems && | |
411 ((*rem->action) (rem->handle) == 0)); | |
412 the_streams = ((stream_list) NULL); | |
413 return (no_problems ? 0 : 1); | |
414 } | |
415 | |
416 void | |
417 add_a_stream (the_stream, closing_action) | |
418 FILE *the_stream; | |
419 int (*closing_action)(); | |
420 { | |
421 stream_list old = the_streams; | |
422 the_streams = new_stream (); | |
423 the_streams->handle = the_stream; | |
424 the_streams->action = closing_action; | |
425 the_streams->rest_streams = old; | |
426 return; | |
427 } | |
428 | |
429 int | |
430 my_fclose (the_file) | |
431 FILE *the_file; | |
432 { | |
433 putc ('\n', the_file); | |
434 fflush (the_file); | |
435 return fclose (the_file); | |
436 } | |
437 | |
438 boolean | |
439 open_a_file (name) | |
440 char *name; | |
441 { | |
442 FILE *the_stream = fopen (name, "a"); | |
443 if (the_stream != ((FILE *) NULL)) | |
444 { | |
445 add_a_stream (the_stream, my_fclose); | |
446 if (the_user == ((char *) NULL)) | |
447 file_preface = make_file_preface (); | |
448 write_line_list (file_preface, the_stream); | |
449 return true; | |
450 } | |
451 return false; | |
452 } | |
453 | |
454 void | |
455 put_string (s) | |
456 char *s; | |
457 { | |
458 register stream_list rem; | |
459 for (rem = the_streams; | |
460 rem != ((stream_list) NULL); | |
461 rem = rem->rest_streams) | |
462 fputs (s, rem->handle); | |
463 return; | |
464 } | |
465 | |
466 void | |
20 | 467 put_line (string) |
468 char *string; | |
18 | 469 { |
470 register stream_list rem; | |
471 for (rem = the_streams; | |
472 rem != ((stream_list) NULL); | |
473 rem = rem->rest_streams) | |
474 { | |
20 | 475 char *s = string; |
476 int column = 0; | |
477 | |
478 /* Divide STRING into lines. */ | |
479 while (*s != 0) | |
480 { | |
481 char *breakpos; | |
482 | |
5959
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
483 /* Find the last char that fits. */ |
20 | 484 for (breakpos = s; *breakpos && column < 78; ++breakpos) |
485 { | |
486 if (*breakpos == '\t') | |
487 column += 8; | |
488 else | |
489 column++; | |
490 } | |
5959
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
491 /* If we didn't reach end of line, break the line. */ |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
492 if (*breakpos) |
20 | 493 { |
5959
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
494 /* Back up to just after the last comma that fits. */ |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
495 while (breakpos != s && breakpos[-1] != ',') --breakpos; |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
496 |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
497 if (breakpos == s) |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
498 { |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
499 /* If no comma fits, move past the first address anyway. */ |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
500 while (*breakpos != 0 && *breakpos != ',') ++breakpos; |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
501 if (*breakpos != 0) |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
502 /* Include the comma after it. */ |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
503 ++breakpos; |
e4337a7bbe32
(put_line): Don't break the line if it all fits.
Richard M. Stallman <rms@gnu.org>
parents:
5447
diff
changeset
|
504 } |
20 | 505 } |
506 /* Output that much, then break the line. */ | |
507 fwrite (s, 1, breakpos - s, rem->handle); | |
508 column = 8; | |
509 | |
510 /* Skip whitespace and prepare to print more addresses. */ | |
511 s = breakpos; | |
512 while (*s == ' ' || *s == '\t') ++s; | |
3219
1aa8fa0a569e
(put_line): Don't output \n\t unless more text follows.
Richard M. Stallman <rms@gnu.org>
parents:
37
diff
changeset
|
513 if (*s != 0) |
1aa8fa0a569e
(put_line): Don't output \n\t unless more text follows.
Richard M. Stallman <rms@gnu.org>
parents:
37
diff
changeset
|
514 fputs ("\n\t", rem->handle); |
20 | 515 } |
18 | 516 putc ('\n', rem->handle); |
517 } | |
518 return; | |
519 } | |
520 | |
521 #define mail_error error | |
522 | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
523 /* Handle an FCC field. FIELD is the text of the first line (after |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
524 the header name), and THE_LIST holds the continuation lines if any. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
525 Call open_a_file for each file. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
526 |
18 | 527 void |
528 setup_files (the_list, field) | |
529 register line_list the_list; | |
530 register char *field; | |
531 { | |
532 register char *start; | |
533 register char c; | |
534 while (true) | |
535 { | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
536 while (((c = *field) != '\0') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
537 && (c == ' ' |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
538 || c == '\t' |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
539 || c == ',')) |
18 | 540 field += 1; |
541 if (c != '\0') | |
542 { | |
543 start = field; | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
544 while (((c = *field) != '\0') |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
545 && c != ' ' |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
546 && c != '\t' |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
547 && c != ',') |
18 | 548 field += 1; |
549 *field = '\0'; | |
550 if (!open_a_file (start)) | |
551 mail_error ("Could not open file %s", start); | |
552 *field = c; | |
553 if (c != '\0') continue; | |
554 } | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
555 if (the_list == ((line_list) NULL)) |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
556 return; |
18 | 557 field = the_list->string; |
558 the_list = the_list->continuation; | |
559 } | |
560 } | |
561 | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
562 /* Compute the total size of all recipient names stored in THE_HEADER. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
563 The result says how big to make the buffer to pass to parse_header. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
564 |
18 | 565 int |
566 args_size (the_header) | |
567 header the_header; | |
568 { | |
569 register header old = the_header; | |
570 register line_list rem; | |
571 register int size = 0; | |
572 do | |
573 { | |
574 char *field; | |
575 register char *keyword = get_keyword (the_header->text->string, &field); | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
576 if ((strcmp (keyword, "TO") == 0) |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
577 || (strcmp (keyword, "CC") == 0) |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
578 || (strcmp (keyword, "BCC") == 0)) |
18 | 579 { |
580 size += 1 + strlen (field); | |
581 for (rem = the_header->text->continuation; | |
582 rem != NIL; | |
583 rem = rem->continuation) | |
584 size += 1 + strlen (rem->string); | |
585 } | |
586 the_header = the_header->next; | |
587 } while (the_header != old); | |
588 return size; | |
589 } | |
590 | |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
591 /* Scan the header described by the lists THE_HEADER, |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
592 and put all recipient names into the buffer WHERE. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
593 Precede each recipient name with a space. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
594 |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
595 Also, if the header has any FCC fields, call setup_files for each one. */ |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
596 |
21389
48690fd8d40a
(_XOPEN_SOURCE): Define for declaration of cuserid.
Andreas Schwab <schwab@suse.de>
parents:
18841
diff
changeset
|
597 void |
18 | 598 parse_header (the_header, where) |
599 header the_header; | |
600 register char *where; | |
601 { | |
602 register header old = the_header; | |
603 do | |
604 { | |
605 char *field; | |
606 register char *keyword = get_keyword (the_header->text->string, &field); | |
607 if (strcmp (keyword, "TO") == 0) | |
608 where = add_field (the_header->text->continuation, field, where); | |
609 else if (strcmp (keyword, "CC") == 0) | |
610 where = add_field (the_header->text->continuation, field, where); | |
611 else if (strcmp (keyword, "BCC") == 0) | |
612 { | |
613 where = add_field (the_header->text->continuation, field, where); | |
614 the_header->previous->next = the_header->next; | |
615 the_header->next->previous = the_header->previous; | |
616 } | |
617 else if (strcmp (keyword, "FCC") == 0) | |
618 setup_files (the_header->text->continuation, field); | |
619 the_header = the_header->next; | |
620 } while (the_header != old); | |
621 *where = '\0'; | |
622 return; | |
623 } | |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
624 |
10265
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
625 /* Read lines from the input until we get a blank line. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
626 Create a list of `header' objects, one for each header field, |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
627 each of which points to a list of `line_list' objects, |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
628 one for each line in that field. |
c53a70ec8d85
(xmalloc, xrealloc): Add casts.
Richard M. Stallman <rms@gnu.org>
parents:
9621
diff
changeset
|
629 Continuation lines are grouped in the headers they continue. */ |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
630 |
18 | 631 header |
632 read_header () | |
633 { | |
634 register header the_header = ((header) NULL); | |
635 register line_list *next_line = ((line_list *) NULL); | |
636 | |
637 init_linebuffer (&lb); | |
638 | |
639 do | |
640 { | |
641 long length; | |
642 register char *line; | |
643 | |
644 readline (&lb, stdin); | |
645 line = lb.buffer; | |
646 length = strlen (line); | |
647 if (length == 0) break; | |
648 | |
649 if (has_keyword (line)) | |
650 { | |
651 register header old = the_header; | |
652 the_header = new_header (); | |
653 if (old == ((header) NULL)) | |
654 { | |
655 the_header->next = the_header; | |
656 the_header->previous = the_header; | |
657 } | |
658 else | |
659 { | |
660 the_header->previous = old; | |
661 the_header->next = old->next; | |
662 old->next = the_header; | |
663 } | |
664 next_line = &(the_header->text); | |
665 } | |
666 | |
667 if (next_line == ((line_list *) NULL)) | |
668 { | |
669 /* Not a valid header */ | |
670 exit (1); | |
671 } | |
672 *next_line = new_list (); | |
673 (*next_line)->string = alloc_string (length); | |
674 strcpy (((*next_line)->string), line); | |
675 next_line = &((*next_line)->continuation); | |
676 *next_line = NIL; | |
677 | |
678 } while (true); | |
679 | |
680 return the_header->next; | |
681 } | |
682 | |
683 void | |
684 write_header (the_header) | |
685 header the_header; | |
686 { | |
687 register header old = the_header; | |
688 do | |
689 { | |
690 register line_list the_list; | |
691 for (the_list = the_header->text; | |
692 the_list != NIL; | |
693 the_list = the_list->continuation) | |
694 put_line (the_list->string); | |
695 the_header = the_header->next; | |
696 } while (the_header != old); | |
697 put_line (""); | |
698 return; | |
699 } | |
700 | |
15683 | 701 int |
18 | 702 main (argc, argv) |
703 int argc; | |
704 char **argv; | |
705 { | |
706 char *command_line; | |
707 header the_header; | |
708 long name_length; | |
709 char *mail_program_name; | |
710 char buf[BUFLEN + 1]; | |
711 register int size; | |
712 FILE *the_pipe; | |
713 | |
714 extern char *getenv (); | |
715 | |
716 mail_program_name = getenv ("FAKEMAILER"); | |
717 if (!(mail_program_name && *mail_program_name)) | |
718 mail_program_name = MAIL_PROGRAM_NAME; | |
719 name_length = strlen (mail_program_name); | |
720 | |
721 my_name = MY_NAME; | |
722 the_streams = ((stream_list) NULL); | |
723 the_date = ((char *) NULL); | |
724 the_user = ((char *) NULL); | |
725 | |
726 the_header = read_header (); | |
727 command_line = alloc_string (name_length + args_size (the_header)); | |
728 strcpy (command_line, mail_program_name); | |
729 parse_header (the_header, &command_line[name_length]); | |
42181
358035cb58d9
Conditionally include config.h.
Pavel Janík <Pavel@Janik.cz>
parents:
42134
diff
changeset
|
730 |
18 | 731 the_pipe = popen (command_line, "w"); |
732 if (the_pipe == ((FILE *) NULL)) | |
733 fatal ("cannot open pipe to real mailer"); | |
734 | |
735 add_a_stream (the_pipe, pclose); | |
736 | |
737 write_header (the_header); | |
738 | |
739 /* Dump the message itself */ | |
740 | |
741 while (!feof (stdin)) | |
742 { | |
743 size = fread (buf, 1, BUFLEN, stdin); | |
744 buf[size] = '\0'; | |
745 put_string (buf); | |
746 } | |
747 | |
748 exit (close_the_streams ()); | |
749 } | |
750 | |
5447
6f0905b05218
(main) [MSDOS]: Dummy stub just to make the file compile.
Richard M. Stallman <rms@gnu.org>
parents:
4696
diff
changeset
|
751 #endif /* not MSDOS */ |
18 | 752 #endif /* not BSD 4.2 (or newer) */ |
52401 | 753 |
754 /* arch-tag: acb0afa6-315a-4c5b-b9e3-def5725c8783 | |
755 (do not change this comment) */ |