Bug Summary

File:src/usr.bin/mail/collect.c
Warning:line 68, column 2
Value stored to 'lastlong' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name collect.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/mail/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/mail/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/mail/collect.c
1/* $OpenBSD: collect.c,v 1.34 2014/01/17 18:42:30 okan Exp $ */
2/* $NetBSD: collect.c,v 1.9 1997/07/09 05:25:45 mikel Exp $ */
3
4/*
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Mail -- a mail program
35 *
36 * Collect input from standard input, handling
37 * ~ escapes.
38 */
39
40#include "rcv.h"
41#include "extern.h"
42
43/*
44 * Read a message from standard output and return a read file to it
45 * or NULL on error.
46 */
47
48/*
49 * The following hokiness with global variables is so that on
50 * receipt of an interrupt signal, the partial message can be salted
51 * away on dead.letter.
52 */
53static FILE *collf; /* File for saving away */
54static int hadintr; /* Have seen one SIGINT so far */
55
56FILE *
57collect(struct header *hp, int printheaders)
58{
59 FILE *fbuf;
60 int lc, cc, fd, c, t, lastlong, rc, sig;
61 int escape, eofcount, longline;
62 char getsub;
63 char linebuf[LINESIZE1024], tempname[PATHSIZE1024], *cp;
64
65 collf = NULL((void *)0);
66 eofcount = 0;
67 hadintr = 0;
68 lastlong = 0;
Value stored to 'lastlong' is never read
69 longline = 0;
70 if ((cp = value("escape")) != NULL((void *)0))
71 escape = *cp;
72 else
73 escape = ESCAPE'~';
74 noreset++;
75
76 (void)snprintf(tempname, sizeof(tempname),
77 "%s/mail.RsXXXXXXXXXX", tmpdir);
78 if ((fd = mkstemp(tempname)) == -1 ||
79 (collf = Fdopen(fd, "w+")) == NULL((void *)0)) {
80 warn("%s", tempname);
81 goto err;
82 }
83 (void)rm(tempname);
84
85 /*
86 * If we are going to prompt for a subject,
87 * refrain from printing a newline after
88 * the headers (since some people mind).
89 */
90 t = GTO1|GSUBJECT2|GCC4|GNL16;
91 getsub = 0;
92 if (hp->h_subject == NULL((void *)0) && value("interactive") != NULL((void *)0) &&
93 (value("ask") != NULL((void *)0) || value("asksub") != NULL((void *)0)))
94 t &= ~GNL16, getsub++;
95 if (printheaders) {
96 puthead(hp, stdout(&__sF[1]), t);
97 fflush(stdout(&__sF[1]));
98 }
99 if (getsub && gethfromtty(hp, GSUBJECT2) == -1)
100 goto err;
101
102 if (0) {
103cont:
104 /* Come here for printing the after-suspend message. */
105 if (isatty(0)) {
106 puts("(continue)");
107 fflush(stdout(&__sF[1]));
108 }
109 }
110 for (;;) {
111 c = readline(stdin(&__sF[0]), linebuf, LINESIZE1024, &sig);
112
113 /* Act on any signal caught during readline() ignoring 'c' */
114 switch (sig) {
115 case 0:
116 break;
117 case SIGINT2:
118 if (collabort())
119 goto err;
120 continue;
121 case SIGHUP1:
122 rewind(collf);
123 savedeadletter(collf);
124 /*
125 * Let's pretend nobody else wants to clean up,
126 * a true statement at this time.
127 */
128 exit(1);
129 default:
130 /* Stopped due to job control */
131 (void)kill(0, sig);
132 goto cont;
133 }
134
135 /* No signal, check for error */
136 if (c < 0) {
137 if (value("interactive") != NULL((void *)0) &&
138 value("ignoreeof") != NULL((void *)0) && ++eofcount < 25) {
139 puts("Use \".\" to terminate letter");
140 continue;
141 }
142 break;
143 }
144 lastlong = longline;
145 longline = (c == LINESIZE1024 - 1);
146 eofcount = 0;
147 hadintr = 0;
148 if (linebuf[0] == '.' && linebuf[1] == '\0' &&
149 value("interactive") != NULL((void *)0) && !lastlong &&
150 (value("dot") != NULL((void *)0) || value("ignoreeof") != NULL((void *)0)))
151 break;
152 if (linebuf[0] != escape || value("interactive") == NULL((void *)0) ||
153 lastlong) {
154 if (putline(collf, linebuf, !longline) < 0)
155 goto err;
156 continue;
157 }
158 c = (unsigned char)linebuf[1];
159 switch (c) {
160 default:
161 /*
162 * On double escape, just send the single one.
163 * Otherwise, it's an error.
164 */
165 if (c == escape) {
166 if (putline(collf, &linebuf[1], !longline) < 0)
167 goto err;
168 else
169 break;
170 }
171 puts("Unknown tilde escape.");
172 break;
173 case '!':
174 /*
175 * Shell escape, send the balance of the
176 * line to sh -c.
177 */
178 shell(&linebuf[2]);
179 break;
180 case ':':
181 case '_':
182 /*
183 * Escape to command mode, but be nice!
184 */
185 execute(&linebuf[2], 1);
186 goto cont;
187 case '.':
188 /*
189 * Simulate end of file on input.
190 */
191 goto out;
192 case 'q':
193 /*
194 * Force a quit of sending mail.
195 * Act like an interrupt happened.
196 */
197 hadintr++;
198 collabort();
199 fputs("Interrupt\n", stderr(&__sF[2]));
200 goto err;
201 case 'x':
202 /*
203 * Force a quit of sending mail.
204 * Do not save the message.
205 */
206 goto err;
207 case 'h':
208 /*
209 * Grab a bunch of headers.
210 */
211 grabh(hp, GTO1|GSUBJECT2|GCC4|GBCC8);
212 goto cont;
213 case 't':
214 /*
215 * Add to the To list.
216 */
217 hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO1));
218 break;
219 case 's':
220 /*
221 * Set the Subject list.
222 */
223 cp = &linebuf[2];
224 while (isspace((unsigned char)*cp))
225 cp++;
226 hp->h_subject = savestr(cp);
227 break;
228 case 'c':
229 /*
230 * Add to the CC list.
231 */
232 hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC4));
233 break;
234 case 'b':
235 /*
236 * Add stuff to blind carbon copies list.
237 */
238 hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC8));
239 break;
240 case 'd':
241 linebuf[2] = '\0';
242 strlcat(linebuf, getdeadletter(), sizeof(linebuf));
243 /* fall into . . . */
244 case 'r':
245 case '<':
246 /*
247 * Invoke a file:
248 * Search for the file name,
249 * then open it and copy the contents to collf.
250 */
251 cp = &linebuf[2];
252 while (isspace((unsigned char)*cp))
253 cp++;
254 if (*cp == '\0') {
255 puts("Interpolate what file?");
256 break;
257 }
258 cp = expand(cp);
259 if (cp == NULL((void *)0))
260 break;
261 if (isdir(cp)) {
262 printf("%s: Directory\n", cp);
263 break;
264 }
265 if ((fbuf = Fopen(cp, "r")) == NULL((void *)0)) {
266 warn("%s", cp);
267 break;
268 }
269 printf("\"%s\" ", cp);
270 fflush(stdout(&__sF[1]));
271 lc = 0;
272 cc = 0;
273 while ((rc = readline(fbuf, linebuf, LINESIZE1024, NULL((void *)0))) >= 0) {
274 if (rc != LINESIZE1024 - 1)
275 lc++;
276 if ((t = putline(collf, linebuf,
277 rc != LINESIZE1024-1)) < 0) {
278 (void)Fclose(fbuf);
279 goto err;
280 }
281 cc += t;
282 }
283 (void)Fclose(fbuf);
284 printf("%d/%d\n", lc, cc);
285 break;
286 case 'w':
287 /*
288 * Write the message on a file.
289 */
290 cp = &linebuf[2];
291 while (*cp == ' ' || *cp == '\t')
292 cp++;
293 if (*cp == '\0') {
294 fputs("Write what file!?\n", stderr(&__sF[2]));
295 break;
296 }
297 if ((cp = expand(cp)) == NULL((void *)0))
298 break;
299 rewind(collf);
300 exwrite(cp, collf, 1);
301 break;
302 case 'm':
303 case 'M':
304 case 'f':
305 case 'F':
306 /*
307 * Interpolate the named messages, if we
308 * are in receiving mail mode. Does the
309 * standard list processing garbage.
310 * If ~f is given, we don't shift over.
311 */
312 if (forward(linebuf + 2, collf, tempname, c) < 0)
313 goto err;
314 goto cont;
315 case '?':
316 if ((fbuf = Fopen(_PATH_TILDE"/usr/share/misc/mail.tildehelp", "r")) == NULL((void *)0)) {
317 warn(_PATH_TILDE"/usr/share/misc/mail.tildehelp");
318 break;
319 }
320 while ((t = getc(fbuf)(!__isthreaded ? (--(fbuf)->_r < 0 ? __srget(fbuf) : (int
)(*(fbuf)->_p++)) : (getc)(fbuf))
) != EOF(-1))
321 (void)putchar(t)(!__isthreaded ? __sputc(t, (&__sF[1])) : (putc)(t, (&
__sF[1])))
;
322 (void)Fclose(fbuf);
323 break;
324 case 'p':
325 /*
326 * Print out the current state of the
327 * message without altering anything.
328 */
329 rewind(collf);
330 puts("-------\nMessage contains:");
331 puthead(hp, stdout(&__sF[1]), GTO1|GSUBJECT2|GCC4|GBCC8|GNL16);
332 while ((t = getc(collf)(!__isthreaded ? (--(collf)->_r < 0 ? __srget(collf) : (
int)(*(collf)->_p++)) : (getc)(collf))
) != EOF(-1))
333 (void)putchar(t)(!__isthreaded ? __sputc(t, (&__sF[1])) : (putc)(t, (&
__sF[1])))
;
334 goto cont;
335 case '|':
336 /*
337 * Pipe message through command.
338 * Collect output as new message.
339 */
340 rewind(collf);
341 mespipe(collf, &linebuf[2]);
342 goto cont;
343 case 'v':
344 case 'e':
345 /*
346 * Edit the current message.
347 * 'e' means to use EDITOR
348 * 'v' means to use VISUAL
349 */
350 rewind(collf);
351 mesedit(collf, c);
352 goto cont;
353 }
354 }
355
356 if (value("interactive") != NULL((void *)0)) {
357 if (value("askcc") != NULL((void *)0) || value("askbcc") != NULL((void *)0)) {
358 if (value("askcc") != NULL((void *)0)) {
359 if (gethfromtty(hp, GCC4) == -1)
360 goto err;
361 }
362 if (value("askbcc") != NULL((void *)0)) {
363 if (gethfromtty(hp, GBCC8) == -1)
364 goto err;
365 }
366 } else {
367 puts("EOT");
368 (void)fflush(stdout(&__sF[1]));
369 }
370 }
371 goto out;
372err:
373 if (collf != NULL((void *)0)) {
374 (void)Fclose(collf);
375 collf = NULL((void *)0);
376 }
377out:
378 if (collf != NULL((void *)0))
379 rewind(collf);
380 noreset--;
381 return(collf);
382}
383
384/*
385 * Write a file, ex-like if f set.
386 */
387int
388exwrite(char *name, FILE *fp, int f)
389{
390 FILE *of;
391 int c;
392 ssize_t cc, lc;
393 struct stat junk;
394
395 if (f) {
396 printf("\"%s\" ", name);
397 fflush(stdout(&__sF[1]));
398 }
399 if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)((junk.st_mode & 0170000) == 0100000)) {
400 if (!f)
401 fprintf(stderr(&__sF[2]), "%s: ", name);
402 fputs("File exists\n", stderr(&__sF[2]));
403 return(-1);
404 }
405 if ((of = Fopen(name, "w")) == NULL((void *)0)) {
406 warn(NULL((void *)0));
407 return(-1);
408 }
409 lc = 0;
410 cc = 0;
411 while ((c = getc(fp)(!__isthreaded ? (--(fp)->_r < 0 ? __srget(fp) : (int)(
*(fp)->_p++)) : (getc)(fp))
) != EOF(-1)) {
412 cc++;
413 if (c == '\n')
414 lc++;
415 (void)putc(c, of)(!__isthreaded ? __sputc(c, of) : (putc)(c, of));
416 if (ferror(of)(!__isthreaded ? (((of)->_flags & 0x0040) != 0) : (ferror
)(of))
) {
417 warn("%s", name);
418 (void)Fclose(of);
419 return(-1);
420 }
421 }
422 (void)Fclose(of);
423 printf("%lld/%lld\n", (long long)lc, (long long)cc);
424 fflush(stdout(&__sF[1]));
425 return(0);
426}
427
428/*
429 * Edit the message being collected on fp.
430 * On return, make the edit file the new temp file.
431 */
432void
433mesedit(FILE *fp, int c)
434{
435 FILE *nf;
436 struct sigaction oact;
437 sigset_t oset;
438
439 (void)ignoresig(SIGINT2, &oact, &oset);
440 nf = run_editor(fp, (off_t)-1, c, 0);
441 if (nf != NULL((void *)0)) {
442 fseek(nf, 0L, SEEK_END2);
443 collf = nf;
444 (void)Fclose(fp);
445 }
446 (void)sigprocmask(SIG_SETMASK3, &oset, NULL((void *)0));
447 (void)sigaction(SIGINT2, &oact, NULL((void *)0));
448}
449
450/*
451 * Pipe the message through the command.
452 * Old message is on stdin of command;
453 * New message collected from stdout.
454 * Sh -c must return 0 to accept the new message.
455 */
456void
457mespipe(FILE *fp, char *cmd)
458{
459 FILE *nf;
460 int fd;
461 char *shell, tempname[PATHSIZE1024];
462 struct sigaction oact;
463 sigset_t oset;
464
465 (void)ignoresig(SIGINT2, &oact, &oset);
466 (void)snprintf(tempname, sizeof(tempname),
467 "%s/mail.ReXXXXXXXXXX", tmpdir);
468 if ((fd = mkstemp(tempname)) == -1 ||
469 (nf = Fdopen(fd, "w+")) == NULL((void *)0)) {
470 warn("%s", tempname);
471 goto out;
472 }
473 (void)rm(tempname);
474 /*
475 * stdin = current message.
476 * stdout = new message.
477 */
478 shell = value("SHELL");
479 if (run_command(shell,
480 0, fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), fileno(nf)(!__isthreaded ? ((nf)->_file) : (fileno)(nf)), "-c", cmd, NULL((void *)0)) < 0) {
481 (void)Fclose(nf);
482 goto out;
483 }
484 if (fsize(nf) == 0) {
485 fprintf(stderr(&__sF[2]), "No bytes from \"%s\" !?\n", cmd);
486 (void)Fclose(nf);
487 goto out;
488 }
489 /*
490 * Take new files.
491 */
492 (void)fseek(nf, 0L, SEEK_END2);
493 collf = nf;
494 (void)Fclose(fp);
495out:
496 (void)sigprocmask(SIG_SETMASK3, &oset, NULL((void *)0));
497 (void)sigaction(SIGINT2, &oact, NULL((void *)0));
498}
499
500/*
501 * Interpolate the named messages into the current
502 * message, preceding each line with a tab.
503 * Return a count of the number of characters now in
504 * the message, or -1 if an error is encountered writing
505 * the message temporary. The flag argument is 'm' if we
506 * should shift over and 'f' if not.
507 */
508int
509forward(char *ms, FILE *fp, char *fn, int f)
510{
511 int *msgvec;
512 struct ignoretab *ig;
513 char *tabst;
514
515 msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec));
516 if (msgvec == NULL((void *)0))
517 return(0);
518 if (getmsglist(ms, msgvec, 0) < 0)
519 return(0);
520 if (*msgvec == 0) {
521 *msgvec = first(0, MMNORM((1<<1)|(1<<2)));
522 if (*msgvec == 0) {
523 puts("No appropriate messages");
524 return(0);
525 }
526 msgvec[1] = 0;
527 }
528 if (tolower(f) == 'f')
529 tabst = NULL((void *)0);
530 else if ((tabst = value("indentprefix")) == NULL((void *)0))
531 tabst = "\t";
532 ig = isupper(f) ? NULL((void *)0) : ignore;
533 fputs("Interpolating:", stdout(&__sF[1]));
534 for (; *msgvec != 0; msgvec++) {
535 struct message *mp = message + *msgvec - 1;
536
537 touch(mp);
538 printf(" %d", *msgvec);
539 if (sendmessage(mp, fp, ig, tabst) < 0) {
540 warn("%s", fn);
541 return(-1);
542 }
543 }
544 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
545 return(0);
546}
547
548/*
549 * User aborted during message composition.
550 * Save the partial message in ~/dead.letter.
551 */
552int
553collabort(void)
554{
555 /*
556 * the control flow is subtle, because we can be called from ~q.
557 */
558 if (hadintr == 0 && isatty(0)) {
559 if (value("ignore") != NULL((void *)0)) {
560 puts("@");
561 fflush(stdout(&__sF[1]));
562 clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~
(0x0040|0x0020))) : (clearerr)((&__sF[0])))
;
563 } else {
564 fflush(stdout(&__sF[1]));
565 fputs("\n(Interrupt -- one more to kill letter)\n",
566 stderr(&__sF[2]));
567 hadintr++;
568 }
569 return(0);
570 }
571 fflush(stdout(&__sF[1]));
572 rewind(collf);
573 if (value("nosave") == NULL((void *)0))
574 savedeadletter(collf);
575 return(1);
576}
577
578void
579savedeadletter(FILE *fp)
580{
581 FILE *dbuf;
582 int c;
583 char *cp;
584
585 if (fsize(fp) == 0)
586 return;
587 cp = getdeadletter();
588 c = umask(077);
589 dbuf = Fopen(cp, "a");
590 (void)umask(c);
591 if (dbuf == NULL((void *)0))
592 return;
593 while ((c = getc(fp)(!__isthreaded ? (--(fp)->_r < 0 ? __srget(fp) : (int)(
*(fp)->_p++)) : (getc)(fp))
) != EOF(-1))
594 (void)putc(c, dbuf)(!__isthreaded ? __sputc(c, dbuf) : (putc)(c, dbuf));
595 (void)Fclose(dbuf);
596 rewind(fp);
597}
598
599int
600gethfromtty(struct header *hp, int gflags)
601{
602
603 hadintr = 0;
604 while (grabh(hp, gflags) != 0) {
605 if (collabort())
606 return(-1);
607 }
608 return(0);
609}