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