1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1998-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *               Glenn Fowler <glenn.s.fowler@gmail.com>                *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * Glenn Fowler
23  * AT&T Research
24  *
25  * uuencode/uudecode methods
26  */
27 
28 static char id[] = "\n@(#)$Id: uulib (AT&T Research) 2003-01-07 $\0\n";
29 
30 static const char lib[] = "libuu:uu";
31 
32 #include "uulib.h"
33 
34 #include <ctype.h>
35 #include <error.h>
36 #include <ls.h>
37 #include <modex.h>
38 #include <sfdisc.h>
39 
40 #define UU_BEGIN	"begin"
41 #define UU_BEGIN_LEN	(sizeof(UU_BEGIN)-1)
42 
43 #define UUIN		3
44 #define UUOUT		4
45 #define UUCHUNK		15
46 #define UULINE		76
47 
48 #define UU_END	(UCHAR_MAX)
49 #define UU_IGN	(UCHAR_MAX-1)
50 #define UU_PAD	(UCHAR_MAX-2)
51 
52 typedef struct
53 {
54 	const char*	name;
55 	unsigned long	flag;
56 } Option_t;
57 
58 static const Option_t	options[] =
59 {
60 	"text",		UU_TEXT,
61 };
62 
63 /*
64  * initialize the uu map from dp
65  */
66 
67 static unsigned char*
uu_map(register Uudata_t * dp,char * map)68 uu_map(register Uudata_t* dp, char* map)
69 {
70 	register int		c;
71 	register char*		p;
72 	register unsigned char*	m;
73 	int			x;
74 
75 	x = (dp->flags & UU_LENGTH) ? 0 : UU_IGN;
76 	p = map;
77 	memset(p, x, UCHAR_MAX + 2);
78 	if (x)
79 	{
80 		p++;
81 		p[dp->pad] = UU_PAD;
82 		p[EOF] = UU_END;
83 	}
84 	for (m = (unsigned char*)dp->map; c = *m; m++)
85 		p[c] =  m - (unsigned char*)dp->map;
86 	return (unsigned char*)p;
87 }
88 
89 /*
90  * grab uu header from input
91  */
92 
93 static int
uu_header(register Uu_t * uu)94 uu_header(register Uu_t* uu)
95 {
96 	register char*	s;
97 	register int	c;
98 	int		n;
99 	int		k;
100 	Uumeth_t*	meth;
101 	char*		t;
102 
103 	c = *UU_BEGIN;
104 	for (;;)
105 	{
106 		if (!(s = sfgetr(uu->ip, '\n', 1)))
107 		{
108 			if (uu->disc->errorf)
109 				(*uu->disc->errorf)(uu, uu->disc, 2, "unknown encoding");
110 			break;
111 		}
112 		if (*s == c && !strncasecmp(s, UU_BEGIN, UU_BEGIN_LEN) && (meth = uumeth(s)))
113 		{
114 			s += UU_BEGIN_LEN + strlen(meth->id);
115 			while (*s == '-')
116 			{
117 				for (t = ++s; isalnum(*s); s++);
118 				k = s - t;
119 				for (n = 0; n < elementsof(options); n++)
120 					if (strlen(options[n].name) == k && !strncasecmp(options[n].name, t, k))
121 					{
122 						uu->flags |= options[n].flag;
123 						break;
124 					}
125 			}
126 			if (*s++ == ' ')
127 			{
128 				uu->mode = strperm(s, &t, 0) & ~(S_IXUSR|S_IXGRP|S_IXOTH);
129 				if (*t++ == ' ')
130 				{
131 					if (!uu->path)
132 					{
133 						uu->path = strdup(t);
134 						uu->flags |= UU_FREEPATH;
135 					}
136 					if (meth->name != uu->meth.name)
137 					{
138 						if (!(((Uudata_t*)uu->meth.data)->flags & UU_DEFAULT) && !streq(meth->id, uu->meth.id) && uu->disc->errorf)
139 							(*uu->disc->errorf)(uu, uu->disc, 1, "switching to %s encoding", meth->name);
140 						uu->meth = *meth;
141 					}
142 					return 0;
143 				}
144 			}
145 		}
146 	}
147 	return -1;
148 }
149 
150 /*
151  * uu encode input to output
152  */
153 
154 static int
uu_encode(register Uu_t * uu)155 uu_encode(register Uu_t* uu)
156 {
157 	register char*		e;
158 	register char*		p;
159 	register unsigned char*	m;
160 	register int		c;
161 	register int		c1;
162 	register int		c2;
163 	register int		c3;
164 	register unsigned long	b;
165 	int			length;
166 	int			nl;
167 	int			pad;
168 	int			text;
169 	Uudata_t*		dp;
170 	struct stat		st;
171 	char			buf[UUOUT * (UUCHUNK + 1)];
172 
173 	dp = (Uudata_t*)uu->meth.data;
174 	m = (unsigned char*)dp->map;
175 	length = !!(dp->flags & UU_LENGTH);
176 	text = !!(uu->flags & UU_TEXT);
177 	pad = dp->pad;
178 	if (uu->flags & UU_HEADER)
179 	{
180 		if (fstat(sffileno(uu->ip), &st) || !(c = modex(st.st_mode) & 0777))
181 			c = 0644;
182 		sfprintf(uu->op, "%s%s%s %03o %s\n", UU_BEGIN, uu->meth.id, text ? "-text" : "", c, uu->path ? uu->path : "-");
183 	}
184 	if (length)
185 		*buf = m[UUIN * UUCHUNK];
186 	p = buf + length;
187 	e = p + UUOUT * UUCHUNK;
188 	nl = 0;
189 	for (;;)
190 	{
191 		do {
192 			if (nl)
193 			{
194 				nl = 0;
195 				c1 = '\n';
196 				goto get_2;
197 			}
198 			if ((c1 = sfgetc(uu->ip)) == EOF)
199 			{
200 				if (length)
201 					*buf = m[((p - buf - length) / UUOUT) * UUIN];
202 				goto eof;
203 			}
204 			if (text && c1 == '\n')
205 			{
206 				c1 = '\r';
207 				c2 = '\n';
208 				goto get_3;
209 			}
210  get_2:
211 			if ((c2 = sfgetc(uu->ip)) == EOF)
212 			{
213 				if (length)
214 					*buf = m[((p - buf - length) / UUOUT) * UUIN + 1];
215 				c2 = dp->fill;
216 				c3 = dp->fill;
217 				b = (c1 << 16) | (c2 << 8) | c3;
218 				*p++ = m[b >> 18];
219 				*p++ = m[(b >> 12) & 077];
220 				*p++ = pad ? pad : m[(b >> 6) & 077];
221 				*p++ = pad ? pad : m[b & 077];
222 				goto eof;
223 			}
224 			if (text && c2 == '\n')
225 			{
226 				c2 = '\r';
227 				c3 = '\n';
228 				goto put_123;
229 			}
230  get_3:
231 			if ((c3 = sfgetc(uu->ip)) == EOF)
232 			{
233 				if (length)
234 					*buf = m[((p - buf - length) / UUOUT) * UUIN + 2];
235 				c3 = dp->fill;
236 				b = (c1 << 16) | (c2 << 8) | c3;
237 				*p++ = m[b >> 18];
238 				*p++ = m[(b >> 12) & 077];
239 				*p++ = m[(b >> 6) & 077];
240 				*p++ = pad ? pad : m[b & 077];
241 				goto eof;
242 			}
243 			if (text && c3 == '\n')
244 			{
245 				nl = 1;
246 				c3 = '\r';
247 			}
248  put_123:
249 			b = (c1 << 16) | (c2 << 8) | c3;
250 			*p++ = m[b >> 18];
251 			*p++ = m[(b >> 12) & 077];
252 			*p++ = m[(b >> 6) & 077];
253 			*p++ = m[b & 077];
254 		} while (p < e);
255 		*p++ = '\n';
256 		sfwrite(uu->op, buf, p - buf);
257 		p = buf + length;
258 	}
259  eof:
260 	if (p > buf + length)
261 	{
262 		*p++ = '\n';
263 		sfwrite(uu->op, buf, p - buf);
264 	}
265 	if (length)
266 		sfprintf(uu->op, "%c\n", m[0]);
267 	if (uu->flags & UU_HEADER)
268 		sfputr(uu->op, dp->end, '\n');
269 	return 0;
270 }
271 
272 /*
273  * uu decode input to output
274  */
275 
276 static int
uu_decode(register Uu_t * uu)277 uu_decode(register Uu_t* uu)
278 {
279 	register Uudata_t*	dp;
280 	register char*		s;
281 	register char*		e;
282 	register char*		p;
283 	register unsigned char*	m;
284 	register int		c;
285 	register unsigned long	n;
286 	int			text;
287 	int			tl;
288 	int			x;
289 	char*			t;
290 	char			buf[UUIN * UUCHUNK + 1];
291 	char			map[UCHAR_MAX + 2];
292 
293 	dp = (Uudata_t*)uu->meth.data;
294 	if (uu->path && (uu->flags & UU_CLOSEOUT) && (dp->flags & uu->flags & UU_HEADER) && chmod(uu->path, uu->mode) && uu->disc->errorf)
295 		(*uu->disc->errorf)(uu, uu->disc, ERROR_SYSTEM|2, "%s: cannot change mode to %s", uu->path, fmtperm(uu->mode));
296 	text = !!(uu->flags & UU_TEXT);
297 	m = uu_map(dp, map);
298 	if (dp->flags & UU_LENGTH)
299 	{
300 		t = (char*)dp->end;
301 		tl = strlen(t) + 1;
302 		while (((s = sfgetr(uu->ip, '\n', 0)) || (s = sfgetr(uu->ip, '\n', -1))) && ((n = sfvalue(uu->ip)) != tl || !strneq(s, t, tl - 1)))
303 			if (c = m[*((unsigned char*)s++)])
304 			{
305 				if (c > sizeof(buf))
306 				{
307 					if (uu->disc->errorf)
308 						(*uu->disc->errorf)(uu, uu->disc, 2, "input is not %s encoded", uu->meth.name);
309 					return -1;
310 				}
311 				p = buf;
312 				e = s + (c + UUIN - 1) / UUIN * UUOUT;
313 				while (s < e)
314 				{
315 					n = m[*((unsigned char*)s++)];
316 					n = (n << 6) | ((s < e) ? m[*((unsigned char*)s++)] : 0);
317 					n = (n << 6) | ((s < e) ? m[*((unsigned char*)s++)] : 0);
318 					n = (n << 6) | ((s < e) ? m[*((unsigned char*)s++)] : 0);
319 					if (text)
320 					{
321 						if ((x = (n >> 16) & 0xFF) == '\r')
322 							c--;
323 						else
324 							*p++ = x;
325 						if ((x = (n >> 8) & 0xFF) == '\r')
326 							c--;
327 						else
328 							*p++ = x;
329 						if ((x = n & 0xFF) == '\r')
330 							c--;
331 						else
332 							*p++ = x;
333 					}
334 					else
335 					{
336 						*p++ = (n >> 16);
337 						*p++ = (n >> 8);
338 						*p++ = n;
339 					}
340 				}
341 				sfwrite(uu->op, buf, c);
342 			}
343 		if (!s && (uu->flags & UU_HEADER) && uu->disc->errorf)
344 			(*uu->disc->errorf)(uu, uu->disc, 1, "end sequence `%s' omitted", t);
345 	}
346 	else
347 	{
348 		for (;;)
349 		{
350 			while ((c = m[sfgetc(uu->ip)]) >= 64)
351 				if (c != UU_IGN)
352 					goto pad;
353 			n = c;
354 			while ((c = m[sfgetc(uu->ip)]) >= 64)
355 				if (c != UU_IGN)
356 				{
357 					if (uu->disc->errorf)
358 						(*uu->disc->errorf)(uu, uu->disc, 1, "%c: extra input character ignored", c);
359 					goto pad;
360 				}
361 			n = (n << 6) | c;
362 			while ((c = m[sfgetc(uu->ip)]) >= 64)
363 				if (c != UU_IGN)
364 				{
365 					if (text)
366 					{
367 						if ((x = (n >> 4) & 0xFF) != '\r')
368 							sfputc(uu->op, x);
369 					}
370 					else sfputc(uu->op, n >> 4);
371 					goto pad;
372 				}
373 			n = (n << 6) | c;
374 			while ((c = m[sfgetc(uu->ip)]) >= 64)
375 				if (c != UU_IGN)
376 				{
377 					if (text)
378 					{
379 						if ((x = (n >> 10) & 0xFF) != '\r')
380 							sfputc(uu->op, x);
381 						if ((x = (n >> 2) & 0xFF) != '\r')
382 							sfputc(uu->op, x);
383 					}
384 					else
385 					{
386 						sfputc(uu->op, n >> 10);
387 						sfputc(uu->op, n >> 2);
388 					}
389 					goto pad;
390 				}
391 			n = (n << 6) | c;
392 			if (text)
393 			{
394 				if ((x = (n >> 16) & 0xFF) != '\r')
395 					sfputc(uu->op, x);
396 				if ((x = (n >> 8) & 0xFF) != '\r')
397 					sfputc(uu->op, x);
398 				if ((x = n & 0xFF) != '\r')
399 					sfputc(uu->op, x);
400 			}
401 			else
402 			{
403 				sfputc(uu->op, (n >> 16));
404 				sfputc(uu->op, (n >> 8));
405 				sfputc(uu->op, (n));
406 			}
407 		}
408 	pad:
409 		n = c == UU_PAD;
410 		while ((c = sfgetc(uu->ip)) != EOF)
411 			if (c == dp->pad && ++n >= 4)
412 				break;
413 		if (n < 4 && (uu->flags & UU_HEADER) && uu->disc->errorf)
414 			(*uu->disc->errorf)(uu, uu->disc, 1, "input end sequence `%s' omitted", dp->end);
415 	}
416 	return 0;
417 }
418 
419 static const char	hex[] = "0123456789ABCDEFabcdef";
420 
421 /*
422  * quoted-printable encode input to output
423  */
424 
425 static int
qp_encode(register Uu_t * uu)426 qp_encode(register Uu_t* uu)
427 {
428 	register unsigned char*	s;
429 	register unsigned char*	e;
430 	register char*		b;
431 	register char*		x;
432 	register int		c;
433 	char			buf[UULINE + 1];
434 
435 	b = buf;
436 	x = b + UULINE - 4;
437 	while ((s = (unsigned char*)sfgetr(uu->ip, '\n', 0)) || (s = (unsigned char*)sfgetr(uu->ip, '\n', -1)))
438 	{
439 		e = s + sfvalue(uu->ip);
440 		switch (*s)
441 		{
442 		case 'F':
443 			if ((e - s) >= 5 && strneq((char*)s, "From ", 5))
444 			{
445 				c = *s++;
446 				goto quote;
447 			}
448 			break;
449 		case '.':
450 			if ((e - s) == 2)
451 			{
452 				c = *s++;
453 				goto quote;
454 			}
455 			break;
456 		}
457 		while (s < e)
458 		{
459 			if ((c = *s++) == '\n')
460 			{
461 				*b++ = c;
462 				sfwrite(uu->op, buf, b - buf);
463 				b = buf;
464 				break;
465 			}
466 			if (b >= x)
467 			{
468 				*b++ = '=';
469 				*b++ = '\n';
470 				sfwrite(uu->op, buf, b - buf);
471 				b = buf;
472 			}
473 			if (c == ' ' || c == '\t')
474 			{
475 				if (s < e && *s != '\n')
476 				{
477 					*b++ = c;
478 					continue;
479 				}
480 			}
481 			else if (isprint(c) && !iscntrl(c) && c != '=')
482 			{
483 				*b++ = c;
484 				continue;
485 			}
486 		quote:
487 			*b++ = '=';
488 			*b++ = hex[(c >> 4) & 0xF];
489 			*b++ = hex[c & 0xF];
490 		}
491 	}
492 	if (b > buf)
493 	{
494 		*b++ = '=';
495 		*b++ = '\n';
496 		sfwrite(uu->op, buf, b - buf);
497 	}
498 	return 0;
499 }
500 
501 /*
502  * quoted-printable decode input to output
503  */
504 
505 static int
qp_decode(register Uu_t * uu)506 qp_decode(register Uu_t* uu)
507 {
508 	register unsigned char*	s;
509 	register unsigned char*	b;
510 	register unsigned char*	x;
511 	register int		c;
512 	register int		d;
513 
514 	short			xeh[UCHAR_MAX + 1];
515 
516 	for (c = 0; c < elementsof(xeh); c++)
517 		xeh[c] = -1;
518 	for (c = 0; c < elementsof(hex) - 1; c++)
519 		xeh[hex[c]] = c >= 16 ? (c - 6) : c;
520 	while (s = (unsigned char*)sfgetr(uu->ip, '\n', 1))
521 	{
522 		if (((b = s + sfvalue(uu->ip)) > s) && !*--b)
523 		{
524 			while (b > s && ((c = *(b - 1)) == ' ' || c == '\t'))
525 				b--;
526 			*b = 0;
527 		}
528 		x = b = s;
529 		for (;;)
530 		{
531 			switch (c = *s++)
532 			{
533 			case 0:
534 				*b++ = '\n';
535 				break;
536 			case '=':
537 				if ((c = xeh[*s++]) < 0 || (d = xeh[*s++]) < 0)
538 					break;
539 				*b++ = (c << 4) | d;
540 				continue;
541 			default:
542 				*b++ = c;
543 				continue;
544 			}
545 			break;
546 		}
547 		sfwrite(uu->op, x, b - x);
548 	}
549 	return 0;
550 }
551 
552 /*
553  * binhex based on
554  *
555  *	xbin Version 2.3 09/30/85
556  *	Dave Johnson, Brown University Computer Science
557  */
558 
559 #define BX_REPEAT	0x90
560 
561 #define BX_OLD		(UU_METHOD<<0)
562 
563 typedef struct
564 {
565 	int		col;
566 	int		eof;
567 	int		last;
568 	int		repeat;
569 	off_t		size;
570 	unsigned long	crc;
571 	unsigned char*	qp;
572 	unsigned char*	qe;
573 	unsigned char	qbuf[3];
574 	char		map[UCHAR_MAX + 2];
575 } Bx_t;
576 
577 /*
578  * add c to the binhex Q format crc
579  */
580 
581 static int
bx_q_crc(register Bx_t * bx,int c)582 bx_q_crc(register Bx_t* bx, int c)
583 {
584 	register int		i = 8;
585 	register unsigned int	k = c;
586 	register unsigned long	crc = bx->crc;
587 
588 	while (i--)
589 	{
590 		k <<= 1;
591 		if ((crc <<= 1) & 0x10000)
592 			crc = (crc & 0xFFFF) ^ 0x1021;
593 		crc ^= k >> 8;
594 		k &= 0xFF;
595 	}
596 	bx->crc = crc;
597 	return c;
598 }
599 
600 /*
601  * return next binhex Q format char
602  */
603 
604 static int
bx_q_getc(register Uu_t * uu,register Bx_t * bx)605 bx_q_getc(register Uu_t* uu, register Bx_t* bx)
606 {
607 	register int		c;
608 	register unsigned char*	ip;
609 	register unsigned char*	ie;
610 	register unsigned char*	m;
611 	int			x;
612 	unsigned long		crc;
613 	unsigned char		ibuf[4];
614 
615 	if (bx->repeat > 0)
616 	{
617 		bx->repeat--;
618 		return bx_q_crc(bx, bx->last);
619 	}
620 	if (bx->qp >= bx->qe)
621 	{
622 		if (bx->eof)
623 			return EOF;
624 		bx->qp = bx->qbuf;
625 		m = (unsigned char*)bx->map + 1;
626 		ie = (ip = ibuf) + sizeof(ibuf);
627 		while (ip < ie)
628 		{
629 			while ((c = m[sfgetc(uu->ip)]) >= 64)
630 				if (c != UU_IGN)
631 				{
632 					bx->eof = 1;
633 					bx->qe = bx->qbuf;
634 					if ((c = (ip - ibuf) - 1) <= 0)
635 						return EOF;
636 					bx->qe += c;
637 					break;
638 				}
639 			*ip++ = c;
640 		}
641 		ip = ibuf;
642 		ie = bx->qp;
643 		ie[0] = (ip[0] << 2) | (ip[1] >> 4);
644 		ie[1] = (ip[1] << 4) | (ip[2] >> 2);
645 		ie[2] = (ip[2] << 6) | (ip[3]     );
646 	}
647 	if ((c = *bx->qp++) == BX_REPEAT && !bx->repeat)
648 	{
649 		c = bx->last;
650 		crc = bx->crc;
651 		bx->repeat = -1;
652 		x = bx_q_getc(uu, bx);
653 		bx->crc = crc;
654 		switch (x)
655 		{
656 		case EOF:
657 			return EOF;
658 		case 0:
659 			bx->repeat = 0;
660 			c = BX_REPEAT;
661 			break;
662 		case 1:
663 			bx->repeat = 0;
664 			break;
665 		default:
666 			bx->repeat = x - 2;
667 			break;
668 		}
669 	}
670 	return bx->last = bx_q_crc(bx, c);
671 }
672 
673 /*
674  * return binhex Q format n byte int
675  */
676 
677 static long
bx_q_getn(register Uu_t * uu,register Bx_t * bx,register int n)678 bx_q_getn(register Uu_t* uu, register Bx_t* bx, register int n)
679 {
680 	register long	v = 0;
681 
682 	while (n--)
683 		v = (v << 8) | bx_q_getc(uu, bx);
684 	return v;
685 }
686 
687 /*
688  * return binhex Q format buffer of size n
689  */
690 
691 static ssize_t
bx_q_gets(register Uu_t * uu,register Bx_t * bx,register char * s,size_t n)692 bx_q_gets(register Uu_t* uu, register Bx_t* bx, register char* s, size_t n)
693 {
694 	register int	c;
695 	register char*	e;
696 
697 	e = s + n;
698 	while (s < e)
699 	{
700 		if ((c = bx_q_getc(uu, bx)) == EOF)
701 			return -1;
702 		*s++ = c;
703 	}
704 	return n;
705 }
706 
707 /*
708  * low level for bx_q_putc()
709  */
710 
711 static int
bx_q_put(register Uu_t * uu,register Bx_t * bx,register int c)712 bx_q_put(register Uu_t* uu, register Bx_t* bx, register int c)
713 {
714 	register unsigned char*	p;
715 	register unsigned char*	m;
716 
717 	*bx->qp++ = c;
718 	if (bx->qp >= bx->qe)
719 	{
720 		m = (unsigned char*)((Uudata_t*)uu->meth.data)->map;
721 		p = bx->qp = bx->qbuf;
722 		c = (p[0] << 16) | (p[1] << 8) | p[2];
723 		sfputc(uu->op, m[(c >> 18) & 0x3f]);
724 		sfputc(uu->op, m[(c >> 12) & 0x3f]);
725 		sfputc(uu->op, m[(c >>  6) & 0x3f]);
726 		sfputc(uu->op, m[(c      ) & 0x3f]);
727 		if ((bx->col += 4) >= 63)
728 		{
729 			bx->col = 0;
730 			sfputc(uu->op, '\n');
731 		}
732 	}
733 	return 0;
734 }
735 
736 /*
737  * output binhex Q format char
738  */
739 
740 static int
bx_q_putc(register Uu_t * uu,register Bx_t * bx,register int c)741 bx_q_putc(register Uu_t* uu, register Bx_t* bx, register int c)
742 {
743 	if (c == bx->last)
744 	{
745 		if (!bx->repeat++)
746 		{
747 			bx_q_put(uu, bx, c);
748 			bx_q_put(uu, bx, BX_REPEAT);
749 		}
750 		bx_q_crc(bx, c);
751 		if (bx->repeat >= 0xFF)
752 		{
753 			bx_q_put(uu, bx, bx->repeat);
754 			bx->repeat = 0;
755 			bx->last = -1;
756 		}
757 	}
758 	else
759 	{
760 		if (bx->repeat)
761 		{
762 			bx_q_put(uu, bx, bx->repeat);
763 			bx->repeat = 0;
764 			bx->last = -1;
765 		}
766 		if (c == BX_REPEAT)
767 		{
768 			bx_q_put(uu, bx, c);
769 			bx_q_put(uu, bx, 0);
770 			bx->last = -1;
771 		}
772 		else if (c == '\n' && (uu->flags & UU_TEXT))
773 		{
774 			bx_q_put(uu, bx, '\r');
775 			bx_q_crc(bx, '\r');
776 			bx_q_put(uu, bx, '\n');
777 			bx->last = -1;
778 		}
779 		else
780 		{
781 			bx_q_put(uu, bx, c);
782 			bx->last = c;
783 		}
784 		bx_q_crc(bx, c);
785 	}
786 	return 0;
787 }
788 
789 /*
790  * output binhex Q format n byte int
791  */
792 
793 static int
bx_q_putn(register Uu_t * uu,register Bx_t * bx,register unsigned long v,int n)794 bx_q_putn(register Uu_t* uu, register Bx_t* bx, register unsigned long v, int n)
795 {
796 	switch (n)
797 	{
798 	case 4:	bx_q_putc(uu, bx, (v >> 24) & 0xFF);
799 	case 3:	bx_q_putc(uu, bx, (v >> 16) & 0xFF);
800 	case 2:	bx_q_putc(uu, bx, (v >>  8) & 0xFF);
801 	case 1:	bx_q_putc(uu, bx, (v >>  0) & 0xFF);
802 	}
803 	return 0;
804 }
805 
806 /*
807  * grab binhex header from input
808  */
809 
810 static int
bx_header(register Uu_t * uu)811 bx_header(register Uu_t* uu)
812 {
813 	register Bx_t*	bx = (Bx_t*)(uu + 1);
814 	Uudata_t*	dp = (Uudata_t*)uu->meth.data;
815 	register int	c;
816 	register int	bol;
817 	register char*	s;
818 	register char*	m;
819 	unsigned long	crc;
820 	unsigned long	crx;
821 	char		buf[UCHAR_MAX + 2];
822 
823 	if (uu->flags & UU_HEADER)
824 		do
825 		{
826 			if (!(s = sfgetr(uu->ip, '\n', 0)))
827 			{
828 				if (uu->disc->errorf)
829 					(*uu->disc->errorf)(uu, uu->disc, 2, "unknown encoding");
830 				return -1;
831 			}
832 		} while (*s != '(' || strncmp(s, "(This file", 10));
833 	bol = 1;
834 	for (;;)
835 	{
836 		switch (c = sfgetc(uu->ip))
837 		{
838 		case EOF:
839 			return -1;
840 		case '\n':
841 		case '\r':
842 			bol = 1;
843 			break;
844 		case ':':
845 			if (bol)
846 			{
847 				/*
848 				 * Q format
849 				 *
850 				 *	1 n name length
851 				 *	n s name
852 				 *	4 s type
853 				 *	4 s author
854 				 *	2 n flags
855 				 *	4 n data size
856 				 *	4 n resource size
857 				 *	2 n header checksum
858 				 */
859 
860 				memset(s = bx->map, UU_END, sizeof(bx->map));
861 				for (s++, m = (char*)dp->map; c = *m; m++)
862 					s[c] =  m - (char*)dp->map;
863 				s['\n'] = UU_IGN;
864 				s['\r'] = UU_IGN;
865 				bx->qp = bx->qe = bx->qbuf + sizeof(bx->qbuf);
866 				if ((c = bx_q_getc(uu, bx)) == EOF)
867 					return -1;
868 				if (bx_q_gets(uu, bx, buf, c + 1) < 0)
869 					return -1;
870 				if (!uu->path)
871 				{
872 					uu->path = strdup(buf);
873 					uu->flags |= UU_FREEPATH;
874 				}
875 				if (bx_q_gets(uu, bx, buf, 4) < 0)
876 					return -1;
877 				if (bx_q_gets(uu, bx, buf, 4) < 0)
878 					return -1;
879 				bx_q_getn(uu, bx, 2);
880 				bx->size = bx_q_getn(uu, bx, 4);
881 				bx_q_getn(uu, bx, 4);
882 				bx_q_crc(bx, 0);
883 				bx_q_crc(bx, 0);
884 				crc = bx->crc;
885 				crx = bx_q_getn(uu, bx, 2);
886 				if (crc != crx)
887 				{
888 					if (uu->disc->errorf)
889 						(*uu->disc->errorf)(uu, uu->disc, 2, "%s format header checksum mismatch", uu->meth.name);
890 					return -1;
891 				}
892 				return 0;
893 			}
894 			break;
895 		case '#':
896 			if (bol)
897 			{
898 				/*
899 				 * old format
900 				 */
901 
902 				sfungetc(uu->ip, c);
903 				uu->flags |= BX_OLD;
904 
905 				/*
906 				 * #<TYPE><AUTH>$<flag>
907 				 */
908 
909 				if (!sfgetr(uu->ip, '\n', 0))
910 					return -1;
911 				return 0;
912 			}
913 			break;
914 		default:
915 			bol = 0;
916 			break;
917 		}
918 	}
919 }
920 
921 /*
922  * old binhex line decode
923  */
924 
925 static int
bx_o_decode(register Uu_t * uu,Bx_t * bx,char * buf,register size_t n)926 bx_o_decode(register Uu_t* uu, Bx_t* bx, char* buf, register size_t n)
927 {
928 	register int		c;
929 	register int		d;
930 	register unsigned long	crc = bx->crc;
931 	register unsigned char*	m = (unsigned char*)bx->map;
932 	register char*		t = (char*)hex;
933 	register unsigned char*	s = (unsigned char*)buf;
934 
935 	memset(m, UU_END, sizeof(bx->map));
936 	for (c = 0; c < elementsof(hex); c++)
937 		m[t[c]] = c;
938 	n <= 2;
939 	while (n--)
940 	{
941 		if ((c = m[*s++]) == UU_END || (d = m[*s++]) == UU_END)
942 			return -1;
943 		crc += c = (c << 4) | d;
944 		sfputc(uu->op, c);
945 	}
946 	bx->crc = crc;
947 	return 0;
948 }
949 
950 /*
951  * old binhex compressed line decode
952  */
953 
954 #define BX_O_MASK(c)	(((c)-0x20)&0x3F)
955 #define BX_O_CRC(s,c)	((s=(s+c)&0xFF),(s=((s<<3)&0xFF)|(s>>13)))
956 
957 static int
bx_c_decode(register Uu_t * uu,Bx_t * bx,register char * s,size_t n)958 bx_c_decode(register Uu_t* uu, Bx_t* bx, register char* s, size_t n)
959 {
960 	register int		c;
961 	register int		oc;
962 	register unsigned long	crc;
963 	char*			e;
964 	int			ic;
965 	char			buf[SF_BUFSIZE];
966 
967 	crc = bx->crc;
968 	oc = (BX_O_MASK(s[0]) << 2) | (BX_O_MASK(s[1]) >> 4);
969 	ic = ((oc / 3) + 1) * 4;
970 	if (ic > SF_BUFSIZE)
971 		ic = SF_BUFSIZE;
972 	if (n > SF_BUFSIZE)
973 		n = SF_BUFSIZE;
974 	memcpy(buf, s, n);
975 	s = buf + n;
976 	e = buf + ic;
977 	while (s < e)
978 		*s++ = ' ';
979 	s = buf;
980 	while ((oc -= 3) >= 0)
981 	{
982 		c = (BX_O_MASK(s[0]) << 2) | (BX_O_MASK(s[1]) >> 4);
983 		BX_O_CRC(crc, c);
984 		sfputc(uu->op, c);
985 		c = (BX_O_MASK(s[1]) << 4) | (BX_O_MASK(s[2]) >> 2);
986 		BX_O_CRC(crc, c);
987 		sfputc(uu->op, c);
988 		c = (BX_O_MASK(s[2]) << 6) | (BX_O_MASK(s[3])     );
989 		BX_O_CRC(crc, c);
990 		sfputc(uu->op, c);
991 		s += 4;
992 	}
993 	bx->crc = crc;
994 	return 0;
995 }
996 
997 /*
998  * binhex decode input to output
999  */
1000 
1001 static int
bx_decode(register Uu_t * uu)1002 bx_decode(register Uu_t* uu)
1003 {
1004 	register Bx_t*	bx = (Bx_t*)(uu + 1);
1005 	register off_t	n;
1006 	register int	c;
1007 	register char*	s;
1008 	unsigned long	crc;
1009 	int		(*decode)(Uu_t*, Bx_t*, char*, size_t);
1010 
1011 	crc = 0x10000;
1012 	bx->crc = 0;
1013 	if (uu->flags & BX_OLD)
1014 	{
1015 		decode = bx_o_decode;
1016 		c = 0;
1017 		while (s = sfgetr(uu->ip, '\n', 0))
1018 			if (*s++ == '*' && *s++ == '*' && *s++ == '*')
1019 			{
1020 				switch (*s)
1021 				{
1022 				case 'C':
1023 					switch (s[1])
1024 					{
1025 					case 'O':
1026 						if (c || strncmp(s, "COMPRESSED", 10))
1027 							continue;
1028 						decode = bx_c_decode;
1029 						continue;
1030 					case 'H':
1031 						if (decode == bx_c_decode || strncmp(s, "CHECKSUM:", 9))
1032 							continue;
1033 						crc = bx->crc & 0xFF;
1034 						bx->crc = strtoul(s + 9, NiL, 16) & 0xFF;
1035 						break;
1036 					case 'R':
1037 						if (decode == bx_o_decode || strncmp(s, "CRC:", 4))
1038 							continue;
1039 						crc = bx->crc & 0xFFFF;
1040 						bx->crc = strtoul(s + 4, NiL, 16) & 0xFFFF;
1041 						break;
1042 					default:
1043 						continue;
1044 					}
1045 					break;
1046 				case 'D':
1047 					if (strncmp(s, "DATA", 4))
1048 						continue;
1049 					while (s = sfgetr(uu->ip, '\n', 0))
1050 					{
1051 						if (strneq(s, "***END", 6))
1052 							break;
1053 						if ((*decode)(uu, bx, s, sfvalue(uu->ip) - 1) < 0)
1054 							return -1;
1055 					}
1056 					break;
1057 				case 'R':
1058 					if (c || strncmp(s, "RESOURCE", 8))
1059 						continue;
1060 					c = 1;
1061 					continue;
1062 				default:
1063 					continue;
1064 				}
1065 				break;
1066 			}
1067 	}
1068 	else
1069 	{
1070 		if ((n = bx->size) > 0)
1071 			while (n--)
1072 			{
1073 				if ((c = bx_q_getc(uu, bx)) == EOF)
1074 					return -1;
1075 				sfputc(uu->op, c);
1076 			}
1077 
1078 		/*
1079 		 * check the header crc
1080 		 */
1081 
1082 		bx_q_crc(bx, 0);
1083 		bx_q_crc(bx, 0);
1084 		crc = bx->crc;
1085 		bx->crc = bx_q_getn(uu, bx, 2);
1086 	}
1087 	if (crc != bx->crc)
1088 	{
1089 		if (uu->disc->errorf)
1090 		{
1091 			if (crc == 0x10000)
1092 				(*uu->disc->errorf)(uu, uu->disc, 2, "%s format checksum missing", uu->meth.name);
1093 			else
1094 				(*uu->disc->errorf)(uu, uu->disc, 2, "%s format data checksum mismatch", uu->meth.name);
1095 		}
1096 		return -1;
1097 	}
1098 	return 0;
1099 }
1100 
1101 /*
1102  * binhex encode input to output
1103  */
1104 
1105 static int
bx_encode(register Uu_t * uu)1106 bx_encode(register Uu_t* uu)
1107 {
1108 	register Bx_t*		bx = (Bx_t*)(uu + 1);
1109 	register unsigned char*	m;
1110 	register int		c;
1111 	register int		i;
1112 	struct stat		st;
1113 
1114 	bx->last = -1;
1115 	bx->qp = bx->qbuf;
1116 	bx->qe = bx->qbuf + sizeof(bx->qbuf);
1117 	if (fstat(sffileno(uu->ip), &st))
1118 		st.st_size = 0;
1119 	sfprintf(uu->op, "(This file must be converted with BinHex 4.0)\n:");
1120 	if (!(m = (unsigned char*)uu->path))
1121 		m = (unsigned char*)"-";
1122 	if ((c = strlen((char*)m)) > 63)
1123 		c = 63;
1124 	bx_q_putc(uu, bx, c);
1125 	for (i = 0; i < c; i++)
1126 		bx_q_putc(uu, bx, m[i]);
1127 	bx_q_putc(uu, bx, 0);
1128 	bx_q_putn(uu, bx, 0, 4);
1129 	bx_q_putn(uu, bx, 0, 4);
1130 	bx_q_putn(uu, bx, 0xF800, 2);
1131 	bx_q_putn(uu, bx, st.st_size, 4);
1132 	bx_q_putn(uu, bx, 0, 4);
1133 	bx_q_crc(bx, 0);
1134 	bx_q_crc(bx, 0);
1135 	bx_q_putn(uu, bx, bx->crc, 2);
1136 	bx->crc = 0;
1137 	while ((c = sfgetc(uu->ip)) != EOF)
1138 		bx_q_putc(uu, bx, c);
1139 	bx_q_crc(bx, 0);
1140 	bx_q_crc(bx, 0);
1141 	bx_q_putn(uu, bx, bx->crc, 2);
1142 	bx->crc = 0;
1143 	bx_q_crc(bx, 0);
1144 	bx_q_crc(bx, 0);
1145 	bx_q_putn(uu, bx, bx->crc, 2);
1146 	while (bx->qp != bx->qbuf)
1147 		bx_q_putc(uu, bx, 0);
1148 	sfputc(uu->op, ':');
1149 	sfputc(uu->op, '\n');
1150 	return 0;
1151 }
1152 
1153 /*
1154  * cat input to output
1155  */
1156 
1157 static int
cat(register Uu_t * uu)1158 cat(register Uu_t* uu)
1159 {
1160 	return sfmove(uu->ip, uu->op, SF_UNBOUND, -1) >= 0 && sfeof(uu->ip) ? 0 : -1;
1161 }
1162 
1163 static Uudata_t	uu_posix =
1164 {
1165 	"end",
1166 	0,
1167 	0,
1168 	UU_HEADER|UU_LENGTH,
1169 	0,
1170 	" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1171 };
1172 
1173 static const Uudata_t	uu_ucb =
1174 {
1175 	"end",
1176 	0,
1177 	0156,
1178 	UU_HEADER|UU_LENGTH,
1179 	0,
1180 	"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
1181 };
1182 
1183 static const Uudata_t	uu_base64 =
1184 {
1185 	"====",
1186 	'=',
1187 	0,
1188 	0,
1189 	0,
1190 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
1191 };
1192 
1193 static const Uudata_t	uu_bx =
1194 {
1195 	0,
1196 	0,
1197 	0,
1198 	UU_HEADER|UU_HEADERMUST,
1199 	sizeof(Bx_t),
1200 	"!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"
1201 };
1202 
1203 static const Uumeth_t	methods[] =
1204 {
1205 
1206 {
1207 	"posix",			"uuencode",	"",
1208 	uu_header,	uu_encode,	uu_decode,	(void*)&uu_posix
1209 },
1210 {
1211 	"ucb",				"bsd",		"",
1212 	uu_header,	uu_encode,	uu_decode,	(void*)&uu_ucb
1213 },
1214 {
1215 	"mime",				"base64",	"-base64",
1216 	0,		uu_encode,	uu_decode,	(void*)&uu_base64
1217 },
1218 {
1219 	"quoted-printable",		"qp",		"",
1220 	0,		qp_encode,	qp_decode,	0
1221 },
1222 {
1223 	"binhex",			"mac-binhex",	"",
1224 	bx_header,	bx_encode,	bx_decode,	(void*)&uu_bx
1225 },
1226 {
1227 	"sevenbit",			"7bit",		"",
1228 	0,		cat,		cat,		0
1229 },
1230 
1231 { 0 }
1232 
1233 };
1234 
1235 /*
1236  * list the method names/alternates on fp
1237  */
1238 
1239 int
uulist(Sfio_t * fp)1240 uulist(Sfio_t* fp)
1241 {
1242 	register const Uumeth_t*	mp;
1243 
1244 	sfprintf(fp, "ENCODING          ALIAS\n");
1245 	for (mp = methods; mp->name; mp++)
1246 		sfprintf(fp, "%-17s %s\n", mp->name, mp->alias);
1247 	return 0;
1248 }
1249 
1250 /*
1251  * return method pointer given name
1252  */
1253 
1254 Uumeth_t*
uumeth(const char * name)1255 uumeth(const char* name)
1256 {
1257 	register const Uumeth_t*	mp;
1258 	register int			c;
1259 	register const char*		v;
1260 	register int			vl;
1261 	const char*			np;
1262 
1263 	/*
1264 	 * first entry is the default
1265 	 */
1266 
1267 	if (!name || !*name)
1268 	{
1269 		((Uudata_t*)methods->data)->flags |= UU_DEFAULT;
1270 		return (Uumeth_t*)methods;
1271 	}
1272 	if ((*name == 'x' || *name == 'X') && *(name + 1) == '-')
1273 		name += 2;
1274 	if (*name == 'b' && !strncasecmp(name, UU_BEGIN, UU_BEGIN_LEN))
1275 	{
1276 		/*
1277 		 * id prefix match
1278 		 */
1279 
1280 		if ((c = *(name += UU_BEGIN_LEN)) == ' ')
1281 			return (Uumeth_t*)methods;
1282 		for (mp = methods; mp->name; mp++)
1283 			if (*mp->id == c && !strncasecmp(name, mp->id, strlen(mp->id)))
1284 				return (Uumeth_t*)mp;
1285 		if (c == '-')
1286 			return (Uumeth_t*)methods;
1287 	}
1288 	else
1289 	{
1290 		c = *name;
1291 		for (v = name + strlen(name); v > name && (isdigit(*(v - 1)) || *(v - 1) == '.'); v--);
1292 		vl = *v ? (v - name) : 0;
1293 
1294 		/*
1295 		 * exact name or alias match
1296 		 */
1297 
1298 		for (;;)
1299 		{
1300 			for (mp = methods; mp->name; mp++)
1301 				if (*mp->name == c && (!strcasecmp(name, mp->name) || vl && !strncasecmp(name, mp->name, vl)) ||
1302 			    	mp->alias && *mp->alias == c && (!strcasecmp(name, mp->alias) || vl && !strncasecmp(name, mp->alias, vl)))
1303 					return (Uumeth_t*)mp;
1304 			np = name;
1305 			if (!(name = strchr(name, '/')))
1306 				break;
1307 			if (((c = *++name) == 'x' || *name == 'X') && *(name + 1) == '-')
1308 				c = *(name += 2);
1309 			if (vl)
1310 				vl -= (name - np);
1311 		}
1312 
1313 		/*
1314 		 * first char name match
1315 		 */
1316 
1317 		for (mp = methods; mp->name; mp++)
1318 			if (*mp->name == c)
1319 				return (Uumeth_t*)mp;
1320 	}
1321 	return 0;
1322 }
1323 
1324 /*
1325  * open an encode/decode handle
1326  */
1327 
1328 Uu_t*
uuopen(Uudisc_t * disc,Uumeth_t * meth)1329 uuopen(Uudisc_t* disc, Uumeth_t* meth)
1330 {
1331 	register Uu_t*		uu;
1332 	register Uudata_t*	data;
1333 	int			extra;
1334 
1335 	if (data = (Uudata_t*)meth->data)
1336 		extra = data->size;
1337 	else
1338 		extra = 0;
1339 	if (!(uu = newof(0, Uu_t, 1, extra)))
1340 		return 0;
1341 	uu->id = lib;
1342 	uu->disc = disc;
1343 	uu->meth = *meth;
1344 	return uu;
1345 }
1346 
1347 /*
1348  * close an encode/decode handle
1349  */
1350 
1351 int
uuclose(Uu_t * uu)1352 uuclose(Uu_t* uu)
1353 {
1354 	if (!uu)
1355 		return -1;
1356 	if ((uu->flags & UU_FREEPATH) && uu->path)
1357 		free(uu->path);
1358 	free(uu);
1359 	return 0;
1360 }
1361 
1362 /*
1363  * common encode/decode tail
1364  */
1365 
1366 static ssize_t
uuop(register Uu_t * uu,Uu_f fun)1367 uuop(register Uu_t* uu, Uu_f fun)
1368 {
1369 	int		n;
1370 	ssize_t		r;
1371 	Sfoff_t		p;
1372 
1373 	if (uu->count != SF_UNBOUND && ((p = sfseek(uu->ip, (Sfoff_t)0, SEEK_CUR)) < 0 || !(uu->ip = sfdcsubstream(NiL, uu->lp = uu->ip, p, uu->count))))
1374 	{
1375 		if (uu->disc->errorf)
1376 			(*uu->disc->errorf)(uu, uu->disc, 2, "cannot initialize substream at %I*d for %I*d bytes", sizeof(p), p, sizeof(uu->count), uu->count);
1377 		return -1;
1378 	}
1379 	p = sfseek(uu->op, (Sfoff_t)0, SEEK_CUR);
1380 	n = (*fun)(uu);
1381 	if (uu->lp)
1382 	{
1383 		sfclose(uu->ip);
1384 		uu->ip = uu->lp;
1385 		uu->lp = 0;
1386 	}
1387 	if (n < 0)
1388 		r = -1;
1389 	else if (sfsync(uu->op) || sferror(uu->op))
1390 	{
1391 		r = -1;
1392 		if (uu->disc->errorf)
1393 			(*uu->disc->errorf)(uu, uu->disc, 2, "write error");
1394 	}
1395 	else if (sferror(uu->ip))
1396 	{
1397 		r = -1;
1398 		if (uu->disc->errorf)
1399 			(*uu->disc->errorf)(uu, uu->disc, 2, "read error");
1400 	}
1401 	else
1402 		r = sfseek(uu->op, (Sfoff_t)0, SEEK_CUR) - p;
1403 	if (uu->flags & UU_CLOSEOUT)
1404 	{
1405 		uu->flags &= ~UU_CLOSEOUT;
1406 		sfclose(uu->op);
1407 	}
1408 	return r;
1409 }
1410 
1411 /*
1412  * encode n bytes (or all if SF_UNBOUND) from ip to op
1413  */
1414 
1415 ssize_t
uuencode(register Uu_t * uu,Sfio_t * ip,Sfio_t * op,size_t n,const char * path)1416 uuencode(register Uu_t* uu, Sfio_t* ip, Sfio_t* op, size_t n, const char* path)
1417 {
1418 	if (!uu->meth.encodef)
1419 	{
1420 		if (uu->disc->errorf)
1421 			(*uu->disc->errorf)(uu, uu->disc, 2, "%s format encoding not supported", uu->meth.name);
1422 		return -1;
1423 	}
1424 	if (!(uu->ip = ip) || !(uu->op = op))
1425 		return -1;
1426 	uu->count = n;
1427 	if ((uu->flags & UU_FREEPATH) && uu->path)
1428 		free(uu->path);
1429 	uu->path = (char*)path;
1430 	uu->flags = uu->disc->flags;
1431 	return uuop(uu, uu->meth.encodef);
1432 }
1433 
1434 /*
1435  * decode n bytes (or all if SF_UNBOUND) from ip to op
1436  */
1437 
1438 ssize_t
uudecode(register Uu_t * uu,Sfio_t * ip,Sfio_t * op,size_t n,const char * path)1439 uudecode(register Uu_t* uu, Sfio_t* ip, Sfio_t* op, size_t n, const char* path)
1440 {
1441 	register char*	s;
1442 	unsigned char*	m;
1443 	int		c;
1444 	int		headerpath;
1445 	Uudata_t*	data;
1446 	const Uumeth_t*	mp;
1447 	char		map[UCHAR_MAX + 2];
1448 
1449 	if (!uu->meth.decodef)
1450 	{
1451 		if (uu->disc->errorf)
1452 			(*uu->disc->errorf)(uu, uu->disc, 2, "%s format decoding not supported", uu->meth.name);
1453 		return -1;
1454 	}
1455 	if (!(uu->ip = ip))
1456 		return -1;
1457 	uu->op = op;
1458 	uu->count = n;
1459 	if ((uu->flags & UU_FREEPATH) && uu->path)
1460 		free(uu->path);
1461 	uu->path = (char*)path;
1462 	uu->flags = uu->disc->flags;
1463 	data = (Uudata_t*)uu->meth.data;
1464 	if (((uu->flags & UU_HEADER) || data && (data->flags & UU_HEADERMUST)) && uu->meth.headerf)
1465 	{
1466 		if ((*uu->meth.headerf)(uu))
1467 			return -1;
1468 		headerpath = 1;
1469 	}
1470 	else
1471 	{
1472 		headerpath = 0;
1473 		if (data && (data->flags & UU_DEFAULT) && (c = sfgetc(uu->ip)) != EOF)
1474 		{
1475 			sfungetc(uu->ip, c);
1476 			for (mp = methods; ((Uudata_t*)mp->data)->flags & UU_LENGTH; mp++)
1477 			{
1478 				m = uu_map((Uudata_t*)mp->data, map);
1479 				if (m[c] > 0 && m[c] < (UUIN * UUCHUNK + 1))
1480 					break;
1481 			}
1482 			if (mp > methods)
1483 			{
1484 				uu->meth = *mp;
1485 				if (uu->disc->errorf)
1486 					(*uu->disc->errorf)(uu, uu->disc, 1, "assuming %s encoding", mp->name);
1487 			}
1488 		}
1489 	}
1490 	if (!uu->op)
1491 	{
1492 		if (!uu->path && headerpath)
1493 		{
1494 			if (uu->disc->errorf)
1495 				(*uu->disc->errorf)(uu, uu->disc, 2, "%s format header has no output file name", uu->meth.name);
1496 			return -1;
1497 		}
1498 		if (!uu->path || !*uu->path || streq(uu->path, "-") || streq(uu->path, "/dev/stdout"))
1499 			uu->op = sfstdout;
1500 		else
1501 		{
1502 			if (headerpath && (uu->flags & UU_LOCAL))
1503 			{
1504 				for (s = uu->path; *s; s++)
1505 					if (isspace(*s) || iscntrl(*s) || !isprint(*s) || *s == '/' || *s == '\\')
1506 						*s = '_';
1507 				s = uu->path;
1508 				if (isalpha(s[0]) && s[1] == ':')
1509 					s[1] = '_';
1510 			}
1511 			if (!(uu->op = sfopen(NiL, uu->path, "w")))
1512 			{
1513 				if (uu->disc->errorf)
1514 					(*uu->disc->errorf)(uu, uu->disc, 2, "%s: cannot write", uu->path);
1515 				return -1;
1516 			}
1517 			uu->flags |= UU_CLOSEOUT;
1518 		}
1519 	}
1520 	return uuop(uu, uu->meth.decodef);
1521 }
1522