1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
3 *
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * Copyright (c) 1980, 1993
8 * The Regents of the University of California. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 #ifdef DOSCCS
41 static char sccsid[] = "@(#)aux.c 2.83 (gritter) 3/4/06";
42 #endif
43 #endif /* not lint */
44
45 #include "rcv.h"
46 #include "extern.h"
47 #include <sys/stat.h>
48 #include <utime.h>
49 #include <time.h>
50 #include <termios.h>
51 #include <ctype.h>
52 #ifdef HAVE_WCTYPE_H
53 #include <wctype.h>
54 #endif /* HAVE_WCTYPE_H */
55 #ifdef HAVE_WCWIDTH
56 #include <wchar.h>
57 #endif /* HAVE_WCWIDTH */
58 #include <errno.h>
59 #include <sys/stat.h>
60 #include <unistd.h>
61 #include <time.h>
62 #include <dirent.h>
63 #include <fcntl.h>
64 #include <limits.h>
65
66 #include "md5.h"
67
68 /*
69 * Mail -- a mail program
70 *
71 * Auxiliary functions.
72 */
73
74 /*
75 * Return a pointer to a dynamic copy of the argument.
76 */
77 char *
savestr(const char * str)78 savestr(const char *str)
79 {
80 char *new;
81 int size = strlen(str) + 1;
82
83 if ((new = salloc(size)) != NULL)
84 memcpy(new, str, size);
85 return new;
86 }
87
88 /*
89 * Make a copy of new argument incorporating old one.
90 */
91 char *
save2str(const char * str,const char * old)92 save2str(const char *str, const char *old)
93 {
94 char *new;
95 int newsize = strlen(str) + 1;
96 int oldsize = old ? strlen(old) + 1 : 0;
97
98 if ((new = salloc(newsize + oldsize)) != NULL) {
99 if (oldsize) {
100 memcpy(new, old, oldsize);
101 new[oldsize - 1] = ' ';
102 }
103 memcpy(new + oldsize, str, newsize);
104 }
105 return new;
106 }
107
108 char *
savecat(const char * s1,const char * s2)109 savecat(const char *s1, const char *s2)
110 {
111 const char *cp;
112 char *ns, *np;
113
114 np = ns = salloc(strlen(s1) + strlen(s2) + 1);
115 for (cp = s1; *cp; cp++)
116 *np++ = *cp;
117 for (cp = s2; *cp; cp++)
118 *np++ = *cp;
119 *np = '\0';
120 return ns;
121 }
122
123 #include <stdarg.h>
124
125 #ifndef HAVE_SNPRINTF
126 /*
127 * Lazy vsprintf wrapper.
128 */
129 int
snprintf(char * str,size_t size,const char * format,...)130 snprintf(char *str, size_t size, const char *format, ...)
131 {
132 va_list ap;
133 int ret;
134
135 va_start(ap, format);
136 ret = vsprintf(str, format, ap);
137 va_end(ap);
138 return ret;
139 }
140 #endif /* !HAVE_SNPRINTF */
141
142 /*
143 * Announce a fatal error and die.
144 */
145 void
panic(const char * format,...)146 panic(const char *format, ...)
147 {
148 va_list ap;
149
150 va_start(ap, format);
151 fprintf(stderr, catgets(catd, CATSET, 1, "panic: "));
152 vfprintf(stderr, format, ap);
153 va_end(ap);
154 fprintf(stderr, catgets(catd, CATSET, 2, "\n"));
155 fflush(stderr);
156 abort();
157 }
158
159 void
holdint(void)160 holdint(void)
161 {
162 sigset_t set;
163
164 sigemptyset(&set);
165 sigaddset(&set, SIGINT);
166 sigprocmask(SIG_BLOCK, &set, NULL);
167 }
168
169 void
relseint(void)170 relseint(void)
171 {
172 sigset_t set;
173
174 sigemptyset(&set);
175 sigaddset(&set, SIGINT);
176 sigprocmask(SIG_UNBLOCK, &set, NULL);
177 }
178
179 /*
180 * Touch the named message by setting its MTOUCH flag.
181 * Touched messages have the effect of not being sent
182 * back to the system mailbox on exit.
183 */
184 void
touch(struct message * mp)185 touch(struct message *mp)
186 {
187
188 mp->m_flag |= MTOUCH;
189 if ((mp->m_flag & MREAD) == 0)
190 mp->m_flag |= MREAD|MSTATUS;
191 }
192
193 /*
194 * Test to see if the passed file name is a directory.
195 * Return true if it is.
196 */
197 int
is_dir(char * name)198 is_dir(char *name)
199 {
200 struct stat sbuf;
201
202 if (stat(name, &sbuf) < 0)
203 return(0);
204 return(S_ISDIR(sbuf.st_mode));
205 }
206
207 /*
208 * Count the number of arguments in the given string raw list.
209 */
210 int
argcount(char ** argv)211 argcount(char **argv)
212 {
213 char **ap;
214
215 for (ap = argv; *ap++ != NULL;)
216 ;
217 return ap - argv - 1;
218 }
219
220 /*
221 * Copy a string, lowercasing it as we go.
222 */
223 void
i_strcpy(char * dest,const char * src,int size)224 i_strcpy(char *dest, const char *src, int size)
225 {
226 char *max;
227
228 max=dest+size-1;
229 while (dest<=max) {
230 *dest++ = lowerconv(*src & 0377);
231 if (*src++ == '\0')
232 break;
233 }
234 }
235
236 char *
i_strdup(const char * src)237 i_strdup(const char *src)
238 {
239 int sz;
240 char *dest;
241
242 sz = strlen(src) + 1;
243 dest = salloc(sz);
244 i_strcpy(dest, src, sz);
245 return dest;
246 }
247
248 /*
249 * Convert a string to lowercase, in-place and with multibyte-aware.
250 */
251 void
makelow(char * cp)252 makelow(char *cp)
253 {
254 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
255 if (mb_cur_max > 1) {
256 char *tp = cp;
257 wchar_t wc;
258 int len;
259
260 while (*cp) {
261 len = mbtowc(&wc, cp, mb_cur_max);
262 if (len < 0)
263 *tp++ = *cp++;
264 else {
265 wc = towlower(wc);
266 if (wctomb(tp, wc) == len)
267 tp += len, cp += len;
268 else
269 *tp++ = *cp++;
270 }
271 }
272 } else
273 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
274 {
275 do
276 *cp = tolower(*cp & 0377);
277 while (*cp++);
278 }
279 }
280
281 int
substr(const char * str,const char * sub)282 substr(const char *str, const char *sub)
283 {
284 const char *cp, *backup;
285
286 cp = sub;
287 backup = str;
288 while (*str && *cp) {
289 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
290 if (mb_cur_max > 1) {
291 wchar_t c, c2;
292 int sz;
293
294 if ((sz = mbtowc(&c, cp, mb_cur_max)) < 0)
295 goto singlebyte;
296 cp += sz;
297 if ((sz = mbtowc(&c2, str, mb_cur_max)) < 0)
298 goto singlebyte;
299 str += sz;
300 c = towupper(c);
301 c2 = towupper(c2);
302 if (c != c2) {
303 if ((sz = mbtowc(&c, backup, mb_cur_max)) > 0) {
304 backup += sz;
305 str = backup;
306 } else
307 str = ++backup;
308 cp = sub;
309 }
310 } else
311 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
312 {
313 int c, c2;
314
315 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
316 singlebyte:
317 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
318 c = *cp++ & 0377;
319 if (islower(c))
320 c = toupper(c);
321 c2 = *str++ & 0377;
322 if (islower(c2))
323 c2 = toupper(c2);
324 if (c != c2) {
325 str = ++backup;
326 cp = sub;
327 }
328 }
329 }
330 return *cp == '\0';
331 }
332
333 char *
colalign(const char * cp,int col,int fill)334 colalign(const char *cp, int col, int fill)
335 {
336 int n, sz;
337 char *nb, *np;
338
339 np = nb = salloc(mb_cur_max * strlen(cp) + col + 1);
340 while (*cp) {
341 #if defined (HAVE_MBTOWC) && defined (HAVE_WCWIDTH)
342 if (mb_cur_max > 1) {
343 wchar_t wc;
344
345 if ((sz = mbtowc(&wc, cp, mb_cur_max)) < 0) {
346 n = sz = 1;
347 } else {
348 if ((n = wcwidth(wc)) < 0)
349 n = 1;
350 }
351 } else
352 #endif /* HAVE_MBTOWC && HAVE_WCWIDTH */
353 {
354 n = sz = 1;
355 }
356 if (n > col)
357 break;
358 col -= n;
359 if (sz == 1 && spacechar(*cp&0377)) {
360 *np++ = ' ';
361 cp++;
362 } else
363 while (sz--)
364 *np++ = *cp++;
365 }
366 if (fill)
367 while (col-- > 0)
368 *np++ = ' ';
369 *np = '\0';
370 return nb;
371 }
372
373 void
try_pager(FILE * fp)374 try_pager(FILE *fp)
375 {
376 long lines = 0;
377 int c;
378 char *cp;
379
380 fflush(fp);
381 rewind(fp);
382 while ((c = getc(fp)) != EOF)
383 if (c == '\n')
384 lines++;
385 rewind(fp);
386 if (is_a_tty[0] && is_a_tty[1] && (cp = value("crt")) != NULL &&
387 lines > (*cp ? atol(cp) : scrnheight))
388 run_command(get_pager(), 0, fileno(fp), -1, NULL, NULL, NULL);
389 else
390 while ((c = getc(fp)) != EOF)
391 putchar(c);
392 }
393
394 /*
395 * The following code deals with input stacking to do source
396 * commands. All but the current file pointer are saved on
397 * the stack.
398 */
399
400 static int ssp; /* Top of file stack */
401 struct sstack {
402 FILE *s_file; /* File we were in. */
403 enum condition s_cond; /* Saved state of conditionals */
404 int s_loading; /* Loading .mailrc, etc. */
405 #define SSTACK 20
406 } sstack[SSTACK];
407
408 /*
409 * Pushdown current input file and switch to a new one.
410 * Set the global flag "sourcing" so that others will realize
411 * that they are no longer reading from a tty (in all probability).
412 */
413 int
source(void * v)414 source(void *v)
415 {
416 char **arglist = v;
417 FILE *fi;
418 char *cp;
419
420 if ((cp = expand(*arglist)) == NULL)
421 return(1);
422 if ((fi = Fopen(cp, "r")) == NULL) {
423 perror(cp);
424 return(1);
425 }
426 if (ssp >= SSTACK - 1) {
427 printf(catgets(catd, CATSET, 3,
428 "Too much \"sourcing\" going on.\n"));
429 Fclose(fi);
430 return(1);
431 }
432 sstack[ssp].s_file = input;
433 sstack[ssp].s_cond = cond;
434 sstack[ssp].s_loading = loading;
435 ssp++;
436 loading = 0;
437 cond = CANY;
438 input = fi;
439 sourcing++;
440 return(0);
441 }
442
443 /*
444 * Pop the current input back to the previous level.
445 * Update the "sourcing" flag as appropriate.
446 */
447 int
unstack(void)448 unstack(void)
449 {
450 if (ssp <= 0) {
451 printf(catgets(catd, CATSET, 4,
452 "\"Source\" stack over-pop.\n"));
453 sourcing = 0;
454 return(1);
455 }
456 Fclose(input);
457 if (cond != CANY)
458 printf(catgets(catd, CATSET, 5, "Unmatched \"if\"\n"));
459 ssp--;
460 cond = sstack[ssp].s_cond;
461 loading = sstack[ssp].s_loading;
462 input = sstack[ssp].s_file;
463 if (ssp == 0)
464 sourcing = loading;
465 return(0);
466 }
467
468 /*
469 * Touch the indicated file.
470 * This is nifty for the shell.
471 */
472 void
alter(char * name)473 alter(char *name)
474 {
475 struct stat sb;
476 struct utimbuf utb;
477
478 if (stat(name, &sb))
479 return;
480 utb.actime = time((time_t *)0) + 1;
481 utb.modtime = sb.st_mtime;
482 utime(name, &utb);
483 }
484
485 /*
486 * Examine the passed line buffer and
487 * return true if it is all blanks and tabs.
488 */
489 int
blankline(char * linebuf)490 blankline(char *linebuf)
491 {
492 char *cp;
493
494 for (cp = linebuf; *cp; cp++)
495 if (!blankchar(*cp & 0377))
496 return(0);
497 return(1);
498 }
499
500 /*
501 * Are any of the characters in the two strings the same?
502 */
503 int
anyof(char * s1,char * s2)504 anyof(char *s1, char *s2)
505 {
506
507 while (*s1)
508 if (strchr(s2, *s1++))
509 return 1;
510 return 0;
511 }
512
513 /*
514 * Determine if as1 is a valid prefix of as2.
515 * Return true if yep.
516 */
517 int
is_prefix(const char * as1,const char * as2)518 is_prefix(const char *as1, const char *as2)
519 {
520 const char *s1, *s2;
521
522 s1 = as1;
523 s2 = as2;
524 while (*s1++ == *s2)
525 if (*s2++ == '\0')
526 return(1);
527 return(*--s1 == '\0');
528 }
529
530 char *
last_at_before_slash(const char * sp)531 last_at_before_slash(const char *sp)
532 {
533 const char *cp;
534
535 for (cp = sp; *cp; cp++)
536 if (*cp == '/')
537 break;
538 while (cp > sp && *--cp != '@');
539 return *cp == '@' ? (char *)cp : NULL;
540 }
541
542 enum protocol
which_protocol(const char * name)543 which_protocol(const char *name)
544 {
545 register const char *cp;
546 char *np;
547 size_t sz;
548 struct stat st;
549 enum protocol p;
550
551 if (name[0] == '%' && name[1] == ':')
552 name += 2;
553 for (cp = name; *cp && *cp != ':'; cp++)
554 if (!alnumchar(*cp&0377))
555 goto file;
556 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
557 if (strncmp(name, "pop3://", 7) == 0)
558 return PROTO_POP3;
559 if (strncmp(name, "pop3s://", 8) == 0)
560 #ifdef USE_SSL
561 return PROTO_POP3;
562 #else /* !USE_SSL */
563 fprintf(stderr, catgets(catd, CATSET, 225,
564 "No SSL support compiled in.\n"));
565 #endif /* !USE_SSL */
566 if (strncmp(name, "imap://", 7) == 0)
567 return PROTO_IMAP;
568 if (strncmp(name, "imaps://", 8) == 0)
569 #ifdef USE_SSL
570 return PROTO_IMAP;
571 #else /* !USE_SSL */
572 fprintf(stderr, catgets(catd, CATSET, 225,
573 "No SSL support compiled in.\n"));
574 #endif /* !USE_SSL */
575 return PROTO_UNKNOWN;
576 } else {
577 file: p = PROTO_FILE;
578 np = ac_alloc((sz = strlen(name)) + 5);
579 strcpy(np, name);
580 if (stat(name, &st) == 0) {
581 if (S_ISDIR(st.st_mode)) {
582 strcpy(&np[sz], "/tmp");
583 if (stat(np, &st) == 0 && S_ISDIR(st.st_mode)) {
584 strcpy(&np[sz], "/new");
585 if (stat(np, &st) == 0 &&
586 S_ISDIR(st.st_mode)) {
587 strcpy(&np[sz], "/cur");
588 if (stat(np, &st) == 0 &&
589 S_ISDIR(st.st_mode))
590 p = PROTO_MAILDIR;
591 }
592 }
593 }
594 } else {
595 strcpy(&np[sz], ".gz");
596 if (stat(np, &st) < 0) {
597 strcpy(&np[sz], ".bz2");
598 if (stat(np, &st) < 0) {
599 if ((cp = value("newfolders")) != 0 &&
600 strcmp(cp, "maildir") == 0)
601 p = PROTO_MAILDIR;
602 }
603 }
604 }
605 ac_free(np);
606 return p;
607 }
608 }
609
610 const char *
protfile(const char * xcp)611 protfile(const char *xcp)
612 {
613 const char *cp = xcp;
614 int state = 0;
615
616 while (*cp) {
617 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
618 cp += 3;
619 state = 1;
620 }
621 if (cp[0] == '/' && state == 1)
622 return &cp[1];
623 if (cp[0] == '/')
624 return xcp;
625 cp++;
626 }
627 return cp;
628 }
629
630 char *
protbase(const char * cp)631 protbase(const char *cp)
632 {
633 char *n = salloc(strlen(cp) + 1);
634 char *np = n;
635
636 while (*cp) {
637 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
638 *np++ = *cp++;
639 *np++ = *cp++;
640 *np++ = *cp++;
641 } else if (cp[0] == '/')
642 break;
643 else
644 *np++ = *cp++;
645 }
646 *np = '\0';
647 return n;
648 }
649
650 int
disconnected(const char * file)651 disconnected(const char *file)
652 {
653 char *cp, *cq, *vp;
654 int vs, r;
655
656 if (value("disconnected"))
657 return 1;
658 cp = protbase(file);
659 if (strncmp(cp, "imap://", 7) == 0)
660 cp += 7;
661 else if (strncmp(cp, "imaps://", 8) == 0)
662 cp += 8;
663 else
664 return 0;
665 if ((cq = strchr(cp, ':')) != NULL)
666 *cq = '\0';
667 vp = ac_alloc(vs = strlen(cp) + 14);
668 snprintf(vp, vs, "disconnected-%s", cp);
669 r = value(vp) != NULL;
670 ac_free(vp);
671 return r;
672 }
673
674 unsigned
pjw(const char * cp)675 pjw(const char *cp)
676 {
677 unsigned h = 0, g;
678
679 cp--;
680 while (*++cp) {
681 h = (h << 4 & 0xffffffff) + (*cp&0377);
682 if ((g = h & 0xf0000000) != 0) {
683 h = h ^ g >> 24;
684 h = h ^ g;
685 }
686 }
687 return h;
688 }
689
690 long
nextprime(long n)691 nextprime(long n)
692 {
693 const long primes[] = {
694 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
695 131071, 262139, 524287, 1048573, 2097143, 4194301,
696 8388593, 16777213, 33554393, 67108859, 134217689,
697 268435399, 536870909, 1073741789, 2147483647
698 };
699 long mprime = 7;
700 int i;
701
702 for (i = 0; i < sizeof primes / sizeof *primes; i++)
703 if ((mprime = primes[i]) >= (n < 65536 ? n*4 :
704 n < 262144 ? n*2 : n))
705 break;
706 if (i == sizeof primes / sizeof *primes)
707 mprime = n; /* not so prime, but better than failure */
708 return mprime;
709 }
710
711 #define Hexchar(n) ((n)>9 ? (n)-10+'A' : (n)+'0')
712 #define hexchar(n) ((n)>9 ? (n)-10+'a' : (n)+'0')
713
714 char *
strenc(const char * cp)715 strenc(const char *cp)
716 {
717 char *n, *np;
718
719 np = n = salloc(strlen(cp) * 3 + 1);
720 while (*cp) {
721 if (alnumchar(*cp&0377) || *cp == '_' || *cp == '@' ||
722 (np > n && (*cp == '.' || *cp == '-' ||
723 *cp == ':')))
724 *np++ = *cp;
725 else {
726 *np++ = '%';
727 *np++ = Hexchar((*cp&0xf0) >> 4);
728 *np++ = Hexchar(*cp&0x0f);
729 }
730 cp++;
731 }
732 *np = '\0';
733 return n;
734 }
735
736 char *
strdec(const char * cp)737 strdec(const char *cp)
738 {
739 char *n, *np;
740
741 np = n = salloc(strlen(cp) + 1);
742 while (*cp) {
743 if (cp[0] == '%' && cp[1] && cp[2]) {
744 *np = (int)(cp[1]>'9'?cp[1]-'A'+10:cp[1]-'0') << 4;
745 *np++ |= cp[2]>'9'?cp[2]-'A'+10:cp[2]-'0';
746 cp += 3;
747 } else
748 *np++ = *cp++;
749 }
750 *np = '\0';
751 return n;
752 }
753
754 char *
md5tohex(const void * vp)755 md5tohex(const void *vp)
756 {
757 char *hex;
758 const char *cp = vp;
759 int i;
760
761 hex = salloc(33);
762 for (i = 0; i < 16; i++) {
763 hex[2*i] = hexchar((cp[i]&0xf0) >> 4);
764 hex[2*i+1] = hexchar(cp[i]&0x0f);
765 }
766 hex[32] = '\0';
767 return hex;
768 }
769
770 char *
cram_md5_string(const char * user,const char * pass,const char * b64)771 cram_md5_string(const char *user, const char *pass, const char *b64)
772 {
773 struct str in, out;
774 char digest[16], *cp, *sp, *rp, *xp;
775 int ss, rs;
776
777 in.s = (char *)b64;
778 in.l = strlen(in.s);
779 mime_fromb64(&in, &out, 0);
780 hmac_md5((unsigned char *)out.s, out.l,
781 (unsigned char *)pass, strlen(pass),
782 digest);
783 free(out.s);
784 xp = md5tohex(digest);
785 sp = ac_alloc(ss = strlen(user) + strlen(xp) + 2);
786 snprintf(sp, ss, "%s %s", user, xp);
787 cp = strtob64(sp);
788 ac_free(sp);
789 rp = salloc(rs = strlen(cp) + 3);
790 snprintf(rp, rs, "%s\r\n", cp);
791 free(cp);
792 return rp;
793 }
794
795 char *
getuser(void)796 getuser(void)
797 {
798 char *line = NULL, *user;
799 size_t linesize = 0;
800
801 if (is_a_tty[0]) {
802 fputs("User: ", stdout);
803 fflush(stdout);
804 }
805 if (readline(stdin, &line, &linesize) == 0) {
806 if (line)
807 free(line);
808 return NULL;
809 }
810 user = savestr(line);
811 free(line);
812 return user;
813 }
814
815 char *
getpassword(struct termios * otio,int * reset_tio,const char * query)816 getpassword(struct termios *otio, int *reset_tio, const char *query)
817 {
818 struct termios tio;
819 char *line = NULL, *pass;
820 size_t linesize = 0;
821 int i;
822
823 if (is_a_tty[0]) {
824 fputs(query ? query : "Password:", stdout);
825 fflush(stdout);
826 tcgetattr(0, &tio);
827 *otio = tio;
828 tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
829 *reset_tio = 1;
830 tcsetattr(0, TCSAFLUSH, &tio);
831 }
832 i = readline(stdin, &line, &linesize);
833 if (is_a_tty[0]) {
834 fputc('\n', stdout);
835 tcsetattr(0, TCSADRAIN, otio);
836 }
837 *reset_tio = 0;
838 if (i < 0) {
839 if (line)
840 free(line);
841 return NULL;
842 }
843 pass = savestr(line);
844 free(line);
845 return pass;
846 }
847
848 void
transflags(struct message * omessage,long omsgCount,int transparent)849 transflags(struct message *omessage, long omsgCount, int transparent)
850 {
851 struct message *omp, *nmp, *newdot, *newprevdot;
852 int hf;
853
854 omp = omessage;
855 nmp = message;
856 newdot = message;
857 newprevdot = NULL;
858 while (omp < &omessage[omsgCount] &&
859 nmp < &message[msgCount]) {
860 if (dot && nmp->m_uid == dot->m_uid)
861 newdot = nmp;
862 if (prevdot && nmp->m_uid == prevdot->m_uid)
863 newprevdot = nmp;
864 if (omp->m_uid == nmp->m_uid) {
865 hf = nmp->m_flag & MHIDDEN;
866 if (transparent && mb.mb_type == MB_IMAP)
867 omp->m_flag &= ~MHIDDEN;
868 *nmp++ = *omp++;
869 if (transparent && mb.mb_type == MB_CACHE)
870 nmp[-1].m_flag |= hf;
871 } else if (omp->m_uid < nmp->m_uid)
872 omp++;
873 else
874 nmp++;
875 }
876 dot = newdot;
877 setdot(newdot);
878 prevdot = newprevdot;
879 free(omessage);
880 }
881
882 char *
getrandstring(size_t length)883 getrandstring(size_t length)
884 {
885 static unsigned char nodedigest[16];
886 static pid_t pid;
887 int i, fd = -1;
888 char *data;
889 char *cp, *rp;
890 MD5_CTX ctx;
891
892 data = salloc(length);
893 if ((fd = open("/dev/urandom", O_RDONLY)) < 0 ||
894 read(fd, data, length) != length) {
895 if (pid == 0) {
896 pid = getpid();
897 srand(pid);
898 cp = nodename(0);
899 MD5Init(&ctx);
900 MD5Update(&ctx, (unsigned char *)cp, strlen(cp));
901 MD5Final(nodedigest, &ctx);
902 }
903 for (i = 0; i < length; i++)
904 data[i] = (int)(255 * (rand() / (RAND_MAX + 1.0))) ^
905 nodedigest[i % sizeof nodedigest];
906 }
907 if (fd > 0)
908 close(fd);
909 cp = memtob64(data, length);
910 rp = salloc(length+1);
911 strncpy(rp, cp, length)[length] = '\0';
912 free(cp);
913 return rp;
914 }
915
916 void
out_of_memory(void)917 out_of_memory(void)
918 {
919 panic("no memory");
920 }
921
922 void *
smalloc(size_t s)923 smalloc(size_t s)
924 {
925 void *p;
926
927 if (s == 0)
928 s = 1;
929 if ((p = malloc(s)) == NULL)
930 out_of_memory();
931 return p;
932 }
933
934 void *
srealloc(void * v,size_t s)935 srealloc(void *v, size_t s)
936 {
937 void *r;
938
939 if (s == 0)
940 s = 1;
941 if (v == NULL)
942 return smalloc(s);
943 if ((r = realloc(v, s)) == NULL)
944 out_of_memory();
945 return r;
946 }
947
948 void *
scalloc(size_t nmemb,size_t size)949 scalloc(size_t nmemb, size_t size)
950 {
951 void *vp;
952
953 if (size == 0)
954 size = 1;
955 if ((vp = calloc(nmemb, size)) == NULL)
956 out_of_memory();
957 return vp;
958 }
959
960 char *
sstpcpy(char * dst,const char * src)961 sstpcpy(char *dst, const char *src)
962 {
963 while ((*dst = *src++) != '\0')
964 dst++;
965 return dst;
966 }
967
968 char *
sstrdup(const char * cp)969 sstrdup(const char *cp)
970 {
971 char *dp;
972
973 if (cp) {
974 dp = smalloc(strlen(cp) + 1);
975 strcpy(dp, cp);
976 return dp;
977 } else
978 return NULL;
979 }
980
981 enum okay
makedir(const char * name)982 makedir(const char *name)
983 {
984 int e;
985 struct stat st;
986
987 if (mkdir(name, 0700) < 0) {
988 e = errno;
989 if ((e == EEXIST || e == ENOSYS) &&
990 stat(name, &st) == 0 &&
991 (st.st_mode&S_IFMT) == S_IFDIR)
992 return OKAY;
993 return STOP;
994 }
995 return OKAY;
996 }
997
998 #ifdef HAVE_FCHDIR
999 enum okay
cwget(struct cw * cw)1000 cwget(struct cw *cw)
1001 {
1002 if ((cw->cw_fd = open(".", O_RDONLY)) < 0)
1003 return STOP;
1004 if (fchdir(cw->cw_fd) < 0) {
1005 close(cw->cw_fd);
1006 return STOP;
1007 }
1008 return OKAY;
1009 }
1010
1011 enum okay
cwret(struct cw * cw)1012 cwret(struct cw *cw)
1013 {
1014 if (fchdir(cw->cw_fd) < 0)
1015 return STOP;
1016 return OKAY;
1017 }
1018
1019 void
cwrelse(struct cw * cw)1020 cwrelse(struct cw *cw)
1021 {
1022 close(cw->cw_fd);
1023 }
1024 #else /* !HAVE_FCHDIR */
1025 enum okay
cwget(struct cw * cw)1026 cwget(struct cw *cw)
1027 {
1028 if (getcwd(cw->cw_wd, sizeof cw->cw_wd) == NULL || chdir(cw->cw_wd) < 0)
1029 return STOP;
1030 return OKAY;
1031 }
1032
1033 enum okay
cwret(struct cw * cw)1034 cwret(struct cw *cw)
1035 {
1036 if (chdir(cw->cw_wd) < 0)
1037 return STOP;
1038 return OKAY;
1039 }
1040
1041 /*ARGSUSED*/
1042 void
cwrelse(struct cw * cw)1043 cwrelse(struct cw *cw)
1044 {
1045 }
1046 #endif /* !HAVE_FCHDIR */
1047
1048 void
makeprint(struct str * in,struct str * out)1049 makeprint(struct str *in, struct str *out)
1050 {
1051 static int print_all_chars = -1;
1052 char *inp, *outp;
1053 size_t msz, dist;
1054
1055 out->s = smalloc(msz = in->l + 1);
1056 if (print_all_chars == -1)
1057 print_all_chars = value("print-all-chars") != NULL;
1058 if (print_all_chars) {
1059 memcpy(out->s, in->s, in->l);
1060 out->l = in->l;
1061 out->s[out->l] = '\0';
1062 return;
1063 }
1064 inp = in->s;
1065 outp = out->s;
1066 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
1067 if (mb_cur_max > 1) {
1068 wchar_t wc;
1069 char mb[MB_LEN_MAX+1];
1070 int i, n;
1071 out->l = 0;
1072 while (inp < &in->s[in->l]) {
1073 if (*inp & 0200)
1074 n = mbtowc(&wc, inp, &in->s[in->l] - inp);
1075 else {
1076 wc = *inp;
1077 n = 1;
1078 }
1079 if (n < 0) {
1080 mbtowc(&wc, NULL, mb_cur_max);
1081 wc = utf8 ? 0xFFFD : '?';
1082 n = 1;
1083 } else if (n == 0)
1084 n = 1;
1085 inp += n;
1086 if (!iswprint(wc) && wc != '\n' && wc != '\r' &&
1087 wc != '\b' && wc != '\t') {
1088 if ((wc & ~(wchar_t)037) == 0)
1089 wc = utf8 ? 0x2400 | wc : '?';
1090 else if (wc == 0177)
1091 wc = utf8 ? 0x2421 : '?';
1092 else
1093 wc = utf8 ? 0x2426 : '?';
1094 }
1095 if ((n = wctomb(mb, wc)) <= 0)
1096 continue;
1097 out->l += n;
1098 if (out->l >= msz - 1) {
1099 dist = outp - out->s;
1100 out->s = srealloc(out->s, msz += 32);
1101 outp = &out->s[dist];
1102 }
1103 for (i = 0; i < n; i++)
1104 *outp++ = mb[i];
1105 }
1106 } else
1107 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
1108 {
1109 int c;
1110 while (inp < &in->s[in->l]) {
1111 c = *inp++ & 0377;
1112 if (!isprint(c) && c != '\n' && c != '\r' &&
1113 c != '\b' && c != '\t')
1114 c = '?';
1115 *outp++ = c;
1116 }
1117 out->l = in->l;
1118 }
1119 out->s[out->l] = '\0';
1120 }
1121
1122 char *
prstr(const char * s)1123 prstr(const char *s)
1124 {
1125 struct str in, out;
1126 char *rp;
1127
1128 in.s = (char *)s;
1129 in.l = strlen(s);
1130 makeprint(&in, &out);
1131 rp = salloc(out.l + 1);
1132 memcpy(rp, out.s, out.l);
1133 rp[out.l] = '\0';
1134 free(out.s);
1135 return rp;
1136 }
1137
1138 int
prout(const char * s,size_t sz,FILE * fp)1139 prout(const char *s, size_t sz, FILE *fp)
1140 {
1141 struct str in, out;
1142 int n;
1143
1144 in.s = (char *)s;
1145 in.l = sz;
1146 makeprint(&in, &out);
1147 n = fwrite(out.s, 1, out.l, fp);
1148 free(out.s);
1149 return n;
1150 }
1151
1152 /*
1153 * Print out a Unicode character or a substitute for it.
1154 */
1155 int
putuc(int u,int c,FILE * fp)1156 putuc(int u, int c, FILE *fp)
1157 {
1158 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
1159 if (utf8 && u & ~(wchar_t)0177) {
1160 char mb[MB_LEN_MAX];
1161 int i, n, r = 0;
1162 if ((n = wctomb(mb, u)) > 0) {
1163 for (i = 0; i < n; i++)
1164 r += putc(mb[i] & 0377, fp) != EOF;
1165 return r;
1166 } else if (n == 0)
1167 return putc('\0', fp) != EOF;
1168 else
1169 return 0;
1170 } else
1171 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
1172 return putc(c, fp) != EOF;
1173 }
1174
1175 /*
1176 * Locale-independent character class functions.
1177 */
1178 int
asccasecmp(const char * s1,const char * s2)1179 asccasecmp(const char *s1, const char *s2)
1180 {
1181 register int cmp;
1182
1183 do
1184 if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
1185 return cmp;
1186 while (*s1++ != '\0' && *s2++ != '\0');
1187 return 0;
1188 }
1189
1190 int
ascncasecmp(const char * s1,const char * s2,size_t sz)1191 ascncasecmp(const char *s1, const char *s2, size_t sz)
1192 {
1193 register int cmp;
1194 size_t i = 1;
1195
1196 if (sz == 0)
1197 return 0;
1198 do
1199 if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
1200 return cmp;
1201 while (i++ < sz && *s1++ != '\0' && *s2++ != '\0');
1202 return 0;
1203 }
1204
1205 char *
asccasestr(const char * haystack,const char * xneedle)1206 asccasestr(const char *haystack, const char *xneedle)
1207 {
1208 char *needle, *NEEDLE;
1209 int i, sz;
1210
1211 sz = strlen(xneedle);
1212 if (sz == 0)
1213 return (char *)haystack;
1214 needle = ac_alloc(sz);
1215 NEEDLE = ac_alloc(sz);
1216 for (i = 0; i < sz; i++) {
1217 needle[i] = lowerconv(xneedle[i]&0377);
1218 NEEDLE[i] = upperconv(xneedle[i]&0377);
1219 }
1220 while (*haystack) {
1221 if (*haystack == *needle || *haystack == *NEEDLE) {
1222 for (i = 1; i < sz; i++)
1223 if (haystack[i] != needle[i] &&
1224 haystack[i] != NEEDLE[i])
1225 break;
1226 if (i == sz)
1227 return (char *)haystack;
1228 }
1229 haystack++;
1230 }
1231 return NULL;
1232 }
1233
1234 const unsigned char class_char[] = {
1235 /* 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel */
1236 C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
1237 /* 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si */
1238 C_CNTRL,C_BLANK,C_WHITE,C_SPACE,C_SPACE,C_SPACE,C_CNTRL,C_CNTRL,
1239 /* 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb */
1240 C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
1241 /* 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us */
1242 C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
1243 /* 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' */
1244 C_BLANK,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1245 /* 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / */
1246 C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1247 /* 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 */
1248 C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,
1249 /* 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? */
1250 C_DIGIT,C_DIGIT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1251 /* 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G */
1252 C_PUNCT,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
1253 /* 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O */
1254 C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
1255 /* 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W */
1256 C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
1257 /* 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ */
1258 C_UPPER,C_UPPER,C_UPPER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1259 /* 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g */
1260 C_PUNCT,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
1261 /* 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o */
1262 C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
1263 /* 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w */
1264 C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
1265 /* 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del */
1266 C_LOWER,C_LOWER,C_LOWER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_CNTRL
1267 };
1268