Commit | Line | Data |
---|---|---|
761330fe DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
0c5f72fb KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
acfc7e9b KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
761330fe DF |
16 | */ |
17 | ||
acfc7e9b | 18 | #ifndef lint |
2de8fc95 | 19 | static char sccsid[] = "@(#)send.c 5.13 (Berkeley) %G%"; |
acfc7e9b | 20 | #endif /* not lint */ |
3184019b KS |
21 | |
22 | #include "rcv.h" | |
97917bd0 | 23 | #include <sys/wait.h> |
a1f76dd3 | 24 | #include <sys/stat.h> |
3184019b KS |
25 | |
26 | /* | |
27 | * Mail -- a mail program | |
28 | * | |
29 | * Mail to others. | |
30 | */ | |
31 | ||
3184019b KS |
32 | /* |
33 | * Send message described by the passed pointer to the | |
2de8fc95 EW |
34 | * passed output buffer. Return -1 on error. |
35 | * Adjust the status: field if need be. | |
36 | * If doign is given, suppress ignored header fields. | |
37 | * prefix is a string to prepend to each output line. | |
3184019b | 38 | */ |
2de8fc95 | 39 | send(mp, obuf, doign, prefix) |
828615a1 | 40 | register struct message *mp; |
3184019b | 41 | FILE *obuf; |
887efe38 | 42 | struct ignoretab *doign; |
2de8fc95 | 43 | char *prefix; |
3184019b | 44 | { |
828615a1 EW |
45 | long count; |
46 | register FILE *ibuf; | |
47 | char line[LINESIZE]; | |
2de8fc95 | 48 | int ishead, infld, ignoring, dostat, firstline; |
828615a1 EW |
49 | register char *cp, *cp2; |
50 | register int c; | |
51 | int length; | |
52 | ||
3184019b | 53 | ibuf = setinput(mp); |
828615a1 | 54 | count = mp->m_size; |
b870137d | 55 | ishead = 1; |
887efe38 | 56 | dostat = doign == 0 || !isign("status", doign); |
a6b3a6c5 | 57 | infld = 0; |
2de8fc95 | 58 | firstline = 1; |
828615a1 EW |
59 | /* |
60 | * Process headers first | |
61 | */ | |
62 | while (count > 0 && ishead) { | |
63 | if (fgets(line, LINESIZE, ibuf) == NULL) | |
64 | break; | |
65 | count -= length = strlen(line); | |
2de8fc95 | 66 | if (firstline) { |
b870137d KS |
67 | /* |
68 | * First line is the From line, so no headers | |
69 | * there to worry about | |
70 | */ | |
2de8fc95 EW |
71 | firstline = 0; |
72 | ignoring = doign == ignoreall; | |
828615a1 | 73 | } else if (line[0] == '\n') { |
b870137d KS |
74 | /* |
75 | * If line is blank, we've reached end of | |
76 | * headers, so force out status: field | |
77 | * and note that we are no longer in header | |
78 | * fields | |
79 | */ | |
828615a1 | 80 | if (dostat) { |
2de8fc95 | 81 | statusput(mp, obuf, prefix); |
828615a1 | 82 | dostat = 0; |
57079810 | 83 | } |
828615a1 | 84 | ishead = 0; |
2de8fc95 | 85 | ignoring = doign == ignoreall; |
828615a1 | 86 | } else if (infld && (line[0] == ' ' || line[0] == '\t')) { |
b870137d | 87 | /* |
df5134c8 BB |
88 | * If this line is a continuation (via space or tab) |
89 | * of a previous header field, just echo it | |
90 | * (unless the field should be ignored). | |
828615a1 | 91 | * In other words, nothing to do. |
b870137d | 92 | */ |
828615a1 | 93 | } else { |
b870137d | 94 | /* |
828615a1 | 95 | * Pick up the header field if we have one. |
b870137d | 96 | */ |
828615a1 EW |
97 | for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) |
98 | ; | |
99 | cp2 = --cp; | |
100 | while (isspace(*cp++)) | |
101 | ; | |
102 | if (cp[-1] != ':') { | |
103 | /* | |
104 | * Not a header line, force out status: | |
105 | * This happens in uucp style mail where | |
106 | * there are no headers at all. | |
107 | */ | |
b870137d | 108 | if (dostat) { |
2de8fc95 | 109 | statusput(mp, obuf, prefix); |
b870137d KS |
110 | dostat = 0; |
111 | } | |
2de8fc95 EW |
112 | if (doign != ignoreall) |
113 | /* add blank line */ | |
114 | (void) putc('\n', obuf); | |
a6b3a6c5 | 115 | ishead = 0; |
828615a1 EW |
116 | ignoring = 0; |
117 | } else { | |
118 | /* | |
119 | * If it is an ignored field and | |
120 | * we care about such things, skip it. | |
121 | */ | |
122 | *cp2 = 0; /* temporarily null terminate */ | |
887efe38 | 123 | if (doign && isign(line, doign)) |
828615a1 EW |
124 | ignoring = 1; |
125 | else if ((line[0] == 's' || line[0] == 'S') && | |
126 | icequal(line, "status")) { | |
127 | /* | |
128 | * If the field is "status," go compute | |
129 | * and print the real Status: field | |
130 | */ | |
131 | if (dostat) { | |
2de8fc95 | 132 | statusput(mp, obuf, prefix); |
828615a1 EW |
133 | dostat = 0; |
134 | } | |
135 | ignoring = 1; | |
136 | } else { | |
137 | ignoring = 0; | |
138 | *cp2 = c; /* restore */ | |
2d7a1b5d | 139 | } |
828615a1 | 140 | infld = 1; |
2d7a1b5d | 141 | } |
57079810 | 142 | } |
828615a1 | 143 | if (!ignoring) { |
2de8fc95 EW |
144 | if (prefix != NOSTR && length > 1) |
145 | fputs(prefix, obuf); | |
751b30cd | 146 | (void) fwrite(line, sizeof *line, length, obuf); |
828615a1 EW |
147 | if (ferror(obuf)) |
148 | return -1; | |
828615a1 | 149 | } |
3184019b | 150 | } |
828615a1 EW |
151 | /* |
152 | * Copy out message body | |
153 | */ | |
2de8fc95 EW |
154 | if (doign == ignoreall) |
155 | count--; /* skip final blank line */ | |
156 | if (prefix != NOSTR) | |
157 | while (count > 0) { | |
158 | if (fgets(line, LINESIZE, ibuf) == NULL) { | |
159 | c = 0; | |
160 | break; | |
161 | } | |
162 | count -= c = strlen(line); | |
163 | if (c > 1) | |
164 | fputs(prefix, obuf); | |
165 | (void) fwrite(line, sizeof *line, c, obuf); | |
166 | if (ferror(obuf)) | |
167 | return -1; | |
168 | } | |
169 | else | |
170 | while (count > 0) { | |
171 | c = count < LINESIZE ? count : LINESIZE; | |
172 | if ((c = fread(line, sizeof *line, c, ibuf)) <= 0) | |
173 | break; | |
174 | count -= c; | |
175 | if (fwrite(line, sizeof *line, c, obuf) != c) | |
176 | return -1; | |
177 | } | |
178 | if (doign == ignoreall && c > 0 && line[c - 1] != '\n') | |
179 | /* no final blank line */ | |
180 | if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) | |
828615a1 | 181 | return -1; |
2de8fc95 | 182 | return 0; |
a6b3a6c5 KS |
183 | } |
184 | ||
57079810 KS |
185 | /* |
186 | * Output a reasonable looking status field. | |
187 | */ | |
2de8fc95 | 188 | statusput(mp, obuf, prefix) |
57079810 | 189 | register struct message *mp; |
828615a1 | 190 | FILE *obuf; |
2de8fc95 | 191 | char *prefix; |
57079810 KS |
192 | { |
193 | char statout[3]; | |
828615a1 | 194 | register char *cp = statout; |
57079810 | 195 | |
57079810 | 196 | if (mp->m_flag & MREAD) |
828615a1 | 197 | *cp++ = 'R'; |
57079810 | 198 | if ((mp->m_flag & MNEW) == 0) |
828615a1 EW |
199 | *cp++ = 'O'; |
200 | *cp = 0; | |
201 | if (statout[0]) | |
2de8fc95 EW |
202 | fprintf(obuf, "%sStatus: %s\n", |
203 | prefix == NOSTR ? "" : prefix, statout); | |
57079810 KS |
204 | } |
205 | ||
3184019b KS |
206 | /* |
207 | * Interface between the argument list and the mail1 routine | |
208 | * which does all the dirty work. | |
209 | */ | |
210 | ||
3d6f01e5 | 211 | mail(to, cc, bcc, smopts, subject) |
790344bc | 212 | struct name *to, *cc, *bcc, *smopts; |
3d6f01e5 | 213 | char *subject; |
3184019b | 214 | { |
3184019b KS |
215 | struct header head; |
216 | ||
3d6f01e5 EW |
217 | head.h_to = to; |
218 | head.h_subject = subject; | |
219 | head.h_cc = cc; | |
220 | head.h_bcc = bcc; | |
221 | head.h_smopts = smopts; | |
222 | (void) mail1(&head, 0); | |
3184019b KS |
223 | return(0); |
224 | } | |
225 | ||
226 | ||
227 | /* | |
228 | * Send mail to a bunch of user names. The interface is through | |
229 | * the mail routine below. | |
230 | */ | |
231 | ||
232 | sendmail(str) | |
233 | char *str; | |
234 | { | |
3184019b KS |
235 | struct header head; |
236 | ||
3d6f01e5 | 237 | head.h_to = extract(str, GTO); |
3184019b | 238 | head.h_subject = NOSTR; |
3d6f01e5 EW |
239 | head.h_cc = NIL; |
240 | head.h_bcc = NIL; | |
241 | head.h_smopts = NIL; | |
242 | (void) mail1(&head, 0); | |
3184019b KS |
243 | return(0); |
244 | } | |
245 | ||
246 | /* | |
247 | * Mail a message on standard input to the people indicated | |
248 | * in the passed header. (Internal interface). | |
249 | */ | |
250 | ||
3d6f01e5 | 251 | mail1(hp, printheaders) |
3184019b KS |
252 | struct header *hp; |
253 | { | |
254 | register char *cp; | |
828615a1 EW |
255 | int pid, i, p, gotcha; |
256 | union wait s; | |
6fa89d43 | 257 | char **namelist, *deliver; |
3184019b | 258 | struct name *to, *np; |
a1f76dd3 | 259 | struct stat sbuf; |
3184019b | 260 | FILE *mtf, *postage; |
3184019b KS |
261 | char **t; |
262 | ||
263 | /* | |
264 | * Collect user's mail from standard input. | |
265 | * Get the result as mtf. | |
266 | */ | |
267 | ||
268 | pid = -1; | |
3d6f01e5 | 269 | if ((mtf = collect(hp, printheaders)) == NULL) |
3184019b | 270 | return(-1); |
686f6134 EW |
271 | if (value("interactive") != NOSTR) |
272 | if (value("askcc") != NOSTR) | |
273 | grabh(hp, GCC); | |
274 | else { | |
275 | printf("EOT\n"); | |
276 | (void) fflush(stdout); | |
277 | } | |
3184019b KS |
278 | /* |
279 | * Now, take the user names from the combined | |
280 | * to and cc lists and do all the alias | |
281 | * processing. | |
282 | */ | |
3184019b | 283 | senderr = 0; |
3d6f01e5 | 284 | to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); |
3184019b KS |
285 | if (to == NIL) { |
286 | printf("No recipients specified\n"); | |
287 | goto topdog; | |
288 | } | |
3184019b KS |
289 | /* |
290 | * Look through the recipient list for names with /'s | |
291 | * in them which we write to as files directly. | |
292 | */ | |
3184019b KS |
293 | to = outof(to, mtf, hp); |
294 | rewind(mtf); | |
2f025913 | 295 | if (senderr) { |
3184019b | 296 | topdog: |
3184019b | 297 | if (fsize(mtf) != 0) { |
751b30cd EW |
298 | (void) remove(deadletter); |
299 | (void) exwrite(deadletter, mtf, 1); | |
3184019b KS |
300 | rewind(mtf); |
301 | } | |
302 | } | |
303 | for (gotcha = 0, np = to; np != NIL; np = np->n_flink) | |
304 | if ((np->n_type & GDEL) == 0) { | |
305 | gotcha++; | |
306 | break; | |
307 | } | |
308 | if (!gotcha) | |
309 | goto out; | |
310 | to = elide(to); | |
3d6f01e5 EW |
311 | if (fsize(mtf) == 0) |
312 | if (hp->h_subject == NOSTR) | |
430e0622 | 313 | printf("No message, no subject; hope that's ok\n"); |
3d6f01e5 | 314 | else |
3184019b | 315 | printf("Null message body; hope that's ok\n"); |
3d6f01e5 EW |
316 | if (count(to) > 0 || hp->h_subject != NOSTR) { |
317 | /* don't do this unless we have to */ | |
318 | fixhead(hp, to); | |
3184019b KS |
319 | if ((mtf = infix(hp, mtf)) == NULL) { |
320 | fprintf(stderr, ". . . message lost, sorry.\n"); | |
321 | return(-1); | |
322 | } | |
323 | } | |
3d6f01e5 | 324 | namelist = unpack(cat(hp->h_smopts, to)); |
3184019b | 325 | if (debug) { |
3d6f01e5 | 326 | printf("Sendmail arguments:"); |
3184019b KS |
327 | for (t = namelist; *t != NOSTR; t++) |
328 | printf(" \"%s\"", *t); | |
329 | printf("\n"); | |
751b30cd | 330 | (void) fflush(stdout); |
828615a1 | 331 | return 0; |
3184019b KS |
332 | } |
333 | if ((cp = value("record")) != NOSTR) | |
751b30cd | 334 | (void) savemail(expand(cp), mtf); |
3184019b KS |
335 | /* |
336 | * Wait, to absorb a potential zombie, then | |
337 | * fork, set up the temporary mail file as standard | |
338 | * input for "mail" and exec with the user list we generated | |
339 | * far above. Return the process id to caller in case he | |
340 | * wants to await the completion of mail. | |
341 | */ | |
828615a1 | 342 | while (wait3(&s, WNOHANG, (struct timeval *) 0) > 0) |
3184019b | 343 | ; |
3184019b KS |
344 | rewind(mtf); |
345 | pid = fork(); | |
346 | if (pid == -1) { | |
347 | perror("fork"); | |
751b30cd EW |
348 | (void) remove(deadletter); |
349 | (void) exwrite(deadletter, mtf, 1); | |
3184019b KS |
350 | goto out; |
351 | } | |
352 | if (pid == 0) { | |
353 | #ifdef SIGTSTP | |
2f025913 EW |
354 | (void) signal(SIGTSTP, SIG_IGN); |
355 | (void) signal(SIGTTIN, SIG_IGN); | |
356 | (void) signal(SIGTTOU, SIG_IGN); | |
3184019b | 357 | #endif |
751b30cd EW |
358 | (void) signal(SIGHUP, SIG_IGN); |
359 | (void) signal(SIGINT, SIG_IGN); | |
360 | (void) signal(SIGQUIT, SIG_IGN); | |
a1f76dd3 CL |
361 | if (!stat(POSTAGE, &sbuf)) |
362 | if ((postage = fopen(POSTAGE, "a")) != NULL) { | |
751b30cd | 363 | fprintf(postage, "%s %d %ld\n", myname, |
a1f76dd3 | 364 | count(to), fsize(mtf)); |
751b30cd | 365 | (void) fclose(postage); |
a1f76dd3 | 366 | } |
751b30cd EW |
367 | (void) close(0); |
368 | (void) dup(fileno(mtf)); | |
828615a1 | 369 | for (i = getdtablesize(); --i > 2;) |
751b30cd | 370 | (void) close(i); |
6fa89d43 | 371 | if ((deliver = value("sendmail")) == NOSTR) |
ac57be53 | 372 | deliver = SENDMAIL; |
6fa89d43 | 373 | execv(deliver, namelist); |
9c226cb6 | 374 | perror(deliver); |
3184019b KS |
375 | exit(1); |
376 | } | |
3184019b | 377 | out: |
2f025913 | 378 | if (value("verbose") != NOSTR) { |
3184019b KS |
379 | while ((p = wait(&s)) != pid && p != -1) |
380 | ; | |
828615a1 | 381 | if (s.w_status != 0) |
3184019b KS |
382 | senderr++; |
383 | pid = 0; | |
384 | } | |
751b30cd | 385 | (void) fclose(mtf); |
3d6f01e5 | 386 | return pid; |
3184019b KS |
387 | } |
388 | ||
389 | /* | |
390 | * Fix the header by glopping all of the expanded names from | |
391 | * the distribution list into the appropriate fields. | |
3184019b | 392 | */ |
3184019b KS |
393 | fixhead(hp, tolist) |
394 | struct header *hp; | |
395 | struct name *tolist; | |
396 | { | |
3184019b KS |
397 | register struct name *np; |
398 | ||
3d6f01e5 EW |
399 | hp->h_to = NIL; |
400 | hp->h_cc = NIL; | |
401 | hp->h_bcc = NIL; | |
402 | for (np = tolist; np != NIL; np = np->n_flink) | |
403 | if ((np->n_type & GMASK) == GTO) | |
404 | hp->h_to = | |
405 | cat(hp->h_to, nalloc(np->n_name, np->n_type)); | |
406 | else if ((np->n_type & GMASK) == GCC) | |
407 | hp->h_cc = | |
408 | cat(hp->h_cc, nalloc(np->n_name, np->n_type)); | |
409 | else if ((np->n_type & GMASK) == GBCC) | |
410 | hp->h_bcc = | |
411 | cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); | |
3184019b KS |
412 | } |
413 | ||
414 | /* | |
415 | * Prepend a header in front of the collected stuff | |
416 | * and return the new file. | |
417 | */ | |
418 | ||
419 | FILE * | |
420 | infix(hp, fi) | |
421 | struct header *hp; | |
422 | FILE *fi; | |
423 | { | |
424 | extern char tempMail[]; | |
425 | register FILE *nfo, *nfi; | |
426 | register int c; | |
427 | ||
1c5ad8c6 | 428 | rewind(fi); |
3184019b KS |
429 | if ((nfo = fopen(tempMail, "w")) == NULL) { |
430 | perror(tempMail); | |
431 | return(fi); | |
432 | } | |
433 | if ((nfi = fopen(tempMail, "r")) == NULL) { | |
434 | perror(tempMail); | |
751b30cd | 435 | (void) fclose(nfo); |
3184019b KS |
436 | return(fi); |
437 | } | |
751b30cd | 438 | (void) remove(tempMail); |
3d6f01e5 | 439 | (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA); |
3184019b KS |
440 | c = getc(fi); |
441 | while (c != EOF) { | |
751b30cd | 442 | (void) putc(c, nfo); |
3184019b KS |
443 | c = getc(fi); |
444 | } | |
445 | if (ferror(fi)) { | |
446 | perror("read"); | |
3184019b KS |
447 | return(fi); |
448 | } | |
751b30cd | 449 | (void) fflush(nfo); |
3184019b KS |
450 | if (ferror(nfo)) { |
451 | perror(tempMail); | |
751b30cd EW |
452 | (void) fclose(nfo); |
453 | (void) fclose(nfi); | |
3184019b KS |
454 | return(fi); |
455 | } | |
751b30cd EW |
456 | (void) fclose(nfo); |
457 | (void) fclose(fi); | |
3184019b KS |
458 | rewind(nfi); |
459 | return(nfi); | |
460 | } | |
461 | ||
462 | /* | |
463 | * Dump the to, subject, cc header on the | |
464 | * passed file buffer. | |
465 | */ | |
3184019b KS |
466 | puthead(hp, fo, w) |
467 | struct header *hp; | |
468 | FILE *fo; | |
469 | { | |
470 | register int gotcha; | |
471 | ||
472 | gotcha = 0; | |
3d6f01e5 EW |
473 | if (hp->h_to != NIL && w & GTO) |
474 | fmt("To: ", hp->h_to, fo, w&GCOMMA), gotcha++; | |
3184019b KS |
475 | if (hp->h_subject != NOSTR && w & GSUBJECT) |
476 | fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; | |
3d6f01e5 EW |
477 | if (hp->h_cc != NIL && w & GCC) |
478 | fmt("Cc: ", hp->h_cc, fo, w&GCOMMA), gotcha++; | |
479 | if (hp->h_bcc != NIL && w & GBCC) | |
480 | fmt("Bcc: ", hp->h_bcc, fo, w&GCOMMA), gotcha++; | |
3184019b | 481 | if (gotcha && w & GNL) |
751b30cd | 482 | (void) putc('\n', fo); |
3184019b KS |
483 | return(0); |
484 | } | |
485 | ||
486 | /* | |
487 | * Format the given text to not exceed 72 characters. | |
488 | */ | |
3d6f01e5 EW |
489 | fmt(str, np, fo, comma) |
490 | char *str; | |
491 | register struct name *np; | |
492 | FILE *fo; | |
493 | int comma; | |
3184019b | 494 | { |
3d6f01e5 | 495 | register col, len; |
a1f76dd3 | 496 | |
3d6f01e5 | 497 | comma = comma ? 1 : 0; |
a1f76dd3 CL |
498 | col = strlen(str); |
499 | if (col) | |
3d6f01e5 EW |
500 | fputs(str, fo); |
501 | len = strlen(np->n_name); | |
502 | for (;;) { | |
503 | fputs(np->n_name, fo); | |
504 | col += len; | |
505 | if (comma) { | |
506 | putc(',', fo); | |
507 | col++; | |
a1f76dd3 | 508 | } |
3d6f01e5 EW |
509 | if ((np = np->n_flink) == NIL) |
510 | break; | |
511 | if (np->n_flink == NIL) | |
512 | comma = 0; | |
513 | len = strlen(np->n_name); | |
514 | if (col + len + comma > 72) { | |
515 | fputs("\n ", fo); | |
516 | col = 4; | |
517 | } else { | |
518 | putc(' ', fo); | |
519 | col++; | |
3184019b | 520 | } |
3184019b | 521 | } |
3d6f01e5 | 522 | putc('\n', fo); |
3184019b KS |
523 | } |
524 | ||
525 | /* | |
526 | * Save the outgoing mail on the passed file. | |
527 | */ | |
528 | ||
828615a1 EW |
529 | /*ARGSUSED*/ |
530 | savemail(name, fi) | |
3184019b | 531 | char name[]; |
828615a1 | 532 | register FILE *fi; |
3184019b KS |
533 | { |
534 | register FILE *fo; | |
828615a1 EW |
535 | char buf[BUFSIZ]; |
536 | register i; | |
537 | time_t now, time(); | |
828615a1 | 538 | char *ctime(); |
3184019b KS |
539 | |
540 | if ((fo = fopen(name, "a")) == NULL) { | |
541 | perror(name); | |
828615a1 | 542 | return (-1); |
3184019b | 543 | } |
751b30cd | 544 | (void) time(&now); |
2f025913 | 545 | fprintf(fo, "From %s %s", myname, ctime(&now)); |
3184019b | 546 | rewind(fi); |
828615a1 | 547 | while ((i = fread(buf, 1, sizeof buf, fi)) > 0) |
751b30cd EW |
548 | (void) fwrite(buf, 1, i, fo); |
549 | (void) putc('\n', fo); | |
550 | (void) fflush(fo); | |
3184019b KS |
551 | if (ferror(fo)) |
552 | perror(name); | |
751b30cd | 553 | (void) fclose(fo); |
828615a1 | 554 | return (0); |
3184019b | 555 | } |