844 lines
18 KiB
C
Executable File
844 lines
18 KiB
C
Executable File
/*
|
|
* Heirloom mailx - a mail user agent derived from Berkeley Mail.
|
|
*
|
|
* Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
|
|
*/
|
|
/*
|
|
* Copyright (c) 1980, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
#ifdef DOSCCS
|
|
static char sccsid[] = "@(#)aux.c 2.83 (gritter) 3/4/06";
|
|
#endif
|
|
#endif /* not lint */
|
|
|
|
#include "rcv.h"
|
|
#include "extern.h"
|
|
#include <sys/stat.h>
|
|
#include <utime.h>
|
|
#include <time.h>
|
|
#include <termios.h>
|
|
#include <ctype.h>
|
|
#ifdef HAVE_WCTYPE_H
|
|
#include <wctype.h>
|
|
#endif /* HAVE_WCTYPE_H */
|
|
#ifdef HAVE_WCWIDTH
|
|
#include <wchar.h>
|
|
#endif /* HAVE_WCWIDTH */
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
|
|
|
|
#include <os_lib.h>
|
|
#include <os_msg.h>
|
|
|
|
#include <mail.h>
|
|
|
|
#include "md5.h"
|
|
/*
|
|
* Mail -- a mail program
|
|
*
|
|
* Auxiliary functions.
|
|
*/
|
|
|
|
/*
|
|
* Return a pointer to a dynamic copy of the argument.
|
|
*/
|
|
char *
|
|
savestr(const char *str)
|
|
{
|
|
char *new;
|
|
int size = strlen(str) + 1;
|
|
|
|
if ((new = salloc(size)) != NULL)
|
|
memcpy(new, str, size);
|
|
return new;
|
|
}
|
|
|
|
/*
|
|
* Make a copy of new argument incorporating old one.
|
|
*/
|
|
char *
|
|
save2str(const char *str, const char *old)
|
|
{
|
|
char *new;
|
|
int newsize = strlen(str) + 1;
|
|
int oldsize = old ? strlen(old) + 1 : 0;
|
|
|
|
if ((new = salloc(newsize + oldsize)) != NULL) {
|
|
if (oldsize) {
|
|
memcpy(new, old, oldsize);
|
|
new[oldsize - 1] = ' ';
|
|
}
|
|
memcpy(new + oldsize, str, newsize);
|
|
}
|
|
return new;
|
|
}
|
|
|
|
char *
|
|
savecat(const char *s1, const char *s2)
|
|
{
|
|
const char *cp;
|
|
char *ns, *np;
|
|
|
|
np = ns = salloc(strlen(s1) + strlen(s2) + 1);
|
|
for (cp = s1; *cp; cp++)
|
|
*np++ = *cp;
|
|
for (cp = s2; *cp; cp++)
|
|
*np++ = *cp;
|
|
*np = '\0';
|
|
return ns;
|
|
}
|
|
|
|
#include <stdarg.h>
|
|
|
|
#ifndef HAVE_SNPRINTF
|
|
/*
|
|
* Lazy vsprintf wrapper.
|
|
*/
|
|
int
|
|
snprintf(char *str, size_t size, const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
int ret;
|
|
|
|
va_start(ap, format);
|
|
ret = vsprintf(str, format, ap);
|
|
va_end(ap);
|
|
return ret;
|
|
}
|
|
#endif /* !HAVE_SNPRINTF */
|
|
|
|
/*
|
|
* Announce a fatal error and die.
|
|
*/
|
|
void
|
|
panic(const char *format, ...)
|
|
{
|
|
#if (DEBUG_LEVEL >= DEBUG_LEVEL_PRINT)
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
DEBUG_ERROR( catgets(catd, CATSET, 1, "panic: "));
|
|
vfprintf(stderr, format, ap);
|
|
|
|
|
|
va_end(ap);
|
|
DEBUG_ERROR( catgets(catd, CATSET, 2, "\n"));
|
|
fflush(stderr);
|
|
#endif
|
|
abort();
|
|
}
|
|
|
|
void mail_exit(int mailStatus)
|
|
{
|
|
CMSG_FD msgFd;
|
|
CMSG_BUFF msg;
|
|
|
|
memset(&msgFd, 0 , sizeof(CMSG_FD));
|
|
memset(&msg, 0 , sizeof(CMSG_BUFF));
|
|
|
|
msg.type = MAIL_ACTION_STATUS_BACK;
|
|
|
|
MAIL_STATUS_ENUM *pStatusEnum = (MAIL_STATUS_ENUM *)msg.content;
|
|
*pStatusEnum = mailStatus;
|
|
|
|
int isCheckConnection = 0;
|
|
|
|
if (value("mail-type")) {
|
|
if (0 == strcmp("check-connection", value("mail-type")))
|
|
{
|
|
msg.priv = MAIL_CHECK_CONNECTION;
|
|
isCheckConnection = 1;
|
|
}
|
|
else if (0 == strcmp("calllog", value("mail-type")))
|
|
{
|
|
msg.priv = MAIL_CALLLOG;
|
|
}
|
|
else if (0 == strcmp("usbvm", value("mail-type")))
|
|
{
|
|
msg.priv = MAIL_USBVM;
|
|
}
|
|
else
|
|
{
|
|
msg.priv = MAIL_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
#if (DEBUG_LEVEL < DEBUG_LEVEL_PRINT)
|
|
if (!isCheckConnection)
|
|
{
|
|
if (NULL != mailrc)
|
|
{
|
|
unlink(mailrc);
|
|
}
|
|
unlink(value("mail-content"));
|
|
}
|
|
#endif
|
|
if (msg_connCliAndSend(CMSG_ID_MAIL, &msgFd, &msg) != 0) {
|
|
DEBUG_PRINT("Send mail changed message failed.\n");
|
|
}
|
|
_exit(0);
|
|
}
|
|
|
|
/*
|
|
* Copy a string, lowercasing it as we go.
|
|
*/
|
|
void
|
|
i_strcpy(char *dest, const char *src, int size)
|
|
{
|
|
char *max;
|
|
|
|
max=dest+size-1;
|
|
while (dest<=max) {
|
|
*dest++ = lowerconv(*src & 0377);
|
|
if (*src++ == '\0')
|
|
break;
|
|
}
|
|
}
|
|
|
|
char *
|
|
i_strdup(const char *src)
|
|
{
|
|
int sz;
|
|
char *dest;
|
|
|
|
sz = strlen(src) + 1;
|
|
dest = salloc(sz);
|
|
i_strcpy(dest, src, sz);
|
|
return dest;
|
|
}
|
|
|
|
int
|
|
substr(const char *str, const char *sub)
|
|
{
|
|
const char *cp, *backup;
|
|
|
|
cp = sub;
|
|
backup = str;
|
|
while (*str && *cp) {
|
|
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
|
|
if (mb_cur_max > 1) {
|
|
wchar_t c, c2;
|
|
int sz;
|
|
|
|
if ((sz = mbtowc(&c, cp, mb_cur_max)) < 0)
|
|
goto singlebyte;
|
|
cp += sz;
|
|
if ((sz = mbtowc(&c2, str, mb_cur_max)) < 0)
|
|
goto singlebyte;
|
|
str += sz;
|
|
c = towupper(c);
|
|
c2 = towupper(c2);
|
|
if (c != c2) {
|
|
if ((sz = mbtowc(&c, backup, mb_cur_max)) > 0) {
|
|
backup += sz;
|
|
str = backup;
|
|
} else
|
|
str = ++backup;
|
|
cp = sub;
|
|
}
|
|
} else
|
|
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
|
|
{
|
|
int c, c2;
|
|
|
|
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
|
|
singlebyte:
|
|
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
|
|
c = *cp++ & 0377;
|
|
if (islower(c))
|
|
c = toupper(c);
|
|
c2 = *str++ & 0377;
|
|
if (islower(c2))
|
|
c2 = toupper(c2);
|
|
if (c != c2) {
|
|
str = ++backup;
|
|
cp = sub;
|
|
}
|
|
}
|
|
}
|
|
return *cp == '\0';
|
|
}
|
|
|
|
/*
|
|
* The following code deals with input stacking to do source
|
|
* commands. All but the current file pointer are saved on
|
|
* the stack.
|
|
*/
|
|
|
|
static int ssp; /* Top of file stack */
|
|
struct sstack {
|
|
FILE *s_file; /* File we were in. */
|
|
enum condition s_cond; /* Saved state of conditionals */
|
|
int s_loading; /* Loading .mailrc, etc. */
|
|
#define SSTACK 20
|
|
} sstack[SSTACK];
|
|
|
|
/*
|
|
* Pop the current input back to the previous level.
|
|
* Update the "sourcing" flag as appropriate.
|
|
*/
|
|
int
|
|
unstack(void)
|
|
{
|
|
if (ssp <= 0) {
|
|
DEBUG_PRINT(catgets(catd, CATSET, 4,
|
|
"\"Source\" stack over-pop.\n"));
|
|
sourcing = 0;
|
|
return(1);
|
|
}
|
|
Fclose(input);
|
|
if (cond != CANY)
|
|
DEBUG_PRINT(catgets(catd, CATSET, 5, "Unmatched \"if\"\n"));
|
|
ssp--;
|
|
cond = sstack[ssp].s_cond;
|
|
loading = sstack[ssp].s_loading;
|
|
input = sstack[ssp].s_file;
|
|
if (ssp == 0)
|
|
sourcing = loading;
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Are any of the characters in the two strings the same?
|
|
*/
|
|
int
|
|
anyof(char *s1, char *s2)
|
|
{
|
|
|
|
while (*s1)
|
|
if (strchr(s2, *s1++))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Determine if as1 is a valid prefix of as2.
|
|
* Return true if yep.
|
|
*/
|
|
int
|
|
is_prefix(const char *as1, const char *as2)
|
|
{
|
|
const char *s1, *s2;
|
|
|
|
s1 = as1;
|
|
s2 = as2;
|
|
while (*s1++ == *s2)
|
|
if (*s2++ == '\0')
|
|
return(1);
|
|
return(*--s1 == '\0');
|
|
}
|
|
|
|
enum protocol
|
|
which_protocol(const char *name)
|
|
{
|
|
register const char *cp;
|
|
char *np;
|
|
size_t sz;
|
|
struct stat st;
|
|
enum protocol p;
|
|
|
|
if (name[0] == '%' && name[1] == ':')
|
|
name += 2;
|
|
for (cp = name; *cp && *cp != ':'; cp++)
|
|
if (!alnumchar(*cp&0377))
|
|
goto file;
|
|
if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
|
|
if (strncmp(name, "pop3://", 7) == 0)
|
|
return PROTO_POP3;
|
|
if (strncmp(name, "pop3s://", 8) == 0)
|
|
return PROTO_POP3;
|
|
|
|
if (strncmp(name, "imap://", 7) == 0)
|
|
return PROTO_IMAP;
|
|
if (strncmp(name, "imaps://", 8) == 0)
|
|
return PROTO_IMAP;
|
|
|
|
return PROTO_UNKNOWN;
|
|
} else {
|
|
file: p = PROTO_FILE;
|
|
np = ac_alloc((sz = strlen(name)) + 5);
|
|
strcpy(np, name);
|
|
if (stat(name, &st) == 0) {
|
|
if (S_ISDIR(st.st_mode)) {
|
|
strcpy(&np[sz], "/tmp");
|
|
if (stat(np, &st) == 0 && S_ISDIR(st.st_mode)) {
|
|
strcpy(&np[sz], "/new");
|
|
if (stat(np, &st) == 0 &&
|
|
S_ISDIR(st.st_mode)) {
|
|
strcpy(&np[sz], "/cur");
|
|
if (stat(np, &st) == 0 &&
|
|
S_ISDIR(st.st_mode))
|
|
p = PROTO_MAILDIR;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
strcpy(&np[sz], ".gz");
|
|
if (stat(np, &st) < 0) {
|
|
strcpy(&np[sz], ".bz2");
|
|
if (stat(np, &st) < 0) {
|
|
if ((cp = value("newfolders")) != 0 &&
|
|
strcmp(cp, "maildir") == 0)
|
|
p = PROTO_MAILDIR;
|
|
}
|
|
}
|
|
}
|
|
ac_free(np);
|
|
return p;
|
|
}
|
|
}
|
|
|
|
char *
|
|
protbase(const char *cp)
|
|
{
|
|
char *n = salloc(strlen(cp) + 1);
|
|
char *np = n;
|
|
|
|
while (*cp) {
|
|
if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
|
|
*np++ = *cp++;
|
|
*np++ = *cp++;
|
|
*np++ = *cp++;
|
|
} else if (cp[0] == '/')
|
|
break;
|
|
else
|
|
*np++ = *cp++;
|
|
}
|
|
*np = '\0';
|
|
return n;
|
|
}
|
|
|
|
long
|
|
nextprime(long n)
|
|
{
|
|
const long primes[] = {
|
|
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
|
|
131071, 262139, 524287, 1048573, 2097143, 4194301,
|
|
8388593, 16777213, 33554393, 67108859, 134217689,
|
|
268435399, 536870909, 1073741789, 2147483647
|
|
};
|
|
long mprime = 7;
|
|
int i;
|
|
|
|
for (i = 0; i < sizeof primes / sizeof *primes; i++)
|
|
if ((mprime = primes[i]) >= (n < 65536 ? n*4 :
|
|
n < 262144 ? n*2 : n))
|
|
break;
|
|
if (i == sizeof primes / sizeof *primes)
|
|
mprime = n; /* not so prime, but better than failure */
|
|
return mprime;
|
|
}
|
|
|
|
#define Hexchar(n) ((n)>9 ? (n)-10+'A' : (n)+'0')
|
|
#define hexchar(n) ((n)>9 ? (n)-10+'a' : (n)+'0')
|
|
|
|
char *
|
|
md5tohex(const void *vp)
|
|
{
|
|
char *hex;
|
|
const char *cp = vp;
|
|
int i;
|
|
|
|
hex = salloc(33);
|
|
for (i = 0; i < 16; i++) {
|
|
hex[2*i] = hexchar((cp[i]&0xf0) >> 4);
|
|
hex[2*i+1] = hexchar(cp[i]&0x0f);
|
|
}
|
|
hex[32] = '\0';
|
|
return hex;
|
|
}
|
|
|
|
char *
|
|
cram_md5_string(const char *user, const char *pass, const char *b64)
|
|
{
|
|
struct str in, out;
|
|
char digest[16], *cp, *sp, *rp, *xp;
|
|
int ss, rs;
|
|
|
|
in.s = (char *)b64;
|
|
in.l = strlen(in.s);
|
|
mime_fromb64(&in, &out, 0);
|
|
hmac_md5((unsigned char *)out.s, out.l,
|
|
(unsigned char *)pass, strlen(pass),
|
|
digest);
|
|
free(out.s);
|
|
xp = md5tohex(digest);
|
|
sp = ac_alloc(ss = strlen(user) + strlen(xp) + 2);
|
|
snprintf(sp, ss, "%s %s", user, xp);
|
|
cp = strtob64(sp);
|
|
ac_free(sp);
|
|
rp = salloc(rs = strlen(cp) + 3);
|
|
snprintf(rp, rs, "%s\r\n", cp);
|
|
free(cp);
|
|
return rp;
|
|
}
|
|
|
|
char *
|
|
getpassword(struct termios *otio, int *reset_tio, const char *query)
|
|
{
|
|
char *line = NULL, *pass;
|
|
size_t linesize = 0;
|
|
int i;
|
|
|
|
i = readline(stdin, &line, &linesize);
|
|
*reset_tio = 0;
|
|
if (i < 0) {
|
|
if (line)
|
|
free(line);
|
|
return NULL;
|
|
}
|
|
pass = savestr(line);
|
|
free(line);
|
|
return pass;
|
|
}
|
|
|
|
char *
|
|
getrandstring(size_t length)
|
|
{
|
|
static unsigned char nodedigest[16];
|
|
static pid_t pid;
|
|
int i, fd = -1;
|
|
char *data;
|
|
char *cp, *rp;
|
|
MD5_CTX ctx;
|
|
|
|
data = salloc(length);
|
|
if ((fd = open("/dev/urandom", O_RDONLY)) < 0 ||
|
|
read(fd, data, length) != length) {
|
|
if (pid == 0) {
|
|
pid = getpid();
|
|
srand(pid);
|
|
cp = nodename(0);
|
|
MD5Init(&ctx);
|
|
MD5Update(&ctx, (unsigned char *)cp, strlen(cp));
|
|
MD5Final(nodedigest, &ctx);
|
|
}
|
|
for (i = 0; i < length; i++)
|
|
data[i] = (int)(255 * (rand() / (RAND_MAX + 1.0))) ^
|
|
nodedigest[i % sizeof nodedigest];
|
|
}
|
|
if (fd > 0)
|
|
close(fd);
|
|
cp = memtob64(data, length);
|
|
rp = salloc(length+1);
|
|
strncpy(rp, cp, length)[length] = '\0';
|
|
free(cp);
|
|
return rp;
|
|
}
|
|
|
|
void
|
|
out_of_memory(void)
|
|
{
|
|
panic("no memory");
|
|
}
|
|
|
|
void *
|
|
smalloc(size_t s)
|
|
{
|
|
#if (DEBUG_LEVEL >= DEBUG_LEVEL_PRINT)
|
|
static size_t total = 0;
|
|
total += s;
|
|
DEBUG_PRINT("mailx malloc: %d %d", s, total);
|
|
#endif
|
|
void *p;
|
|
if (s == 0)
|
|
s = 1;
|
|
if ((p = malloc(s)) == NULL)
|
|
out_of_memory();
|
|
return p;
|
|
}
|
|
|
|
void *
|
|
srealloc(void *v, size_t s)
|
|
{
|
|
#if (DEBUG_LEVEL >= DEBUG_LEVEL_PRINT)
|
|
static size_t total = 0;
|
|
total += s;
|
|
DEBUG_PRINT("mailx realloc: %d %d", s, total);
|
|
#endif
|
|
void *r;
|
|
|
|
if (s == 0)
|
|
s = 1;
|
|
if (v == NULL)
|
|
return smalloc(s);
|
|
if ((r = realloc(v, s)) == NULL)
|
|
out_of_memory();
|
|
return r;
|
|
}
|
|
|
|
void *
|
|
scalloc(size_t nmemb, size_t size)
|
|
{
|
|
#if (DEBUG_LEVEL >= DEBUG_LEVEL_PRINT)
|
|
static size_t total = 0;
|
|
total += size;
|
|
DEBUG_PRINT("mailx calloc: %d %d", size, total);
|
|
#endif
|
|
void *vp;
|
|
|
|
if (size == 0)
|
|
size = 1;
|
|
if ((vp = calloc(nmemb, size)) == NULL)
|
|
out_of_memory();
|
|
return vp;
|
|
}
|
|
|
|
char *
|
|
sstpcpy(char *dst, const char *src)
|
|
{
|
|
while ((*dst = *src++) != '\0')
|
|
dst++;
|
|
return dst;
|
|
}
|
|
|
|
char *
|
|
sstrdup(const char *cp)
|
|
{
|
|
char *dp;
|
|
|
|
if (cp) {
|
|
dp = smalloc(strlen(cp) + 1);
|
|
strcpy(dp, cp);
|
|
return dp;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
enum okay
|
|
makedir(const char *name)
|
|
{
|
|
int e;
|
|
struct stat st;
|
|
|
|
if (mkdir(name, 0700) < 0) {
|
|
e = errno;
|
|
if ((e == EEXIST || e == ENOSYS) &&
|
|
stat(name, &st) == 0 &&
|
|
(st.st_mode&S_IFMT) == S_IFDIR)
|
|
return OKAY;
|
|
return STOP;
|
|
}
|
|
return OKAY;
|
|
}
|
|
void
|
|
makeprint(struct str *in, struct str *out)
|
|
{
|
|
static int print_all_chars = -1;
|
|
char *inp, *outp;
|
|
size_t msz, dist;
|
|
|
|
out->s = smalloc(msz = in->l + 1);
|
|
if (print_all_chars == -1)
|
|
print_all_chars = value("print-all-chars") != NULL;
|
|
if (print_all_chars) {
|
|
memcpy(out->s, in->s, in->l);
|
|
out->l = in->l;
|
|
out->s[out->l] = '\0';
|
|
return;
|
|
}
|
|
inp = in->s;
|
|
outp = out->s;
|
|
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
|
|
if (mb_cur_max > 1) {
|
|
wchar_t wc;
|
|
char mb[MB_LEN_MAX+1];
|
|
int i, n;
|
|
out->l = 0;
|
|
while (inp < &in->s[in->l]) {
|
|
if (*inp & 0200)
|
|
n = mbtowc(&wc, inp, &in->s[in->l] - inp);
|
|
else {
|
|
wc = *inp;
|
|
n = 1;
|
|
}
|
|
if (n < 0) {
|
|
mbtowc(&wc, NULL, mb_cur_max);
|
|
wc = utf8 ? 0xFFFD : '?';
|
|
n = 1;
|
|
} else if (n == 0)
|
|
n = 1;
|
|
inp += n;
|
|
if (!iswprint(wc) && wc != '\n' && wc != '\r' &&
|
|
wc != '\b' && wc != '\t') {
|
|
if ((wc & ~(wchar_t)037) == 0)
|
|
wc = utf8 ? 0x2400 | wc : '?';
|
|
else if (wc == 0177)
|
|
wc = utf8 ? 0x2421 : '?';
|
|
else
|
|
wc = utf8 ? 0x2426 : '?';
|
|
}
|
|
if ((n = wctomb(mb, wc)) <= 0)
|
|
continue;
|
|
out->l += n;
|
|
if (out->l >= msz - 1) {
|
|
dist = outp - out->s;
|
|
out->s = srealloc(out->s, msz += 32);
|
|
outp = &out->s[dist];
|
|
}
|
|
for (i = 0; i < n; i++)
|
|
*outp++ = mb[i];
|
|
}
|
|
} else
|
|
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
|
|
{
|
|
int c;
|
|
while (inp < &in->s[in->l]) {
|
|
c = *inp++ & 0377;
|
|
if (!isprint(c) && c != '\n' && c != '\r' &&
|
|
c != '\b' && c != '\t')
|
|
c = '?';
|
|
*outp++ = c;
|
|
}
|
|
out->l = in->l;
|
|
}
|
|
out->s[out->l] = '\0';
|
|
}
|
|
|
|
char *
|
|
prstr(const char *s)
|
|
{
|
|
struct str in, out;
|
|
char *rp;
|
|
|
|
in.s = (char *)s;
|
|
in.l = strlen(s);
|
|
makeprint(&in, &out);
|
|
rp = salloc(out.l + 1);
|
|
memcpy(rp, out.s, out.l);
|
|
rp[out.l] = '\0';
|
|
free(out.s);
|
|
return rp;
|
|
}
|
|
|
|
/*
|
|
* Locale-independent character class functions.
|
|
*/
|
|
int
|
|
asccasecmp(const char *s1, const char *s2)
|
|
{
|
|
register int cmp;
|
|
|
|
do
|
|
if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
|
|
return cmp;
|
|
while (*s1++ != '\0' && *s2++ != '\0');
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ascncasecmp(const char *s1, const char *s2, size_t sz)
|
|
{
|
|
register int cmp;
|
|
size_t i = 1;
|
|
|
|
if (sz == 0)
|
|
return 0;
|
|
do
|
|
if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
|
|
return cmp;
|
|
while (i++ < sz && *s1++ != '\0' && *s2++ != '\0');
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
asccasestr(const char *haystack, const char *xneedle)
|
|
{
|
|
char *needle, *NEEDLE;
|
|
int i, sz;
|
|
|
|
sz = strlen(xneedle);
|
|
if (sz == 0)
|
|
return (char *)haystack;
|
|
needle = ac_alloc(sz);
|
|
NEEDLE = ac_alloc(sz);
|
|
for (i = 0; i < sz; i++) {
|
|
needle[i] = lowerconv(xneedle[i]&0377);
|
|
NEEDLE[i] = upperconv(xneedle[i]&0377);
|
|
}
|
|
while (*haystack) {
|
|
if (*haystack == *needle || *haystack == *NEEDLE) {
|
|
for (i = 1; i < sz; i++)
|
|
if (haystack[i] != needle[i] &&
|
|
haystack[i] != NEEDLE[i])
|
|
break;
|
|
if (i == sz)
|
|
return (char *)haystack;
|
|
}
|
|
haystack++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const unsigned char class_char[] = {
|
|
/* 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel */
|
|
C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
|
|
/* 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si */
|
|
C_CNTRL,C_BLANK,C_WHITE,C_SPACE,C_SPACE,C_SPACE,C_CNTRL,C_CNTRL,
|
|
/* 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb */
|
|
C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
|
|
/* 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us */
|
|
C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
|
|
/* 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' */
|
|
C_BLANK,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
|
|
/* 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / */
|
|
C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
|
|
/* 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 */
|
|
C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,
|
|
/* 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? */
|
|
C_DIGIT,C_DIGIT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
|
|
/* 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G */
|
|
C_PUNCT,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
|
|
/* 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O */
|
|
C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
|
|
/* 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W */
|
|
C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
|
|
/* 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ */
|
|
C_UPPER,C_UPPER,C_UPPER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
|
|
/* 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g */
|
|
C_PUNCT,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
|
|
/* 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o */
|
|
C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
|
|
/* 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w */
|
|
C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
|
|
/* 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del */
|
|
C_LOWER,C_LOWER,C_LOWER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_CNTRL
|
|
};
|