Source from upstream; imap-2007f.tar.gz

MD5 2126fd125ea26b73b20f01fcd5940369
This commit is contained in:
Chris
2019-01-03 04:12:17 -06:00
parent c6e9661b42
commit 22f316e36d
581 changed files with 216530 additions and 0 deletions

40
src/ansilib/memmove.c Normal file
View File

@@ -0,0 +1,40 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Memory move
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 30 August 2006
*/
/* Copy memory block
* Accepts: destination pointer
* source pointer
* length
* Returns: destination pointer
*/
void *memmove (void *s,void *ct,size_t n)
{
bcopy (ct,s,n); /* they should have this one */
return s;
}

49
src/ansilib/memmove2.c Normal file
View File

@@ -0,0 +1,49 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Memory move when no bcopy()
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 11 May 1989
* Last Edited: 30 August 2006
*/
/* Copy memory block
* Accepts: destination pointer
* source pointer
* length
* Returns: destination pointer
*/
void *memmove (void *s,void *ct,size_t n)
{
char *dp,*sp;
int i;
unsigned long dest = (unsigned long) s;
unsigned long src = (unsigned long) ct;
if (((dest < src) && ((dest + n) < src)) ||
((dest > src) && ((src + n) < dest))) return (void *) memcpy (s,ct,n);
dp = (char *) s;
sp = (char *) ct;
if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i];
else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i];
return s;
}

40
src/ansilib/memset.c Normal file
View File

@@ -0,0 +1,40 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Set memory
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
*
* Date: 11 May 1989
* Last Edited: 30 August 2006
*/
/* Set a block of memory
* Accepts: destination pointer
* value to set
* length
* Returns: destination pointer
*/
void *memset (void *s,int c,size_t n)
{
if (c) while (n) s[--n] = c; /* this way if non-zero */
else bzero (s,n); /* they should have this one */
return s;
}

40
src/ansilib/strpbrk.c Normal file
View File

@@ -0,0 +1,40 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: String search for break character
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
*
* Date: 11 May 1989
* Last Edited: 30 August 2006
*/
/* Return pointer to first occurance in string of any delimiter
* Accepts: source pointer
* vector of delimiters pointer
* Returns: pointer to delimiter or NIL if not found
*/
char *strpbrk (char *cs,char *ct)
{
char *s;
/* search for delimiter until end of string */
for (; *cs; cs++) for (s = ct; *s; s++) if (*s == *cs) return cs;
return NIL; /* not found */
}

45
src/ansilib/strstr.c Normal file
View File

@@ -0,0 +1,45 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Substring search
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
*
* Date: 11 May 1989
* Last Edited: 30 August 2006
*/
/* Return pointer to first occurance in string of a substring
* Accepts: source pointer
* substring pointer
* Returns: pointer to substring in source or NIL if not found
*/
char *strstr (char *cs,char *ct)
{
char *s;
char *t;
while (cs = strchr (cs,*ct)) {/* for each occurance of the first character */
/* see if remainder of string matches */
for (s = cs + 1, t = ct + 1; *t && *s == *t; s++, t++);
if (!*t) return cs; /* if ran out of substring then have match */
cs++; /* try from next character */
}
return NIL; /* not found */
}

67
src/ansilib/strtok.c Normal file
View File

@@ -0,0 +1,67 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: String return successive tokens
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
*
* Date: 11 May 1989
* Last Edited: 30 January 2007
*/
/* Find token in string
* Accepts: source pointer or NIL to use previous source
* vector of token delimiters pointer
* Returns: pointer to next token
*/
static char *state = NIL; /* string to locate tokens */
char *strtok (char *s,char *ct)
{
return strtok_r (s,ct,&state);/* jacket into reentrant routine */
}
/* Find token in string (reentrant)
* Accepts: source pointer or NIL to use previous source
* vector of token delimiters pointer
* returned state pointer
* Returns: pointer to next token
*/
char *strtok_r (char *s,char *ct,char **r)
{
char *t,*ts;
if (!s) s = *r; /* use previous token if none specified */
*r = NIL; /* default to no returned state */
if (!(s && *s)) return NIL; /* no tokens left */
/* find any leading delimiters */
do for (t = ct, ts = NIL; *t; t++) if (*t == *s) {
if (*(ts = ++s)) break; /* yes, restart search if more in string */
return NIL; /* else no more tokens */
} while (ts); /* continue until no more leading delimiters */
/* can we find a new delimiter? */
for (ts = s; *ts; ts++) for (t = ct; *t; t++) if (*t == *ts) {
*ts++ = '\0'; /* yes, tie off token at that point */
*r = ts; /* save subsequent tokens for future call */
return s; /* return our token */
}
return s; /* return final token */
}

73
src/ansilib/strtoul.c Normal file
View File

@@ -0,0 +1,73 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: String to unsigned long
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
*
* Date: 14 February 1995
* Last Edited: 30 August 2006
*/
/*
* Turn a string unsigned long into the real thing
* Accepts: source string
* pointer to place to return end pointer
* base
* Returns: parsed unsigned long integer, end pointer is updated
*/
unsigned long strtoul (char *t,char **endp,int base)
{
unsigned long value = 0; /* the accumulated value */
int negative = 0; /* this a negative number? */
unsigned char c,*s = t;
if (base && (base < 2 || base > 36)) {
errno = EINVAL; /* insist upon valid base */
return value;
}
while (isspace (*s)) s++; /* skip leading whitespace */
switch (*s) { /* check for leading sign char */
case '-':
negative = 1; /* yes, negative #. fall into '+' */
case '+':
s++; /* skip the sign character */
}
if (!base) { /* base not specified? */
if (*s != '0') base = 10; /* must be decimal if doesn't start with 0 */
/* starts with 0x? */
else if (tolower (*++s) == 'x') {
base = 16; /* yes, is hex */
s++; /* skip the x */
}
else base = 8; /* ...or octal */
}
do { /* convert to numeric form if digit */
if (isdigit (*s)) c = *s - '0';
/* alphabetic conversion */
else if (isalpha (*s)) c = *s - (isupper (*s) ? 'A' : 'a') + 10;
else break; /* else no way it's valid */
if (c >= base) break; /* digit out of range for base? */
value = value * base + c; /* accumulate the digit */
} while (*++s); /* loop until non-numeric character */
if (tolower (*s) == 'l') s++; /* ignore 'l' or 'L' marker */
if (endp) *endp = s; /* save users endp to after number */
/* negate number if needed */
return negative ? -value : value;
}

96
src/c-client/auth_ext.c Normal file
View File

@@ -0,0 +1,96 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: EXTERNAL authenticator
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 6 April 2005
* Last Edited: 30 August 2006
*/
long auth_external_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user);
char *auth_external_server (authresponse_t responder,int argc,char *argv[]);
AUTHENTICATOR auth_ext = { /* secure, has full auth, hidden */
AU_SECURE | AU_AUTHUSER | AU_HIDE,
"EXTERNAL", /* authenticator name */
NIL, /* always valid */
auth_external_client, /* client method */
auth_external_server, /* server method */
NIL /* next authenticator */
};
/* Client authenticator
* Accepts: challenger function
* responder function
* SASL service name
* parsed network mailbox structure
* stream argument for functions
* pointer to current trial count
* returned user name
* Returns: T if success, NIL otherwise, number of trials incremented if retry
*/
long auth_external_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user)
{
void *challenge;
unsigned long clen;
long ret = NIL;
*trial = 65535; /* never retry */
if (challenge = (*challenger) (stream,&clen)) {
fs_give ((void **) &challenge);
/* send authorization id (empty string OK) */
if ((*responder) (stream,strcpy (user,mb->user),strlen (mb->user))) {
if (challenge = (*challenger) (stream,&clen))
fs_give ((void **) &challenge);
else ret = LONGT; /* check the authentication */
}
}
return ret;
}
/* Server authenticator
* Accepts: responder function
* argument count
* argument vector
* Returns: authenticated user name or NIL
*/
char *auth_external_server (authresponse_t responder,int argc,char *argv[])
{
unsigned long len;
char *authid;
char *authenid = (char *) mail_parameters (NIL,GET_EXTERNALAUTHID,NIL);
char *ret = NIL;
/* get authorization identity */
if (authenid && (authid = (*responder) ("",0,&len))) {
/* note: responders null-terminate */
if (*authid ? authserver_login (authid,authenid,argc,argv) :
authserver_login (authenid,NIL,argc,argv)) ret = myusername ();
fs_give ((void **) &authid);
}
return ret;
}

423
src/c-client/auth_gss.c Normal file
View File

@@ -0,0 +1,423 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: GSSAPI authenticator
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 12 January 1998
* Last Edited: 30 August 2006
*/
long auth_gssapi_valid (void);
long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user);
long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
authrespond_t responder,char *service,NETMBX *mb,
void *stream,char *user,kinit_t ki);
char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]);
AUTHENTICATOR auth_gss = {
AU_SECURE | AU_AUTHUSER, /* secure authenticator */
"GSSAPI", /* authenticator name */
auth_gssapi_valid, /* check if valid */
auth_gssapi_client, /* client method */
auth_gssapi_server, /* server method */
NIL /* next authenticator */
};
#define AUTH_GSSAPI_P_NONE 1
#define AUTH_GSSAPI_P_INTEGRITY 2
#define AUTH_GSSAPI_P_PRIVACY 4
#define AUTH_GSSAPI_C_MAXSIZE 8192
#define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y)
/* Check if GSSAPI valid on this system
* Returns: T if valid, NIL otherwise
*/
long auth_gssapi_valid (void)
{
char tmp[MAILTMPLEN];
OM_uint32 smn;
gss_buffer_desc buf;
gss_name_t name;
/* make service name */
sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
mylocalhost ());
buf.length = strlen (buf.value = tmp);
/* see if can build a name */
if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&name) !=
GSS_S_COMPLETE) return NIL;
/* remove server method if no keytab */
if (!kerberos_server_valid ()) auth_gss.server = NIL;
gss_release_name (&smn,&name);/* finished with name */
return LONGT;
}
/* Client authenticator
* Accepts: challenger function
* responder function
* SASL service name
* parsed network mailbox structure
* stream argument for functions
* pointer to current trial count
* returned user name
* Returns: T if success, NIL otherwise, number of trials incremented if retry
*/
long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user)
{
gss_buffer_desc chal;
kinit_t ki = (kinit_t) mail_parameters (NIL,GET_KINIT,NIL);
long ret = NIL;
*trial = 65535; /* never retry */
/* get initial (empty) challenge */
if (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) {
if (chal.length) { /* abort if challenge non-empty */
mm_log ("Server bug: non-empty initial GSSAPI challenge",WARN);
(*responder) (stream,NIL,0);
ret = LONGT; /* will get a BAD response back */
}
else if (mb->authuser[0] && strcmp (mb->authuser,myusername ())) {
mm_log ("Can't use Kerberos: invalid /authuser",WARN);
(*responder) (stream,NIL,0);
ret = LONGT; /* will get a BAD response back */
}
else ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
stream,user,ki);
}
return ret;
}
/* Client authenticator worker function
* Accepts: challenger function
* responder function
* SASL service name
* parsed network mailbox structure
* stream argument for functions
* returned user name
* kinit function pointer if should retry with kinit
* Returns: T if success, NIL otherwise
*/
long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
authrespond_t responder,char *service,NETMBX *mb,
void *stream,char *user,kinit_t ki)
{
char tmp[MAILTMPLEN];
OM_uint32 smj,smn,dsmj,dsmn;
OM_uint32 mctx = 0;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
gss_buffer_desc resp,buf;
long i;
int conf;
gss_qop_t qop;
gss_name_t crname = NIL;
blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
void *data;
long ret = NIL;
sprintf (tmp,"%s@%s",service,mb->host);
buf.length = strlen (buf.value = tmp);
/* get service name */
if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) !=
GSS_S_COMPLETE) {
mm_log ("Can't import Kerberos service name",WARN);
(*responder) (stream,NIL,0);
}
else {
data = (*bn) (BLOCK_SENSITIVE,NIL);
/* negotiate with KDC */
smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL,
GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG |
GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS,
GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL);
(*bn) (BLOCK_NONSENSITIVE,data);
/* while continuation needed */
while (smj == GSS_S_CONTINUE_NEEDED) {
if (chal.value) fs_give ((void **) &chal.value);
/* send response, get next challenge */
i = (*responder) (stream,resp.value,resp.length) &&
(chal.value = (*challenger) (stream,(unsigned long *) &chal.length));
gss_release_buffer (&smn,&resp);
if (i) { /* negotiate continuation with KDC */
data = (*bn) (BLOCK_SENSITIVE,NIL);
switch (smj = /* make sure continuation going OK */
gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,
crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG |
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,
GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL,
&resp,NIL,NIL)) {
case GSS_S_CONTINUE_NEEDED:
case GSS_S_COMPLETE:
break;
default: /* error, don't need context any more */
gss_delete_sec_context (&smn,&ctx,NIL);
}
(*bn) (BLOCK_NONSENSITIVE,data);
}
else { /* error in continuation */
mm_log ("Error in negotiating Kerberos continuation",WARN);
(*responder) (stream,NIL,0);
/* don't need context any more */
gss_delete_sec_context (&smn,&ctx,NIL);
break;
}
}
switch (smj) { /* done - deal with final condition */
case GSS_S_COMPLETE:
if (chal.value) fs_give ((void **) &chal.value);
/* get prot mechanisms and max size */
if ((*responder) (stream,resp.value ? resp.value : "",resp.length) &&
(chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&&
(gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) &&
(resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){
/* make copy of flags and length */
memcpy (tmp,resp.value,4);
gss_release_buffer (&smn,&resp);
/* no session protection */
tmp[0] = AUTH_GSSAPI_P_NONE;
/* install user name */
strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ()));
buf.value = tmp; buf.length = strlen (user) + 4;
/* successful negotiation */
switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) {
case GSS_S_COMPLETE:
if ((*responder) (stream,resp.value,resp.length)) ret = T;
gss_release_buffer (&smn,&resp);
break;
default:
do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE:
mctx = 0;
case GSS_S_CONTINUE_NEEDED:
sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value);
mm_log (tmp,WARN);
gss_release_buffer (&dsmn,&resp);
}
while (dsmj == GSS_S_CONTINUE_NEEDED);
do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE:
case GSS_S_CONTINUE_NEEDED:
sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
mm_log (tmp,WARN);
gss_release_buffer (&dsmn,&resp);
}
while (dsmj == GSS_S_CONTINUE_NEEDED);
(*responder) (stream,NIL,0);
}
}
/* flush final challenge */
if (chal.value) fs_give ((void **) &chal.value);
/* don't need context any more */
gss_delete_sec_context (&smn,&ctx,NIL);
break;
case GSS_S_CREDENTIALS_EXPIRED:
if (chal.value) fs_give ((void **) &chal.value);
/* retry if application kinits */
if (ki && (*ki) (mb->host,"Kerberos credentials expired"))
ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
stream,user,NIL);
else { /* application can't kinit */
sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s",
mb->host);
mm_log (tmp,WARN);
(*responder) (stream,NIL,0);
}
break;
case GSS_S_FAILURE:
if (chal.value) fs_give ((void **) &chal.value);
do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE: /* end of message, can kinit? */
if (ki && kerberos_try_kinit (smn) &&
(*ki) (mb->host,(char *) resp.value)) {
gss_release_buffer (&dsmn,&resp);
ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
stream,user,NIL);
break; /* done */
}
else (*responder) (stream,NIL,0);
case GSS_S_CONTINUE_NEEDED:
sprintf (tmp,kerberos_try_kinit (smn) ?
"Kerberos error: %.80s (try running kinit) for %.80s" :
"GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host);
mm_log (tmp,WARN);
gss_release_buffer (&dsmn,&resp);
} while (dsmj == GSS_S_CONTINUE_NEEDED);
break;
default: /* miscellaneous errors */
if (chal.value) fs_give ((void **) &chal.value);
do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE:
mctx = 0;
case GSS_S_CONTINUE_NEEDED:
sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value);
mm_log (tmp,WARN);
gss_release_buffer (&dsmn,&resp);
}
while (dsmj == GSS_S_CONTINUE_NEEDED);
do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE:
case GSS_S_CONTINUE_NEEDED:
sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
mm_log (tmp,WARN);
gss_release_buffer (&dsmn,&resp);
}
while (dsmj == GSS_S_CONTINUE_NEEDED);
(*responder) (stream,NIL,0);
break;
}
/* finished with credentials name */
if (crname) gss_release_name (&smn,&crname);
}
return ret; /* return status */
}
/* Server authenticator
* Accepts: responder function
* argument count
* argument vector
* Returns: authenticated user name or NIL
*/
char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[])
{
char *ret = NIL;
char tmp[MAILTMPLEN];
unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE);
int conf;
OM_uint32 smj,smn,dsmj,dsmn,flags;
OM_uint32 mctx = 0;
gss_name_t crname,name;
gss_OID mech;
gss_buffer_desc chal,resp,buf;
gss_cred_id_t crd;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
gss_qop_t qop = GSS_C_QOP_DEFAULT;
/* make service name */
sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
tcp_serverhost ());
buf.length = strlen (buf.value = tmp);
/* acquire credentials */
if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) ==
GSS_S_COMPLETE) {
if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL))
== GSS_S_COMPLETE) {
if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) {
do { /* negotiate authentication */
smj = gss_accept_sec_context (&smn,&ctx,crd,&resp,
GSS_C_NO_CHANNEL_BINDINGS,&name,&mech,
&chal,&flags,NIL,NIL);
/* don't need response any more */
fs_give ((void **) &resp.value);
switch (smj) { /* how did it go? */
case GSS_S_COMPLETE: /* successful */
case GSS_S_CONTINUE_NEEDED:
if (chal.value) { /* send challenge, get next response */
resp.value = (*responder) (chal.value,chal.length,
(unsigned long *) &resp.length);
gss_release_buffer (&smn,&chal);
}
break;
}
}
while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED));
/* successful exchange? */
if ((smj == GSS_S_COMPLETE) &&
(gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) {
/* send security and size */
memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4);
tmp[0] = AUTH_GSSAPI_P_NONE;
if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){
resp.value = (*responder) (chal.value,chal.length,
(unsigned long *) &resp.length);
gss_release_buffer (&smn,&chal);
if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) {
/* client request valid */
if (chal.value && (chal.length > 4) &&
(chal.length < (MAILTMPLEN - 1)) &&
memcpy (tmp,chal.value,chal.length) &&
(tmp[0] & AUTH_GSSAPI_P_NONE)) {
/* tie off authorization ID */
tmp[chal.length] = '\0';
ret = kerberos_login (tmp+4,buf.value,argc,argv);
}
/* done with user name */
gss_release_buffer (&smn,&chal);
}
/* finished with response */
fs_give ((void **) &resp.value);
}
/* don't need name buffer any more */
gss_release_buffer (&smn,&buf);
}
/* don't need client name any more */
gss_release_name (&smn,&name);
/* don't need context any more */
if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL);
}
/* finished with credentials */
gss_release_cred (&smn,&crd);
}
else { /* can't acquire credentials! */
if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE)
SERVER_LOG ("Failed to acquire credentials for %s",buf.value);
if (smj != GSS_S_FAILURE) do
switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE:
mctx = 0;
case GSS_S_CONTINUE_NEEDED:
SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value);
gss_release_buffer (&dsmn,&resp);
}
while (dsmj == GSS_S_CONTINUE_NEEDED);
do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
GSS_C_NO_OID,&mctx,&resp)) {
case GSS_S_COMPLETE:
case GSS_S_CONTINUE_NEEDED:
SERVER_LOG ("GSSAPI mechanism status: %s",resp.value);
gss_release_buffer (&dsmn,&resp);
}
while (dsmj == GSS_S_CONTINUE_NEEDED);
}
/* finished with credentials name */
gss_release_name (&smn,&crname);
}
return ret; /* return status */
}

117
src/c-client/auth_log.c Normal file
View File

@@ -0,0 +1,117 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Login authenticator
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 5 December 1995
* Last Edited: 30 August 2006
*/
long auth_login_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user);
char *auth_login_server (authresponse_t responder,int argc,char *argv[]);
AUTHENTICATOR auth_log = {
AU_HIDE, /* hidden */
"LOGIN", /* authenticator name */
NIL, /* always valid */
auth_login_client, /* client method */
auth_login_server, /* server method */
NIL /* next authenticator */
};
#define PWD_USER "User Name"
#define PWD_PWD "Password"
/* Client authenticator
* Accepts: challenger function
* responder function
* SASL service name
* parsed network mailbox structure
* stream argument for functions
* pointer to current trial count
* returned user name
* Returns: T if success, NIL otherwise, number of trials incremented if retry
*/
long auth_login_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user)
{
char pwd[MAILTMPLEN];
void *challenge;
unsigned long clen;
long ret = NIL;
/* get user name prompt */
if (challenge = (*challenger) (stream,&clen)) {
fs_give ((void **) &challenge);
pwd[0] = NIL; /* prompt user */
mm_login (mb,user,pwd,*trial);
if (!pwd[0]) { /* user requested abort */
(*responder) (stream,NIL,0);
*trial = 0; /* cancel subsequent attempts */
ret = LONGT; /* will get a BAD response back */
}
/* send user name */
else if ((*responder) (stream,user,strlen (user)) &&
(challenge = (*challenger) (stream,&clen))) {
fs_give ((void **) &challenge);
/* send password */
if ((*responder) (stream,pwd,strlen (pwd))) {
if (challenge = (*challenger) (stream,&clen))
fs_give ((void **) &challenge);
else {
++*trial; /* can try again if necessary */
ret = LONGT; /* check the authentication */
}
}
}
}
memset (pwd,0,MAILTMPLEN); /* erase password */
if (!ret) *trial = 65535; /* don't retry if bad protocol */
return ret;
}
/* Server authenticator
* Accepts: responder function
* argument count
* argument vector
* Returns: authenticated user name or NIL
*/
char *auth_login_server (authresponse_t responder,int argc,char *argv[])
{
char *ret = NIL;
char *user,*pass,*authuser;
if (user = (*responder) (PWD_USER,sizeof (PWD_USER),NIL)) {
if (pass = (*responder) (PWD_PWD,sizeof (PWD_PWD),NIL)) {
/* delimit user from possible admin */
if (authuser = strchr (user,'*')) *authuser++ = '\0';
if (server_login (user,pass,authuser,argc,argv)) ret = myusername ();
fs_give ((void **) &pass);
}
fs_give ((void **) &user);
}
return ret;
}

495
src/c-client/auth_md5.c Normal file
View File

@@ -0,0 +1,495 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: CRAM-MD5 authenticator
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 21 October 1998
* Last Edited: 30 January 2007
*/
/* MD5 context */
#define MD5BLKLEN 64 /* MD5 block length */
#define MD5DIGLEN 16 /* MD5 digest length */
typedef struct {
unsigned long chigh; /* high 32bits of byte count */
unsigned long clow; /* low 32bits of byte count */
unsigned long state[4]; /* state (ABCD) */
unsigned char buf[MD5BLKLEN]; /* input buffer */
unsigned char *ptr; /* buffer position */
} MD5CONTEXT;
/* Prototypes */
long auth_md5_valid (void);
long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user);
char *auth_md5_server (authresponse_t responder,int argc,char *argv[]);
char *auth_md5_pwd (char *user);
char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl);
void md5_init (MD5CONTEXT *ctx);
void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len);
void md5_final (unsigned char *digest,MD5CONTEXT *ctx);
static void md5_transform (unsigned long *state,unsigned char *block);
static void md5_encode (unsigned char *dst,unsigned long *src,int len);
static void md5_decode (unsigned long *dst,unsigned char *src,int len);
/* Authenticator linkage */
AUTHENTICATOR auth_md5 = {
AU_SECURE, /* secure authenticator */
"CRAM-MD5", /* authenticator name */
auth_md5_valid, /* check if valid */
auth_md5_client, /* client method */
auth_md5_server, /* server method */
NIL /* next authenticator */
};
/* Check if CRAM-MD5 valid on this system
* Returns: T, always
*/
long auth_md5_valid (void)
{
struct stat sbuf;
/* server forbids MD5 if no MD5 enable file */
if (stat (MD5ENABLE,&sbuf)) auth_md5.server = NIL;
return T; /* MD5 is otherwise valid */
}
/* Client authenticator
* Accepts: challenger function
* responder function
* SASL service name
* parsed network mailbox structure
* stream argument for functions
* pointer to current trial count
* returned user name
* Returns: T if success, NIL otherwise, number of trials incremented if retry
*/
long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user)
{
char pwd[MAILTMPLEN];
void *challenge;
unsigned long clen;
long ret = NIL;
/* get challenge */
if (challenge = (*challenger) (stream,&clen)) {
pwd[0] = NIL; /* prompt user */
mm_login (mb,user,pwd,*trial);
if (!pwd[0]) { /* user requested abort */
fs_give ((void **) &challenge);
(*responder) (stream,NIL,0);
*trial = 0; /* cancel subsequent attempts */
ret = LONGT; /* will get a BAD response back */
}
else { /* got password, build response */
sprintf (pwd,"%.65s %.33s",user,hmac_md5 (challenge,clen,
pwd,strlen (pwd)));
fs_give ((void **) &challenge);
/* send credentials, allow retry if OK */
if ((*responder) (stream,pwd,strlen (pwd))) {
if (challenge = (*challenger) (stream,&clen))
fs_give ((void **) &challenge);
else {
++*trial; /* can try again if necessary */
ret = LONGT; /* check the authentication */
}
}
}
}
memset (pwd,0,MAILTMPLEN); /* erase password in case not overwritten */
if (!ret) *trial = 65535; /* don't retry if bad protocol */
return ret;
}
/* Server authenticator
* Accepts: responder function
* argument count
* argument vector
* Returns: authenticated user name or NIL
*
* This is much hairier than it needs to be due to the necessary of zapping
* the password data.
*/
static int md5try = MAXLOGINTRIALS;
char *auth_md5_server (authresponse_t responder,int argc,char *argv[])
{
char *ret = NIL;
char *p,*u,*user,*authuser,*hash,chal[MAILTMPLEN];
unsigned long cl,pl;
/* generate challenge */
sprintf (chal,"<%lu.%lu@%s>",(unsigned long) getpid (),
(unsigned long) time (0),mylocalhost ());
/* send challenge, get user and hash */
if (user = (*responder) (chal,cl = strlen (chal),NIL)) {
/* got user, locate hash */
if (hash = strrchr (user,' ')) {
*hash++ = '\0'; /* tie off user */
/* see if authentication user */
if (authuser = strchr (user,'*')) *authuser++ = '\0';
/* get password */
if (p = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) {
pl = strlen (p);
u = (md5try && !strcmp (hash,hmac_md5 (chal,cl,p,pl))) ? user : NIL;
memset (p,0,pl); /* erase sensitive information */
fs_give ((void **) &p); /* flush erased password */
/* now log in for real */
if (u && authserver_login (u,authuser,argc,argv)) ret = myusername ();
else if (md5try) --md5try;
}
}
fs_give ((void **) &user);
}
if (!ret) sleep (3); /* slow down possible cracker */
return ret;
}
/* Return MD5 password for user
* Accepts: user name
* Returns: plaintext password if success, else NIL
*
* This is much hairier than it needs to be due to the necessary of zapping
* the password data. That's why we don't use stdio here.
*/
char *auth_md5_pwd (char *user)
{
struct stat sbuf;
int fd = open (MD5ENABLE,O_RDONLY,NIL);
unsigned char *s,*t,*buf,*lusr,*lret;
char *r;
char *ret = NIL;
if (fd >= 0) { /* found the file? */
fstat (fd,&sbuf); /* yes, slurp it into memory */
read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
/* see if any uppercase characters in user */
for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
/* yes, make lowercase copy */
lusr = *s ? lcase (cpystr (user)) : NIL;
for (s = strtok_r ((char *) buf,"\015\012",&r),lret = NIL; s;
s = ret ? NIL : strtok_r (NIL,"\015\012",&r))
/* must be valid entry line */
if (*s && (*s != '#') && (t = strchr (s,'\t')) && t[1]) {
*t++ = '\0'; /* found tab, tie off user, point to pwd */
if (!strcmp (s,user)) ret = cpystr (t);
else if (lusr && !lret) if (!strcmp (s,lusr)) lret = t;
}
/* accept case-independent name */
if (!ret && lret) ret = cpystr (lret);
/* don't need lowercase copy any more */
if (lusr) fs_give ((void **) &lusr);
/* erase sensitive information from buffer */
memset (buf,0,sbuf.st_size + 1);
fs_give ((void **) &buf); /* flush the buffer */
close (fd); /* don't need file any longer */
}
return ret; /* return password */
}
/* APOP server login
* Accepts: challenge
* desired user name
* purported MD5
* argument count
* argument vector
* Returns: authenticated user name or NIL
*/
char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[])
{
int i,j;
char *ret = NIL;
char *s,*authuser,tmp[MAILTMPLEN];
unsigned char digest[MD5DIGLEN];
MD5CONTEXT ctx;
char *hex = "0123456789abcdef";
/* see if authentication user */
if (authuser = strchr (user,'*')) *authuser++ = '\0';
/* get password */
if (s = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) {
md5_init (&ctx); /* initialize MD5 context */
/* build string to get MD5 digest */
sprintf (tmp,"%.128s%.128s",chal,s);
memset (s,0,strlen (s)); /* erase sensitive information */
fs_give ((void **) &s); /* flush erased password */
md5_update (&ctx,(unsigned char *) tmp,strlen (tmp));
memset (tmp,0,MAILTMPLEN); /* erase sensitive information */
md5_final (digest,&ctx);
/* convert to printable hex */
for (i = 0, s = tmp; i < MD5DIGLEN; i++) {
*s++ = hex[(j = digest[i]) >> 4];
*s++ = hex[j & 0xf];
}
*s = '\0'; /* tie off hash text */
memset (digest,0,MD5DIGLEN);/* erase sensitive information */
if (md5try && !strcmp (md5,tmp) &&
authserver_login (user,authuser,argc,argv))
ret = cpystr (myusername ());
else if (md5try) --md5try;
memset (tmp,0,MAILTMPLEN); /* erase sensitive information */
}
if (!ret) sleep (3); /* slow down possible cracker */
return ret;
}
/*
* RFC 2104 HMAC hashing
* Accepts: text to hash
* text length
* key
* key length
* Returns: hash as text, always
*/
char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl)
{
int i,j;
static char hshbuf[2*MD5DIGLEN + 1];
char *s;
MD5CONTEXT ctx;
char *hex = "0123456789abcdef";
unsigned char digest[MD5DIGLEN],k_ipad[MD5BLKLEN+1],k_opad[MD5BLKLEN+1];
if (kl > MD5BLKLEN) { /* key longer than pad length? */
md5_init (&ctx); /* yes, set key as MD5(key) */
md5_update (&ctx,(unsigned char *) key,kl);
md5_final (digest,&ctx);
key = (char *) digest;
kl = MD5DIGLEN;
}
memcpy (k_ipad,key,kl); /* store key in pads */
memset (k_ipad+kl,0,(MD5BLKLEN+1)-kl);
memcpy (k_opad,k_ipad,MD5BLKLEN+1);
/* XOR key with ipad and opad values */
for (i = 0; i < MD5BLKLEN; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
md5_init (&ctx); /* inner MD5: hash ipad and text */
md5_update (&ctx,k_ipad,MD5BLKLEN);
md5_update (&ctx,(unsigned char *) text,tl);
md5_final (digest,&ctx);
md5_init (&ctx); /* outer MD5: hash opad and inner results */
md5_update (&ctx,k_opad,MD5BLKLEN);
md5_update (&ctx,digest,MD5DIGLEN);
md5_final (digest,&ctx);
/* convert to printable hex */
for (i = 0, s = hshbuf; i < MD5DIGLEN; i++) {
*s++ = hex[(j = digest[i]) >> 4];
*s++ = hex[j & 0xf];
}
*s = '\0'; /* tie off hash text */
return hshbuf;
}
/* Everything after this point is derived from the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm
*/
/* You may wonder why these strange "a &= 0xffffffff;" statements are here.
* This is to ensure correct results on machines with a unsigned long size of
* larger than 32 bits.
*/
#define RND1(a,b,c,d,x,s,ac) \
a += ((b & c) | (d & ~b)) + x + (unsigned long) ac; \
a &= 0xffffffff; \
a = b + ((a << s) | (a >> (32 - s)));
#define RND2(a,b,c,d,x,s,ac) \
a += ((b & d) | (c & ~d)) + x + (unsigned long) ac; \
a &= 0xffffffff; \
a = b + ((a << s) | (a >> (32 - s)));
#define RND3(a,b,c,d,x,s,ac) \
a += (b ^ c ^ d) + x + (unsigned long) ac; \
a &= 0xffffffff; \
a = b + ((a << s) | (a >> (32 - s)));
#define RND4(a,b,c,d,x,s,ac) \
a += (c ^ (b | ~d)) + x + (unsigned long) ac; \
a &= 0xffffffff; \
a = b + ((a << s) | (a >> (32 - s)));
/* Initialize MD5 context
* Accepts: context to initialize
*/
void md5_init (MD5CONTEXT *ctx)
{
ctx->clow = ctx->chigh = 0; /* initialize byte count to zero */
/* initialization constants */
ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89;
ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476;
ctx->ptr = ctx->buf; /* reset buffer pointer */
}
/* MD5 add data to context
* Accepts: context
* input data
* length of data
*/
void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len)
{
unsigned long i = (ctx->buf + MD5BLKLEN) - ctx->ptr;
/* update double precision number of bytes */
if ((ctx->clow += len) < len) ctx->chigh++;
while (i <= len) { /* copy/transform data, 64 bytes at a time */
memcpy (ctx->ptr,data,i); /* fill up 64 byte chunk */
md5_transform (ctx->state,ctx->ptr = ctx->buf);
data += i,len -= i,i = MD5BLKLEN;
}
memcpy (ctx->ptr,data,len); /* copy final bit of data in buffer */
ctx->ptr += len; /* update buffer pointer */
}
/* MD5 Finalization
* Accepts: destination digest
* context
*/
void md5_final (unsigned char *digest,MD5CONTEXT *ctx)
{
unsigned long i,bits[2];
bits[0] = ctx->clow << 3; /* calculate length in bits (before padding) */
bits[1] = (ctx->chigh << 3) + (ctx->clow >> 29);
*ctx->ptr++ = 0x80; /* padding byte */
if ((i = (ctx->buf + MD5BLKLEN) - ctx->ptr) < 8) {
memset (ctx->ptr,0,i); /* pad out buffer with zeros */
md5_transform (ctx->state,ctx->buf);
/* pad out with zeros, leaving 8 bytes */
memset (ctx->buf,0,MD5BLKLEN - 8);
ctx->ptr = ctx->buf + MD5BLKLEN - 8;
}
else if (i -= 8) { /* need to pad this buffer? */
memset (ctx->ptr,0,i); /* yes, pad out with zeros, leaving 8 bytes */
ctx->ptr += i;
}
md5_encode (ctx->ptr,bits,2); /* make LSB-first length */
md5_transform (ctx->state,ctx->buf);
/* store state in digest */
md5_encode (digest,ctx->state,4);
/* erase context */
memset (ctx,0,sizeof (MD5CONTEXT));
}
/* MD5 basic transformation
* Accepts: state vector
* current 64-byte block
*/
static void md5_transform (unsigned long *state,unsigned char *block)
{
unsigned long a = state[0],b = state[1],c = state[2],d = state[3],x[16];
md5_decode (x,block,16); /* decode into 16 longs */
/* round 1 */
RND1 (a,b,c,d,x[ 0], 7,0xd76aa478); RND1 (d,a,b,c,x[ 1],12,0xe8c7b756);
RND1 (c,d,a,b,x[ 2],17,0x242070db); RND1 (b,c,d,a,x[ 3],22,0xc1bdceee);
RND1 (a,b,c,d,x[ 4], 7,0xf57c0faf); RND1 (d,a,b,c,x[ 5],12,0x4787c62a);
RND1 (c,d,a,b,x[ 6],17,0xa8304613); RND1 (b,c,d,a,x[ 7],22,0xfd469501);
RND1 (a,b,c,d,x[ 8], 7,0x698098d8); RND1 (d,a,b,c,x[ 9],12,0x8b44f7af);
RND1 (c,d,a,b,x[10],17,0xffff5bb1); RND1 (b,c,d,a,x[11],22,0x895cd7be);
RND1 (a,b,c,d,x[12], 7,0x6b901122); RND1 (d,a,b,c,x[13],12,0xfd987193);
RND1 (c,d,a,b,x[14],17,0xa679438e); RND1 (b,c,d,a,x[15],22,0x49b40821);
/* round 2 */
RND2 (a,b,c,d,x[ 1], 5,0xf61e2562); RND2 (d,a,b,c,x[ 6], 9,0xc040b340);
RND2 (c,d,a,b,x[11],14,0x265e5a51); RND2 (b,c,d,a,x[ 0],20,0xe9b6c7aa);
RND2 (a,b,c,d,x[ 5], 5,0xd62f105d); RND2 (d,a,b,c,x[10], 9, 0x2441453);
RND2 (c,d,a,b,x[15],14,0xd8a1e681); RND2 (b,c,d,a,x[ 4],20,0xe7d3fbc8);
RND2 (a,b,c,d,x[ 9], 5,0x21e1cde6); RND2 (d,a,b,c,x[14], 9,0xc33707d6);
RND2 (c,d,a,b,x[ 3],14,0xf4d50d87); RND2 (b,c,d,a,x[ 8],20,0x455a14ed);
RND2 (a,b,c,d,x[13], 5,0xa9e3e905); RND2 (d,a,b,c,x[ 2], 9,0xfcefa3f8);
RND2 (c,d,a,b,x[ 7],14,0x676f02d9); RND2 (b,c,d,a,x[12],20,0x8d2a4c8a);
/* round 3 */
RND3 (a,b,c,d,x[ 5], 4,0xfffa3942); RND3 (d,a,b,c,x[ 8],11,0x8771f681);
RND3 (c,d,a,b,x[11],16,0x6d9d6122); RND3 (b,c,d,a,x[14],23,0xfde5380c);
RND3 (a,b,c,d,x[ 1], 4,0xa4beea44); RND3 (d,a,b,c,x[ 4],11,0x4bdecfa9);
RND3 (c,d,a,b,x[ 7],16,0xf6bb4b60); RND3 (b,c,d,a,x[10],23,0xbebfbc70);
RND3 (a,b,c,d,x[13], 4,0x289b7ec6); RND3 (d,a,b,c,x[ 0],11,0xeaa127fa);
RND3 (c,d,a,b,x[ 3],16,0xd4ef3085); RND3 (b,c,d,a,x[ 6],23, 0x4881d05);
RND3 (a,b,c,d,x[ 9], 4,0xd9d4d039); RND3 (d,a,b,c,x[12],11,0xe6db99e5);
RND3 (c,d,a,b,x[15],16,0x1fa27cf8); RND3 (b,c,d,a,x[ 2],23,0xc4ac5665);
/* round 4 */
RND4 (a,b,c,d,x[ 0], 6,0xf4292244); RND4 (d,a,b,c,x[ 7],10,0x432aff97);
RND4 (c,d,a,b,x[14],15,0xab9423a7); RND4 (b,c,d,a,x[ 5],21,0xfc93a039);
RND4 (a,b,c,d,x[12], 6,0x655b59c3); RND4 (d,a,b,c,x[ 3],10,0x8f0ccc92);
RND4 (c,d,a,b,x[10],15,0xffeff47d); RND4 (b,c,d,a,x[ 1],21,0x85845dd1);
RND4 (a,b,c,d,x[ 8], 6,0x6fa87e4f); RND4 (d,a,b,c,x[15],10,0xfe2ce6e0);
RND4 (c,d,a,b,x[ 6],15,0xa3014314); RND4 (b,c,d,a,x[13],21,0x4e0811a1);
RND4 (a,b,c,d,x[ 4], 6,0xf7537e82); RND4 (d,a,b,c,x[11],10,0xbd3af235);
RND4 (c,d,a,b,x[ 2],15,0x2ad7d2bb); RND4 (b,c,d,a,x[ 9],21,0xeb86d391);
/* update state */
state[0] += a; state[1] += b; state[2] += c; state[3] += d;
memset (x,0,sizeof (x)); /* erase sensitive data */
}
/* You may wonder why these strange "& 0xff" maskings are here. This is to
* ensure correct results on machines with a char size of larger than 8 bits.
* For example, the KCC compiler on the PDP-10 uses 9-bit chars.
*/
/* MD5 encode unsigned long into LSB-first bytes
* Accepts: destination pointer
* source
* length of source
*/
static void md5_encode (unsigned char *dst,unsigned long *src,int len)
{
int i;
for (i = 0; i < len; i++) {
*dst++ = (unsigned char) (src[i] & 0xff);
*dst++ = (unsigned char) ((src[i] >> 8) & 0xff);
*dst++ = (unsigned char) ((src[i] >> 16) & 0xff);
*dst++ = (unsigned char) ((src[i] >> 24) & 0xff);
}
}
/* MD5 decode LSB-first bytes into unsigned long
* Accepts: destination pointer
* source
* length of destination
*/
static void md5_decode (unsigned long *dst,unsigned char *src,int len)
{
int i, j;
for (i = 0, j = 0; i < len; i++, j += 4)
dst[i] = ((unsigned long) (src[j] & 0xff)) |
(((unsigned long) (src[j+1] & 0xff)) << 8) |
(((unsigned long) (src[j+2] & 0xff)) << 16) |
(((unsigned long) (src[j+3] & 0xff)) << 24);
}

133
src/c-client/auth_pla.c Normal file
View File

@@ -0,0 +1,133 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Plain authenticator
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 22 September 1998
* Last Edited: 30 August 2006
*/
long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user);
char *auth_plain_server (authresponse_t responder,int argc,char *argv[]);
AUTHENTICATOR auth_pla = {
AU_AUTHUSER | AU_HIDE, /* allow authuser, hidden */
"PLAIN", /* authenticator name */
NIL, /* always valid */
auth_plain_client, /* client method */
auth_plain_server, /* server method */
NIL /* next authenticator */
};
/* Client authenticator
* Accepts: challenger function
* responder function
* SASL service name
* parsed network mailbox structure
* stream argument for functions
* pointer to current trial count
* returned user name
* Returns: T if success, NIL otherwise, number of trials incremented if retry
*/
long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
char *service,NETMBX *mb,void *stream,
unsigned long *trial,char *user)
{
char *u,pwd[MAILTMPLEN];
void *challenge;
unsigned long clen;
long ret = NIL;
/* snarl if not SSL/TLS session */
if (!mb->sslflag && !mb->tlsflag)
mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN",WARN);
/* get initial (empty) challenge */
if (challenge = (*challenger) (stream,&clen)) {
fs_give ((void **) &challenge);
if (clen) { /* abort if challenge non-empty */
mm_log ("Server bug: non-empty initial PLAIN challenge",WARN);
(*responder) (stream,NIL,0);
ret = LONGT; /* will get a BAD response back */
}
pwd[0] = NIL; /* prompt user if empty challenge */
mm_login (mb,user,pwd,*trial);
if (!pwd[0]) { /* empty challenge or user requested abort */
(*responder) (stream,NIL,0);
*trial = 0; /* cancel subsequent attempts */
ret = LONGT; /* will get a BAD response back */
}
else {
unsigned long rlen =
strlen (mb->authuser) + strlen (user) + strlen (pwd) + 2;
char *response = (char *) fs_get (rlen);
char *t = response; /* copy authorization id */
if (mb->authuser[0]) for (u = user; *u; *t++ = *u++);
*t++ = '\0'; /* delimiting NUL */
/* copy authentication id */
for (u = mb->authuser[0] ? mb->authuser : user; *u; *t++ = *u++);
*t++ = '\0'; /* delimiting NUL */
/* copy password */
for (u = pwd; *u; *t++ = *u++);
/* send credentials */
if ((*responder) (stream,response,rlen)) {
if (challenge = (*challenger) (stream,&clen))
fs_give ((void **) &challenge);
else {
++*trial; /* can try again if necessary */
ret = LONGT; /* check the authentication */
}
}
memset (response,0,rlen); /* erase credentials */
fs_give ((void **) &response);
}
}
memset (pwd,0,MAILTMPLEN); /* erase password */
if (!ret) *trial = 65535; /* don't retry if bad protocol */
return ret;
}
/* Server authenticator
* Accepts: responder function
* argument count
* argument vector
* Returns: authenticated user name or NIL
*/
char *auth_plain_server (authresponse_t responder,int argc,char *argv[])
{
char *ret = NIL;
char *user,*aid,*pass;
unsigned long len;
/* get user name */
if (aid = (*responder) ("",0,&len)) {
/* note: responders null-terminate */
if ((((unsigned long) ((user = aid + strlen (aid) + 1) - aid)) < len) &&
(((unsigned long) ((pass = user + strlen (user) + 1) - aid)) < len) &&
(((unsigned long) ((pass + strlen (pass)) - aid)) == len) &&
(*aid ? server_login (aid,pass,user,argc,argv) :
server_login (user,pass,NIL,argc,argv))) ret = myusername ();
fs_give ((void **) &aid);
}
return ret;
}

55
src/c-client/c-client.h Normal file
View File

@@ -0,0 +1,55 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: c-client master include for application programs
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 19 May 2000
* Last Edited: 6 December 2006
*/
#ifndef __CCLIENT_H /* nobody should include this twice... */
#define __CCLIENT_H
#ifdef __cplusplus /* help out people who use C++ compilers */
extern "C" {
/* If you use gcc, you may also have to use -fno-operator-names */
#define private cclientPrivate /* private to c-client */
#define and cclientAnd /* C99 doesn't realize that ISO 646 is dead */
#define or cclientOr
#define not cclientNot
#endif
#include "mail.h" /* primary interfaces */
#include "osdep.h" /* OS-dependent routines */
#include "rfc822.h" /* RFC822 and MIME routines */
#include "smtp.h" /* SMTP sending routines */
#include "nntp.h" /* NNTP sending routines */
#include "utf8.h" /* Unicode and charset routines */
#include "utf8aux.h" /* Unicode auxillary routines */
#include "misc.h" /* miscellaneous utility routines */
#ifdef __cplusplus /* undo the C++ mischief */
#undef private
}
#endif
#endif

45
src/c-client/env.h Normal file
View File

@@ -0,0 +1,45 @@
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Environment routines
*
* Author: Mark Crispin
* UW Technology
* University of Washington
* Seattle, WA 98195
* Internet: MRC@Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 13 February 2008
*/
/* Function prototypes */
long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim);
long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim);
void *env_parameters (long function,void *value);
void rfc822_date (char *date);
void rfc822_timezone (char *s,void *t);
void internal_date (char *date);
long server_input_wait (long seconds);
void server_init (char *server,char *service,char *sasl,
void *clkint,void *kodint,void *hupint,void *trmint,
void *staint);
long server_login (char *user,char *pass,char *authuser,int argc,char *argv[]);
long authserver_login (char *user,char *authuser,int argc,char *argv[]);
long anonymous_login (int argc,char *argv[]);
char *mylocalhost (void);
char *myhomedir (void);
char *mailboxfile (char *dst,char *name);
MAILSTREAM *default_proto (long type);

91
src/c-client/flstring.c Normal file
View File

@@ -0,0 +1,91 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: File string routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 15 April 1997
* Last Edited: 6 December 2006
*/
#include <stdio.h>
#include "mail.h"
#include "flstring.h"
/* String driver for stdio file strings */
static void file_string_init (STRING *s,void *data,unsigned long size);
static char file_string_next (STRING *s);
static void file_string_setpos (STRING *s,unsigned long i);
STRINGDRIVER file_string = {
file_string_init, /* initialize string structure */
file_string_next, /* get next byte in string structure */
file_string_setpos /* set position in string structure */
};
/* Initialize mail string structure for file
* Accepts: string structure
* pointer to string
* size of string
*/
static void file_string_init (STRING *s,void *data,unsigned long size)
{
s->data = data; /* note file descriptor */
/* big enough for one byte */
s->chunk = s->curpos = (char *) &s->data1;
s->size = size; /* data size */
s->cursize = s->chunksize = 1;/* always call stdio */
file_string_setpos (s,0); /* initial offset is 0 */
}
/* Get next character from string
* Accepts: string structure
* Returns: character, string structure chunk refreshed
*/
static char file_string_next (STRING *s)
{
char ret = *s->curpos;
s->offset++; /* advance position */
s->cursize = 1; /* reset size */
*s->curpos = (char) getc ((FILE *) s->data);
return ret;
}
/* Set string pointer position
* Accepts: string structure
* new position
*/
static void file_string_setpos (STRING *s,unsigned long i)
{
s->offset = i; /* note new offset */
fseek ((FILE *) s->data,i,SEEK_SET);
/* in case using returnstringstruct hack */
s->chunk = s->curpos = (char *) &s->data1;
*s->curpos = (char) getc ((FILE *) s->data);
}

30
src/c-client/flstring.h Normal file
View File

@@ -0,0 +1,30 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: File string routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 15 April 1997
* Last Edited: 30 August 2006
*/
extern STRINGDRIVER file_string;

34
src/c-client/fs.h Normal file
View File

@@ -0,0 +1,34 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Free storage management routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 30 August 2006
*/
/* Function prototypes */
void *fs_get (size_t size);
void fs_resize (void **block,size_t size);
void fs_give (void **block);

32
src/c-client/ftl.h Normal file
View File

@@ -0,0 +1,32 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Crash management routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 30 August 2006
*/
/* Function prototypes */
void fatal (char *string);

5670
src/c-client/imap4r1.c Normal file

File diff suppressed because it is too large Load Diff

281
src/c-client/imap4r1.h Normal file
View File

@@ -0,0 +1,281 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Interactive Mail Access Protocol 4rev1 (IMAP4R1) routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 14 October 1988
* Last Edited: 5 September 2007
*/
/* This include file is provided for applications which need to look under
* the covers at the IMAP driver and in particular want to do different
* operations depending upon the IMAP server's protocol level and
* capabilities. It is NOT included in the normal c-client.h application
* export, and most applications do NOT need the definitions in this file.
*
* As of October 15, 2003, it is believed that:
*
* Version RFC Status Known Implementations
* ------- --- ------ ---------------------
* IMAP1 none extinct experimental TOPS-20 server
* IMAP2 1064 extinct old TOPS-20, SUMEX servers
* IMAP2 1176 rare TOPS-20, old UW servers
* IMAP2bis expired I-D uncommon old UW, Cyrus servers
* IMAP3 1203 extinct none (never implemented)
* IMAP4 1730 rare old UW, Cyrus, Netscape servers
* IMAP4rev1 2060, 3501 ubiquitous UW, Cyrus, and many others
*
* Most client implementations will only interoperate with an IMAP4rev1
* server. c-client based client implementations can interoperate with IMAP2,
* IMAP2bis, IMAP4, and IMAP4rev1 servers, but only if they are very careful.
*
* The LEVELxxx() macros in this file enable the client to determine the
* server protocol level and capabilities. This file also contains a few
* backdoor calls into the IMAP driver.
*/
/* Server protocol level and capabilities */
typedef struct imap_cap {
unsigned int rfc1176 : 1; /* server is RFC-1176 IMAP2 */
unsigned int imap2bis : 1; /* server is IMAP2bis */
unsigned int imap4 : 1; /* server is IMAP4 (RFC 1730) */
unsigned int imap4rev1 : 1; /* server is IMAP4rev1 */
unsigned int acl : 1; /* server has ACL (RFC 2086) */
unsigned int quota : 1; /* server has QUOTA (RFC 2087) */
unsigned int litplus : 1; /* server has LITERAL+ (RFC 2088) */
unsigned int idle : 1; /* server has IDLE (RFC 2177) */
unsigned int mbx_ref : 1; /* server has mailbox referrals (RFC 2193) */
unsigned int log_ref : 1; /* server has login referrals (RFC 2221) */
unsigned int authanon : 1; /* server has anonymous SASL (RFC 2245) */
unsigned int namespace :1; /* server has NAMESPACE (RFC 2342) */
unsigned int uidplus : 1; /* server has UIDPLUS (RFC 2359) */
unsigned int starttls : 1; /* server has STARTTLS (RFC 2595) */
/* server disallows LOGIN command (RFC 2595) */
unsigned int logindisabled : 1;
unsigned int id : 1; /* server has ID (RFC 2971) */
unsigned int children : 1; /* server has CHILDREN (RFC 3348) */
unsigned int multiappend : 1; /* server has multi-APPEND (RFC 3502) ;*/
unsigned int binary : 1; /* server has BINARY (RFC 3516) */
unsigned int unselect : 1; /* server has UNSELECT */
unsigned int sasl_ir : 1; /* server has SASL-IR initial response */
unsigned int sort : 1; /* server has SORT */
unsigned int scan : 1; /* server has SCAN */
unsigned int urlauth : 1; /* server has URLAUTH (RFC 4467) */
unsigned int catenate : 1; /* server has CATENATE (RFC 4469) */
unsigned int condstore : 1; /* server has CONDSTORE (RFC 4551) */
unsigned int esearch : 1; /* server has ESEARCH (RFC 4731) */
unsigned int within : 1; /* server has WITHIN (RFC 5032) */
unsigned int extlevel; /* extension data level supported by server */
/* supported authenticators */
unsigned int auth : MAXAUTHENTICATORS;
THREADER *threader; /* list of threaders */
} IMAPCAP;
/* IMAP4rev1 level or better */
#define LEVELIMAP4rev1(stream) imap_cap (stream)->imap4rev1
#define LEVELSTATUS LEVELIMAP4rev1
/* IMAP4 level or better (not including RFC 1730 design mistakes) */
#define LEVELIMAP4(stream) (imap_cap (stream)->imap4rev1 || \
imap_cap (stream)->imap4)
/* IMAP4 RFC-1730 level */
#define LEVEL1730(stream) imap_cap (stream)->imap4
/* IMAP2bis level or better */
#define LEVELIMAP2bis(stream) imap_cap (stream)->imap2bis
/* IMAP2 RFC-1176 level or better */
#define LEVEL1176(stream) imap_cap (stream)->rfc1176
/* IMAP2 RFC-1064 or better */
#define LEVEL1064(stream) 1
/* Has ACL extension */
#define LEVELACL(stream) imap_cap (stream)->acl
/* Has QUOTA extension */
#define LEVELQUOTA(stream) imap_cap (stream)->quota
/* Has LITERALPLUS extension */
#define LEVELLITERALPLUS(stream) imap_cap (stream)->litplus
/* Has IDLE extension */
#define LEVELIDLE(stream) imap_cap (stream)->idle
/* Has mailbox referrals */
#define LEVELMBX_REF(stream) imap_cap (stream)->mbx_ref
/* Has login referrals */
#define LEVELLOG_REF(stream) imap_cap (stream)->log_ref
/* Has AUTH=ANONYMOUS extension */
#define LEVELANONYMOUS(stream) imap_cap (stream)->authanon
/* Has NAMESPACE extension */
#define LEVELNAMESPACE(stream) imap_cap (stream)->namespace
/* Has UIDPLUS extension */
#define LEVELUIDPLUS(stream) imap_cap (stream)->uidplus
/* Has STARTTLS extension */
#define LEVELSTARTTLS(stream) imap_cap (stream)->starttls
/* Has LOGINDISABLED extension */
#define LEVELLOGINDISABLED(stream) imap_cap (stream)->logindisabled
/* Has ID extension */
#define LEVELID(stream) imap_cap (stream)->id
/* Has CHILDREN extension */
#define LEVELCHILDREN(stream) imap_cap (stream)->children
/* Has MULTIAPPEND extension */
#define LEVELMULTIAPPEND(stream) imap_cap (stream)->multiappend
/* Has BINARY extension */
#define LEVELBINARY(stream) imap_cap (stream)->binary
/* Has UNSELECT extension */
#define LEVELUNSELECT(stream) imap_cap (stream)->unselect
/* Has SASL initial response extension */
#define LEVELSASLIR(stream) imap_cap (stream)->sasl_ir
/* Has SORT extension */
#define LEVELSORT(stream) imap_cap (stream)->sort
/* Has at least one THREAD extension */
#define LEVELTHREAD(stream) ((imap_cap (stream)->threader) ? T : NIL)
/* Has SCAN extension */
#define LEVELSCAN(stream) imap_cap (stream)->scan
/* Has URLAUTH extension */
#define LEVELURLAUTH(stream) imap_cap (stream)->urlauth
/* Has CATENATE extension */
#define LEVELCATENATE(stream) imap_cap (stream)->catenate
/* Has CONDSTORE extension */
#define LEVELCONDSTORE(stream) imap_cap (stream)->condstore
/* Has ESEARCH extension */
#define LEVELESEARCH(stream) imap_cap (stream)->esearch
/* Has WITHIN extension */
#define LEVELWITHIN(stream) imap_cap (stream)->within
/* Body structure extension levels */
/* These are in BODYSTRUCTURE order. Note that multipart bodies do not have
* body-fld-md5. This is alright, since all subsequent body structure
* extensions are in both singlepart and multipart bodies. If that ever
* changes, this will have to be split.
*/
#define BODYEXTMD5 1 /* body-fld-md5 */
#define BODYEXTDSP 2 /* body-fld-dsp */
#define BODYEXTLANG 3 /* body-fld-lang */
#define BODYEXTLOC 4 /* body-fld-loc */
/* Function prototypes */
IMAPCAP *imap_cap (MAILSTREAM *stream);
char *imap_host (MAILSTREAM *stream);
long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg,
STRINGLIST *stl,SIZEDTEXT *text);
/* Temporary */
long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights);
long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id);
long imap_getacl (MAILSTREAM *stream,char *mailbox);
long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id);
long imap_myrights (MAILSTREAM *stream,char *mailbox);
long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits);
long imap_getquota (MAILSTREAM *stream,char *qroot);
long imap_getquotaroot (MAILSTREAM *stream,char *mailbox);

6331
src/c-client/mail.c Normal file

File diff suppressed because it is too large Load Diff

1837
src/c-client/mail.h Normal file

File diff suppressed because it is too large Load Diff

475
src/c-client/misc.c Normal file
View File

@@ -0,0 +1,475 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Miscellaneous utility routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 5 July 1988
* Last Edited: 6 December 2006
*
* This original version of this file is
* Copyright 1988 Stanford University
* and was developed in the Symbolic Systems Resources Group of the Knowledge
* Systems Laboratory at Stanford University in 1987-88, and was funded by the
* Biomedical Research Technology Program of the NationalInstitutes of Health
* under grant number RR-00785.
*/
#include <ctype.h>
#include "c-client.h"
/* Convert ASCII string to all uppercase
* Accepts: string pointer
* Returns: string pointer
*
* Don't use islower/toupper since this function must be ASCII only.
*/
unsigned char *ucase (unsigned char *s)
{
unsigned char *t;
/* if lowercase covert to upper */
for (t = s; *t; t++) if ((*t >= 'a') && (*t <= 'z')) *t -= ('a' - 'A');
return s; /* return string */
}
/* Convert string to all lowercase
* Accepts: string pointer
* Returns: string pointer
*
* Don't use isupper/tolower since this function must be ASCII only.
*/
unsigned char *lcase (unsigned char *s)
{
unsigned char *t;
/* if uppercase covert to lower */
for (t = s; *t; t++) if ((*t >= 'A') && (*t <= 'Z')) *t += ('a' - 'A');
return s; /* return string */
}
/* Copy string to free storage
* Accepts: source string
* Returns: free storage copy of string
*/
char *cpystr (const char *string)
{
return string ? strcpy ((char *) fs_get (1 + strlen (string)),string) : NIL;
}
/* Copy text/size to free storage as sized text
* Accepts: destination sized text
* pointer to source text
* size of source text
* Returns: text as a char *
*/
char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size)
{
/* flush old space */
if (dst->data) fs_give ((void **) &dst->data);
/* copy data in sized text */
memcpy (dst->data = (unsigned char *)
fs_get ((size_t) (dst->size = size) + 1),text,(size_t) size);
dst->data[size] = '\0'; /* tie off text */
return (char *) dst->data; /* convenience return */
}
/* Copy sized text to free storage as sized text
* Accepts: destination sized text
* source sized text
* Returns: text as a char *
*/
char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src)
{
/* flush old space */
if (dst->data) fs_give ((void **) &dst->data);
/* copy data in sized text */
memcpy (dst->data = (unsigned char *)
fs_get ((size_t) (dst->size = src->size) + 1),
src->data,(size_t) src->size);
dst->data[dst->size] = '\0'; /* tie off text */
return (char *) dst->data; /* convenience return */
}
/* Copy stringstruct to free storage as sized text
* Accepts: destination sized text
* source stringstruct
* Returns: text as a char *
*/
char *textcpystring (SIZEDTEXT *text,STRING *bs)
{
unsigned long i = 0;
/* clear old space */
if (text->data) fs_give ((void **) &text->data);
/* make free storage space in sized text */
text->data = (unsigned char *) fs_get ((size_t) (text->size = SIZE (bs)) +1);
while (i < text->size) text->data[i++] = SNX (bs);
text->data[i] = '\0'; /* tie off text */
return (char *) text->data; /* convenience return */
}
/* Copy stringstruct from offset to free storage as sized text
* Accepts: destination sized text
* source stringstruct
* offset into stringstruct
* size of source text
* Returns: text as a char *
*/
char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset,
unsigned long size)
{
unsigned long i = 0;
/* clear old space */
if (text->data) fs_give ((void **) &text->data);
SETPOS (bs,offset); /* offset the string */
/* make free storage space in sized text */
text->data = (unsigned char *) fs_get ((size_t) (text->size = size) + 1);
while (i < size) text->data[i++] = SNX (bs);
text->data[i] = '\0'; /* tie off text */
return (char *) text->data; /* convenience return */
}
/* Returns index of rightmost bit in word
* Accepts: pointer to a 32 bit value
* Returns: -1 if word is 0, else index of rightmost bit
*
* Bit is cleared in the word
*/
unsigned long find_rightmost_bit (unsigned long *valptr)
{
unsigned long value = *valptr;
unsigned long bit = 0;
if (!(value & 0xffffffff)) return 0xffffffff;
/* binary search for rightmost bit */
if (!(value & 0xffff)) value >>= 16, bit += 16;
if (!(value & 0xff)) value >>= 8, bit += 8;
if (!(value & 0xf)) value >>= 4, bit += 4;
if (!(value & 0x3)) value >>= 2, bit += 2;
if (!(value & 0x1)) value >>= 1, bit += 1;
*valptr ^= (1 << bit); /* clear specified bit */
return bit;
}
/* Return minimum of two integers
* Accepts: integer 1
* integer 2
* Returns: minimum
*/
long min (long i,long j)
{
return ((i < j) ? i : j);
}
/* Return maximum of two integers
* Accepts: integer 1
* integer 2
* Returns: maximum
*/
long max (long i,long j)
{
return ((i > j) ? i : j);
}
/* Search, case-insensitive for ASCII characters
* Accepts: base string
* length of base string
* pattern string
* length of pattern string
* Returns: T if pattern exists inside base, else NIL
*/
long search (unsigned char *base,long basec,unsigned char *pat,long patc)
{
long i,j,k;
int c;
unsigned char mask[256];
static unsigned char alphatab[256] = {
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255,
255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
};
/* validate arguments */
if (base && (basec > 0) && pat && (basec >= patc)) {
if (patc <= 0) return T; /* empty pattern always succeeds */
memset (mask,0,256); /* initialize search validity mask */
for (i = 0; i < patc; i++) if (!mask[c = pat[i]]) {
/* mark single character if non-alphabetic */
if (alphatab[c] & 0x20) mask[c] = T;
/* else mark both cases */
else mask[c & 0xdf] = mask[c | 0x20] = T;
}
/* Boyer-Moore type search */
for (i = --patc; i < basec; i += (mask[c] ? 1 : (j + 1)))
for (j = patc,c = base[k = i]; !((c ^ pat[j]) & alphatab[c]);
j--,c = base[--k])
if (!j) return T; /* found a match! */
}
return NIL; /* pattern not found */
}
/* Boyer-Moore string search
* Accepts: base string
* length of base string
* pattern string
* length of pattern string
* Returns: T if pattern exists inside base, else NIL
*/
long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc)
{
long i,j,k;
int c;
unsigned char mask[256];
/* validate arguments */
if (base && (basec > 0) && pat && (basec >= patc)) {
if (patc <= 0) return T; /* empty pattern always succeeds */
memset (mask,0,256); /* initialize search validity mask */
for (i = 0; i < patc; i++) mask[pat[i]] = T;
/* Boyer-Moore type search */
for (i = --patc, c = pat[i]; i < basec; i += (mask[c] ? 1 : (j + 1)))
for (j = patc,c = base[k = i]; (c == pat[j]); j--,c = base[--k])
if (!j) return T; /* found a match! */
}
return NIL; /* pattern not found */
}
/* Create a hash table
* Accepts: size of new table (note: should be a prime)
* Returns: hash table
*/
HASHTAB *hash_create (size_t size)
{
size_t i = sizeof (size_t) + size * sizeof (HASHENT *);
HASHTAB *ret = (HASHTAB *) memset (fs_get (i),0,i);
ret->size = size;
return ret;
}
/* Destroy hash table
* Accepts: hash table
*/
void hash_destroy (HASHTAB **hashtab)
{
if (*hashtab) {
hash_reset (*hashtab); /* reset hash table */
fs_give ((void **) hashtab);
}
}
/* Reset hash table
* Accepts: hash table
*/
void hash_reset (HASHTAB *hashtab)
{
size_t i;
HASHENT *ent,*nxt;
/* free each hash entry */
for (i = 0; i < hashtab->size; i++) if (ent = hashtab->table[i])
for (hashtab->table[i] = NIL; ent; ent = nxt) {
nxt = ent->next; /* get successor */
fs_give ((void **) &ent); /* flush this entry */
}
}
/* Calculate index into hash table
* Accepts: hash table
* entry name
* Returns: index
*/
unsigned long hash_index (HASHTAB *hashtab,char *key)
{
unsigned long i,ret;
/* polynomial of letters of the word */
for (ret = 0; i = (unsigned int) *key++; ret += i) ret *= HASHMULT;
return ret % (unsigned long) hashtab->size;
}
/* Look up name in hash table
* Accepts: hash table
* key
* Returns: associated data
*/
void **hash_lookup (HASHTAB *hashtab,char *key)
{
HASHENT *ret;
for (ret = hashtab->table[hash_index (hashtab,key)]; ret; ret = ret->next)
if (!strcmp (key,ret->name)) return ret->data;
return NIL;
}
/* Add entry to hash table
* Accepts: hash table
* key
* associated data
* number of extra data slots
* Returns: hash entry
* Caller is responsible for ensuring that entry isn't already in table
*/
HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra)
{
unsigned long i = hash_index (hashtab,key);
size_t j = sizeof (HASHENT) + (extra * sizeof (void *));
HASHENT *ret = (HASHENT *) memset (fs_get (j),0,j);
ret->next = hashtab->table[i];/* insert as new head in this index */
ret->name = key; /* set up hash key */
ret->data[0] = data; /* and first data */
return hashtab->table[i] = ret;
}
/* Look up name in hash table
* Accepts: hash table
* key
* associated data
* number of extra data slots
* Returns: associated data
*/
void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra)
{
HASHENT *ret;
unsigned long i = hash_index (hashtab,key);
size_t j = sizeof (HASHENT) + (extra * sizeof (void *));
for (ret = hashtab->table[i]; ret; ret = ret->next)
if (!strcmp (key,ret->name)) return ret->data;
ret = (HASHENT *) memset (fs_get (j),0,j);
ret->next = hashtab->table[i];/* insert as new head in this index */
ret->name = key; /* set up hash key */
ret->data[0] = data; /* and first data */
return (hashtab->table[i] = ret)->data;
}
/* Convert two hex characters into byte
* Accepts: char for high nybble
* char for low nybble
* Returns: byte
*
* Arguments must be isxdigit validated
*/
unsigned char hex2byte (unsigned char c1,unsigned char c2)
{
/* merge the two nybbles */
return ((c1 -= (isdigit (c1) ? '0' : ((c1 <= 'Z') ? 'A' : 'a') - 10)) << 4) +
(c2 - (isdigit (c2) ? '0' : ((c2 <= 'Z') ? 'A' : 'a') - 10));
}
/* Compare two unsigned longs
* Accepts: first value
* second value
* Returns: -1 if l1 < l2, 0 if l1 == l2, 1 if l1 > l2
*/
int compare_ulong (unsigned long l1,unsigned long l2)
{
if (l1 < l2) return -1;
if (l1 > l2) return 1;
return 0;
}
/* Compare two unsigned chars, case-independent
* Accepts: first value
* second value
* Returns: -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2
*
* Don't use isupper/tolower since this function must be ASCII only.
*/
int compare_uchar (unsigned char c1,unsigned char c2)
{
return compare_ulong (((c1 >= 'A') && (c1 <= 'Z')) ? c1 + ('a' - 'A') : c1,
((c2 >= 'A') && (c2 <= 'Z')) ? c2 + ('a' - 'A') : c2);
}
/* Compare two case-independent ASCII strings
* Accepts: first string
* second string
* Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2
*/
int compare_cstring (unsigned char *s1,unsigned char *s2)
{
int i;
if (!s1) return s2 ? -1 : 0; /* empty string cases */
else if (!s2) return 1;
for (; *s1 && *s2; s1++,s2++) if (i = (compare_uchar (*s1,*s2))) return i;
if (*s1) return 1; /* first string is longer */
return *s2 ? -1 : 0; /* second string longer : strings identical */
}
/* Compare case-independent string with sized text
* Accepts: first string
* sized text
* Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2
*/
int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2)
{
int i;
unsigned char *s;
unsigned long j;
if (!s1) return s2 ? -1 : 0; /* null string cases */
else if (!s2) return 1;
for (s = (char *) s2->data,j = s2->size; *s1 && j; ++s1,++s,--j)
if (i = (compare_uchar (*s1,*s))) return i;
if (*s1) return 1; /* first string is longer */
return j ? -1 : 0; /* second string longer : strings identical */
}

110
src/c-client/misc.h Normal file
View File

@@ -0,0 +1,110 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Miscellaneous utility routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 5 July 1988
* Last Edited: 30 August 2006
*
* This original version of this file is
* Copyright 1988 Stanford University
* and was developed in the Symbolic Systems Resources Group of the Knowledge
* Systems Laboratory at Stanford University in 1987-88, and was funded by the
* Biomedical Research Technology Program of the NationalInstitutes of Health
* under grant number RR-00785.
*/
/* Hash table operations */
#define HASHMULT 29 /* hash polynomial multiplier */
#define HASHENT struct hash_entry
HASHENT {
HASHENT *next; /* next entry with same hash code */
char *name; /* name of this hash entry */
void *data[1]; /* data of this hash entry */
};
#define HASHTAB struct hash_table
HASHTAB {
size_t size; /* size of this table */
HASHENT *table[1]; /* table */
};
/* KLUDGE ALERT!!!
*
* Yes, write() is overridden here instead of in osdep. This
* is because misc.h is one of the last files that most things #include, so
* this should avoid problems with some system #include file.
*/
#define write safe_write
/* Some C compilers have these as macros */
#undef min
#undef max
/* And some C libraries have these as int functions */
#define min Min
#define max Max
/* Compatibility definitions */
#define pmatch(s,pat) \
pmatch_full (s,pat,NIL)
/* Function prototypes */
unsigned char *ucase (unsigned char *string);
unsigned char *lcase (unsigned char *string);
char *cpystr (const char *string);
char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size);
char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src);
char *textcpystring (SIZEDTEXT *text,STRING *bs);
char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset,
unsigned long size);
unsigned long find_rightmost_bit (unsigned long *valptr);
long min (long i,long j);
long max (long i,long j);
long search (unsigned char *base,long basec,unsigned char *pat,long patc);
long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc);
HASHTAB *hash_create (size_t size);
void hash_destroy (HASHTAB **hashtab);
void hash_reset (HASHTAB *hashtab);
unsigned long hash_index (HASHTAB *hashtab,char *key);
void **hash_lookup (HASHTAB *hashtab,char *key);
HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra);
void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra);
unsigned char hex2byte (unsigned char c1,unsigned char c2);
int compare_ulong (unsigned long l1,unsigned long l2);
int compare_uchar (unsigned char c1,unsigned char c2);
int compare_cstring (unsigned char *s1,unsigned char *s2);
int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2);

104
src/c-client/netmsg.c Normal file
View File

@@ -0,0 +1,104 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Network message (SMTP/NNTP/POP2/POP3) routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 8 June 1995
* Last Edited: 6 December 2006
*/
#include <stdio.h>
#include <errno.h>
extern int errno; /* just in case */
#include "c-client.h"
#include "netmsg.h"
#include "flstring.h"
/* Network message read
* Accepts: file
* number of bytes to read
* buffer address
* Returns: T if success, NIL otherwise
*/
long netmsg_read (void *stream,unsigned long count,char *buffer)
{
return (fread (buffer,(size_t) 1,(size_t) count,(FILE *) stream) == count) ?
T : NIL;
}
/* Slurp dot-terminated text from NET
* Accepts: NET stream
* place to return size
* place to return header size
* Returns: file descriptor
*/
FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz)
{
unsigned long i;
char *s,*t,tmp[MAILTMPLEN];
FILE *f = tmpfile ();
if (!f) {
sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
if (f = fopen (tmp,"wb+")) unlink (tmp);
else {
sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
MM_LOG (tmp,ERROR);
return NIL;
}
}
*size = 0; /* initially emtpy */
if (hsiz) *hsiz = 0;
while (s = net_getline (stream)) {
if (*s == '.') { /* possible end of text? */
if (s[1]) t = s + 1; /* pointer to true start of line */
else {
fs_give ((void **) &s); /* free the line */
break; /* end of data */
}
}
else t = s; /* want the entire line */
if (f) { /* copy it to the file */
i = strlen (t); /* size of line */
if ((fwrite (t,(size_t) 1,(size_t) i,f) == i) &&
(fwrite ("\015\012",(size_t) 1,(size_t) 2,f) == 2)) {
*size += i + 2; /* tally up size of data */
/* note header position */
if (!i && hsiz && !*hsiz) *hsiz = *size;
}
else {
sprintf (tmp,"Error writing scratch file at byte %lu",*size);
MM_LOG (tmp,ERROR);
fclose (f); /* forget it */
f = NIL; /* failure now */
}
}
fs_give ((void **) &s); /* free the line */
}
/* if making a file, rewind to start of file */
if (f) fseek (f,(unsigned long) 0,SEEK_SET);
/* header consumes entire message */
if (hsiz && !*hsiz) *hsiz = *size;
return f; /* return the file descriptor */
}

32
src/c-client/netmsg.h Normal file
View File

@@ -0,0 +1,32 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Network message (SMTP/NNTP/POP2/POP3) routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 8 June 1995
* Last Edited: 30 August 2006
*/
/* stream must be void* for use as readfn_t */
long netmsg_read (void *stream,unsigned long count,char *buffer);
FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz);

510
src/c-client/newsrc.c Normal file
View File

@@ -0,0 +1,510 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Newsrc manipulation routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 12 September 1994
* Last Edited: 30 August 2006
*/
#include <ctype.h>
#include <stdio.h>
#include "c-client.h"
#include "newsrc.h"
#ifndef OLDFILESUFFIX
#define OLDFILESUFFIX ".old"
#endif
/* Error message
* Accepts: message format
* additional message string
* message level
* Returns: NIL, always
*/
long newsrc_error (char *fmt,char *text,long errflg)
{
char tmp[MAILTMPLEN];
sprintf (tmp,fmt,text);
MM_LOG (tmp,errflg);
return NIL;
}
/* Write error message
* Accepts: newsrc name
* file designator
* file designator
* Returns: NIL, always
*/
long newsrc_write_error (char *name,FILE *f1,FILE *f2)
{
if (f1) fclose (f1); /* close file designators */
if (f2) fclose (f2);
return newsrc_error ("Error writing to %.80s",name,ERROR);
}
/* Create newsrc file in local form
* Accepts: MAIL stream
* notification flag
* Returns: file designator of newsrc
*/
FILE *newsrc_create (MAILSTREAM *stream,int notify)
{
char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
FILE *f = fopen (newsrc,"wb");
if (!f) newsrc_error ("Unable to create news state %.80s",newsrc,ERROR);
else if (notify) newsrc_error ("Creating news state %.80s",newsrc,WARN);
return f;
}
/* Write new state in newsrc
* Accepts: file designator of newsrc
* group
* new subscription status character
* newline convention
* Returns: T if successful, NIL otherwise
*/
long newsrc_newstate (FILE *f,char *group,char state,char *nl)
{
long ret = (f && (fputs (group,f) != EOF) && ((putc (state,f)) != EOF) &&
((putc (' ',f)) != EOF) && (fputs (nl,f) != EOF)) ? LONGT : NIL;
if (fclose (f) == EOF) ret = NIL;
return ret;
}
/* Write messages in newsrc
* Accepts: file designator of newsrc
* MAIL stream
* message number/newsgroup message map
* newline convention
* Returns: T if successful, NIL otherwise
*/
long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl)
{
unsigned long i,j,k;
char tmp[MAILTMPLEN];
MESSAGECACHE *elt;
int c = ' ';
if (stream->nmsgs) { /* have any messages? */
for (i = 1,j = k = (mail_elt (stream,i)->private.uid > 1) ? 1 : 0;
i <= stream->nmsgs; ++i) {
/* deleted message? */
if ((elt = mail_elt (stream,i))->deleted) {
k = elt->private.uid; /* this is the top of the current range */
if (!j) j = k; /* if no range in progress, start one */
}
else if (j) { /* unread message, ending a range */
/* calculate end of range */
if (k = elt->private.uid - 1) {
/* dump range */
sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k);
if (fputs (tmp,f) == EOF) return NIL;
c = ','; /* need a comma after the first time */
}
j = 0; /* no more range in progress */
}
}
if (j) { /* dump trailing range */
sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k);
if (fputs (tmp,f) == EOF) return NIL;
}
}
/* write trailing newline, return */
return (fputs (nl,f) == EOF) ? NIL : LONGT;
}
/* List subscribed newsgroups
* Accepts: MAIL stream
* prefix to append name
* pattern to search
*/
void newsrc_lsub (MAILSTREAM *stream,char *pattern)
{
char *s,*t,*lcl,name[MAILTMPLEN];
int c = ' ';
int showuppers = pattern[strlen (pattern) - 1] == '%';
FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
if (f) { /* got file? */
/* remote name? */
if (*(lcl = strcpy (name,pattern)) == '{') lcl = strchr (lcl,'}') + 1;
if (*lcl == '#') lcl += 6; /* namespace format name? */
while (c != EOF) { /* yes, read newsrc */
for (s = lcl; (s < (name + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
(c != ':') && (c != '!') && (c != '\015') && (c != '\012');
*s++ = c);
if (c == ':') { /* found a subscribed newsgroup? */
*s = '\0'; /* yes, tie off name */
/* report if match */
if (pmatch_full (name,pattern,'.')) mm_lsub (stream,'.',name,NIL);
else while (showuppers && (t = strrchr (lcl,'.'))) {
*t = '\0'; /* tie off the name */
if (pmatch_full (name,pattern,'.'))
mm_lsub (stream,'.',name,LATT_NOSELECT);
}
}
while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
}
fclose (f);
}
}
/* Update subscription status of newsrc
* Accepts: MAIL stream
* group
* new subscription status character
* Returns: T if successful, NIL otherwise
*/
long newsrc_update (MAILSTREAM *stream,char *group,char state)
{
char tmp[MAILTMPLEN];
char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
long ret = NIL;
FILE *f = fopen (newsrc,"r+b");
if (f) { /* update existing file */
int c = 0;
char *s,nl[3];
long pos = 0;
nl[0] = nl[1] = nl[2]='\0'; /* no newline known yet */
do { /* read newsrc */
for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
(c != ':') && (c != '!') && (c != '\015') && (c != '\012');
*s++ = c) pos = ftell (f);
*s = '\0'; /* tie off name */
/* found the newsgroup? */
if (((c == ':') || (c == '!')) && !strcmp (tmp,group)) {
if (c == state) { /* already at that state? */
if (c == ':') newsrc_error("Already subscribed to %.80s",group,WARN);
ret = LONGT; /* noop the update */
}
/* write the character */
else if (!fseek (f,pos,0)) ret = ((putc (state,f)) == EOF) ? NIL:LONGT;
if (fclose (f) == EOF) ret = NIL;
f = NIL; /* done with file */
break;
}
/* gobble remainder of this line */
while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
/* need to know about newlines and found it? */
if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){
/* sniff and see if an LF */
if ((c = getc (f)) == '\012') nl[1] = c;
else ungetc (c,f); /* nope, push it back */
}
} while (c != EOF);
if (f) { /* still haven't written it yet? */
if (nl[0]) { /* know its newline convention? */
fseek (f,0L,2); /* yes, seek to end of file */
ret = newsrc_newstate (f,group,state,nl);
}
else { /* can't find a newline convention */
fclose (f); /* punt the file */
/* can't win if read something */
if (pos) newsrc_error ("Unknown newline convention in %.80s",
newsrc,ERROR);
/* file must have been empty, rewrite it */
else ret = newsrc_newstate(newsrc_create(stream,NIL),group,state,"\n");
}
}
}
/* create new file */
else ret = newsrc_newstate (newsrc_create (stream,T),group,state,"\n");
return ret; /* return with update status */
}
/* Update newsgroup status in stream
* Accepts: newsgroup name
* MAIL stream
* Returns: number of recent messages
*/
long newsrc_read (char *group,MAILSTREAM *stream)
{
int c = 0;
char *s,tmp[MAILTMPLEN];
unsigned long i,j;
MESSAGECACHE *elt;
unsigned long m = 1,recent = 0,unseen = 0;
FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
if (f) do { /* read newsrc */
for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
(c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
*s = '\0'; /* tie off name */
if ((c==':') || (c=='!')) { /* found newsgroup? */
if (strcmp (tmp,group)) /* group name match? */
while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
else { /* yes, skip leading whitespace */
while ((c = getc (f)) == ' ');
/* only if unprocessed messages */
if (stream->nmsgs) while (f && (m <= stream->nmsgs)) {
/* collect a number */
if (isdigit (c)) { /* better have a number */
for (i = 0,j = 0; isdigit (c); c = getc (f)) i = i*10 + (c-'0');
if (c == '-') for (c = getc (f); isdigit (c); c = getc (f))
j = j*10 +(c-'0');/* collect second value if range */
if (!unseen && (mail_elt (stream,m)->private.uid < i)) unseen = m;
/* skip messages before first value */
while ((m <= stream->nmsgs) &&
((elt = mail_elt (stream,m))->private.uid < i) && m++)
elt->valid = T;
/* do all messages in range */
while ((m <= stream->nmsgs) && (elt = mail_elt (stream,m)) &&
(j ? ((elt->private.uid >= i) && (elt->private.uid <= j)) :
(elt->private.uid == i)) && m++)
elt->valid = elt->deleted = T;
}
switch (c) { /* what is the delimiter? */
case ',': /* more to come */
c = getc (f); /* get first character of number */
break;
default: /* bogus character */
sprintf (tmp,"Bogus character 0x%x in news state",(unsigned int)c);
MM_LOG (tmp,ERROR);
case EOF: case '\015': case '\012':
fclose (f); /* all done - close the file */
f = NIL;
break;
}
}
else { /* empty newsgroup */
while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
fclose (f); /* all done - close the file */
f = NIL;
}
}
}
} while (f && (c != EOF)); /* until file closed or EOF */
if (f) { /* still have file open? */
sprintf (tmp,"No state for newsgroup %.80s found, reading as new",group);
MM_LOG (tmp,WARN);
fclose (f); /* close the file */
}
if (m <= stream->nmsgs) { /* any messages beyond newsrc range? */
if (!unseen) unseen = m; /* then this must be the first unseen one */
do {
elt = mail_elt (stream,m++);
elt->valid = elt->recent = T;
++recent; /* count another recent message */
}
while (m <= stream->nmsgs);
}
if (unseen) { /* report first unseen message */
sprintf (tmp,"[UNSEEN] %lu is first unseen message in %.80s",unseen,group);
MM_NOTIFY (stream,tmp,(long) NIL);
}
return recent;
}
/* Update newsgroup entry in newsrc
* Accepts: newsgroup name
* MAIL stream
* Returns: T if successful, NIL otherwise
*/
long newsrc_write (char *group,MAILSTREAM *stream)
{
long ret = NIL;
int c = 0,d = EOF;
char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
char *s,tmp[MAILTMPLEN],backup[MAILTMPLEN],nl[3];
FILE *f,*bf;
nl[0] = nl[1] = nl[2] = '\0'; /* no newline known yet */
if (f = fopen (newsrc,"rb")) {/* have existing newsrc file? */
if (!(bf = fopen ((strcat (strcpy (backup,newsrc),OLDFILESUFFIX)),"wb"))) {
fclose (f); /* punt input file */
return newsrc_error("Can't create backup news state %.80s",backup,ERROR);
}
/* copy to backup file */
while ((c = getc (f)) != EOF) {
/* need to know about newlines and found it? */
if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){
/* sniff and see if an LF */
if ((c = getc (f)) == '\012') nl[1] = c;
ungetc (c,f); /* push it back */
}
/* write to backup file */
if ((d = putc (c,bf)) == EOF) {
fclose (f); /* punt input file */
return newsrc_error ("Error writing backup news state %.80s",
newsrc,ERROR);
}
}
fclose (f); /* close existing file */
if (fclose (bf) == EOF) /* and backup file */
return newsrc_error ("Error closing backup news state %.80s",
newsrc,ERROR);
if (d == EOF) { /* open for write if empty file */
if (f = newsrc_create (stream,NIL)) bf = NIL;
else return NIL;
}
else if (!nl[0]) /* make sure newlines valid */
return newsrc_error ("Unknown newline convention in %.80s",newsrc,ERROR);
/* now read backup file */
else if (!(bf = fopen (backup,"rb")))
return newsrc_error ("Error reading backup news state %.80s",
backup,ERROR);
/* open newsrc for writing */
else if (!(f = fopen (newsrc,"wb"))) {
fclose (bf); /* punt backup */
return newsrc_error ("Can't rewrite news state %.80s",newsrc,ERROR);
}
}
else { /* create new newsrc file */
if (f = newsrc_create (stream,T)) bf = NIL;
else return NIL; /* can't create newsrc */
}
while (bf) { /* read newsrc */
for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (bf)) != EOF) &&
(c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
*s = '\0'; /* tie off name */
/* saw correct end of group delimiter? */
if (tmp[0] && ((c == ':') || (c == '!'))) {
/* yes, write newsgroup name and delimiter */
if ((tmp[0] && (fputs (tmp,f) == EOF)) || ((putc (c,f)) == EOF))
return newsrc_write_error (newsrc,bf,f);
if (!strcmp (tmp,group)) {/* found correct group? */
/* yes, write new status */
if (!newsrc_newmessages (f,stream,nl[0] ? nl : "\n"))
return newsrc_write_error (newsrc,bf,f);
/* skip past old data */
while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012'));
/* skip past newline */
while ((c == '\015') || (c == '\012')) c = getc (bf);
while (c != EOF) { /* copy remainder of file */
if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
c = getc (bf); /* get next character */
}
/* done with file */
if (fclose (f) == EOF) return newsrc_write_error (newsrc,bf,NIL);
f = NIL;
}
/* copy remainder of line */
else while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012'))
if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
if (c == '\015') { /* write CR if seen */
if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
/* sniff to see if LF */
if (((c = getc (bf)) != EOF) && (c != '\012')) ungetc (c,bf);
}
/* write LF if seen */
if ((c == '\012') && (putc (c,f) == EOF))
return newsrc_write_error (newsrc,bf,f);
}
if (c == EOF) { /* hit end of file? */
fclose (bf); /* yup, close the file */
bf = NIL;
}
}
if (f) { /* still have newsrc file open? */
ret = ((fputs (group,f) != EOF) && ((putc (':',f)) != EOF) &&
newsrc_newmessages (f,stream,nl[0] ? nl : "\n")) ? LONGT : NIL;
if (fclose (f) == EOF) ret = newsrc_write_error (newsrc,NIL,NIL);
}
else ret = LONGT;
return ret;
}
/* Get newsgroup state as text stream
* Accepts: MAIL stream
* newsgroup name
* Returns: string containing newsgroup state, or NIL if not found
*/
char *newsrc_state (MAILSTREAM *stream,char *group)
{
int c = 0;
char *s,tmp[MAILTMPLEN];
long pos;
size_t size;
FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
if (f) do { /* read newsrc */
for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
(c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
*s = '\0'; /* tie off name */
if ((c==':') || (c=='!')) { /* found newsgroup? */
if (strcmp (tmp,group)) /* group name match? */
while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
else { /* yes, skip leading whitespace */
do pos = ftell (f);
while ((c = getc (f)) == ' ');
/* count characters in state */
for (size = 0; (c != '\015') && (c != '\012') && (c != EOF); size++)
c = getc (f);
/* now copy it */
s = (char *) fs_get (size + 1);
fseek (f,pos,SEEK_SET);
fread (s,(size_t) 1,size,f);
s[size] = '\0'; /* tie off string */
fclose (f); /* all done - close the file */
return s;
}
}
} while (f && (c != EOF)); /* until file closed or EOF */
sprintf (tmp,"No state for newsgroup %.80s found",group);
MM_LOG (tmp,WARN);
if (f) fclose (f); /* close the file */
return NIL; /* not found return */
}
/* Check UID in newsgroup state
* Accepts: newsgroup state string
* uid
* returned recent count
* returned unseen count
*/
void newsrc_check_uid (unsigned char *state,unsigned long uid,
unsigned long *recent,unsigned long *unseen)
{
unsigned long i,j;
while (*state) { /* until run out of state string */
/* collect a number */
for (i = 0; isdigit (*state); i = i*10 + (*state++ - '0'));
if (*state != '-') j = i; /* coerce single mesage into range */
else { /* have a range */
for (j = 0; isdigit (*++state); j = j*10 + (*state - '0'));
if (!j) j = i; /* guard against -0 */
if (j < i) return; /* bogon if end less than start */
}
if (*state == ',') state++; /* skip past comma */
else if (*state) return; /* otherwise it's a bogon */
if (uid <= j) { /* covered by upper bound? */
if (uid < i) ++*unseen; /* unseen if not covered by lower bound */
return; /* don't need to look further */
}
}
++*unseen; /* not found in any range, message is unseen */
++*recent; /* and recent */
}

43
src/c-client/newsrc.h Normal file
View File

@@ -0,0 +1,43 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Newsrc manipulation routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 12 September 1994
* Last Edited: 30 August 2006
*/
/* Function prototypes */
long newsrc_error (char *fmt,char *text,long errflg);
long newsrc_write_error (char *name,FILE *f1,FILE *f2);
FILE *newsrc_create (MAILSTREAM *stream,int notify);
long newsrc_newstate (FILE *f,char *group,char state,char *nl);
long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl);
void newsrc_lsub (MAILSTREAM *stream,char *pattern);
long newsrc_update (MAILSTREAM *stream,char *group,char state);
long newsrc_read (char *group,MAILSTREAM *stream);
long newsrc_write (char *group,MAILSTREAM *stream);
char *newsrc_state (MAILSTREAM *stream,char *group);
void newsrc_check_uid (unsigned char *state,unsigned long uid,
unsigned long *recent,unsigned long *unseen);

34
src/c-client/nl.h Normal file
View File

@@ -0,0 +1,34 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Newline routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 30 August 2006
*/
/* Function prototypes */
unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
unsigned char *src,unsigned long srcl);
unsigned long strcrlflen (STRING *s);

2224
src/c-client/nntp.c Normal file

File diff suppressed because it is too large Load Diff

56
src/c-client/nntp.h Normal file
View File

@@ -0,0 +1,56 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Network News Transfer Protocol (NNTP) routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 10 February 1992
* Last Edited: 30 August 2006
*/
/* Constants (should be in nntp.c) */
#define NNTPTCPPORT (long) 119 /* assigned TCP contact port */
/* NNTP open options
* For compatibility with the past, NOP_DEBUG must always be 1.
*/
#define NOP_DEBUG (long) 0x1 /* debug protocol negotiations */
#define NOP_READONLY (long) 0x2 /* read-only open */
#define NOP_TRYSSL (long) 0x4 /* try SSL first */
/* reserved for application use */
#define NOP_RESERVED (unsigned long) 0xff000000
/* Compatibility support names */
#define nntp_open(hostlist,options) \
nntp_open_full (NIL,hostlist,"nntp",NIL,options)
/* Function prototypes */
SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service,
unsigned long port,long options);
SENDSTREAM *nntp_close (SENDSTREAM *stream);
long nntp_mail (SENDSTREAM *stream,ENVELOPE *msg,BODY *body);

1091
src/c-client/pop3.c Normal file

File diff suppressed because it is too large Load Diff

2369
src/c-client/rfc822.c Normal file

File diff suppressed because it is too large Load Diff

127
src/c-client/rfc822.h Normal file
View File

@@ -0,0 +1,127 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: RFC 2822 and MIME routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 27 July 1988
* Last Edited: 30 August 2006
*
* This original version of this file is
* Copyright 1988 Stanford University
* and was developed in the Symbolic Systems Resources Group of the Knowledge
* Systems Laboratory at Stanford University in 1987-88, and was funded by the
* Biomedical Research Technology Program of the NationalInstitutes of Health
* under grant number RR-00785.
*/
#define MAXGROUPDEPTH 50 /* RFC [2]822 doesn't allow any group nesting */
#define MAXMIMEDEPTH 50 /* more than any sane MIMEgram */
/* Output buffering for RFC [2]822 */
typedef long (*soutr_t) (void *stream,char *string);
typedef long (*rfc822out_t) (char *tmp,ENVELOPE *env,BODY *body,soutr_t f,
void *s,long ok8bit);
typedef struct rfc822buffer {
soutr_t f; /* I/O flush routine */
void *s; /* stream for I/O routine */
char *beg; /* start of buffer */
char *cur; /* current buffer pointer */
char *end; /* end of buffer */
} RFC822BUFFER;
typedef long (*rfc822outfull_t) (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
long ok8bit);
/* Function prototypes */
char *rfc822_default_subtype (unsigned short type);
void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
STRING *bs,char *host,unsigned long depth,
unsigned long flags);
void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth,
unsigned long flags);
void rfc822_parse_content_header (BODY *body,char *name,char *s);
void rfc822_parse_parameter (PARAMETER **par,char *text);
void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host);
ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string,
char *defaulthost,unsigned long depth);
ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string,
char *defaulthost,unsigned long depth);
ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost);
long rfc822_phraseonly (char *end);
ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost);
ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost);
char *rfc822_parse_domain (char *string,char **end);
char *rfc822_parse_phrase (char *string);
char *rfc822_parse_word (char *string,const char *delimiters);
char *rfc822_cpy (char *src);
char *rfc822_quote (char *src);
ADDRESS *rfc822_cpy_adr (ADDRESS *adr);
void rfc822_skipws (char **s);
char *rfc822_skip_comment (char **s,long trim);
long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8);
long rfc822_output_flush (RFC822BUFFER *buf);
long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
const char *specials,long flags);
long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent,
char *text);
long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent,
ADDRESS *adr,const char *specials);
long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty,
const char *specials);
long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr);
long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials);
long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param);
long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl);
long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body);
void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body);
void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body);
long rfc822_output_text (RFC822BUFFER *buf,BODY *body);
void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len);
unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len);
unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl,
unsigned long *len);
unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl,
unsigned long *len);
/* Legacy routines for compatibility with the past */
void rfc822_header (char *header,ENVELOPE *env,BODY *body);
void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text);
void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr);
char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base);
void rfc822_address (char *dest,ADDRESS *adr);
void rfc822_cat (char *dest,char *src,const char *specials);
void rfc822_write_body_header (char **header,BODY *body);
long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
long ok8bit);
long rfc822_output_body (BODY *body,soutr_t f,void *s);
#define rfc822_write_address(dest,adr) \
rfc822_write_address_full (dest,adr,NIL)
#define rfc822_parse_msg(en,bdy,s,i,bs,host,flags) \
rfc822_parse_msg_full (en,bdy,s,i,bs,host,0,flags)

129
src/c-client/smanager.c Normal file
View File

@@ -0,0 +1,129 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Subscription Manager
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 3 December 1992
* Last Edited: 6 December 2006
*/
#include <stdio.h>
#include <ctype.h>
#include "c-client.h"
/* Subscribe to mailbox
* Accepts: mailbox name
* Returns: T on success, NIL on failure
*/
long sm_subscribe (char *mailbox)
{
FILE *f;
char *s,db[MAILTMPLEN],tmp[MAILTMPLEN];
/* canonicalize INBOX */
if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX";
SUBSCRIPTIONFILE (db); /* open subscription database */
if (f = fopen (db,"r")) { /* make sure not already there */
while (fgets (tmp,MAILTMPLEN,f)) {
if (s = strchr (tmp,'\n')) *s = '\0';
if (!strcmp (tmp,mailbox)) {/* already subscribed? */
sprintf (tmp,"Already subscribed to mailbox %.80s",mailbox);
MM_LOG (tmp,ERROR);
fclose (f);
return NIL;
}
}
fclose (f);
}
if (!(f = fopen (db,"a"))) { /* append new entry */
MM_LOG ("Can't append to subscription database",ERROR);
return NIL;
}
fprintf (f,"%s\n",mailbox);
return (fclose (f) == EOF) ? NIL : T;
}
/* Unsubscribe from mailbox
* Accepts: mailbox name
* Returns: T on success, NIL on failure
*/
long sm_unsubscribe (char *mailbox)
{
FILE *f,*tf;
char *s,tmp[MAILTMPLEN],old[MAILTMPLEN],newname[MAILTMPLEN];
int found = NIL;
/* canonicalize INBOX */
if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX";
SUBSCRIPTIONFILE (old); /* make file names */
SUBSCRIPTIONTEMP (newname);
if (!(f = fopen (old,"r"))) /* open subscription database */
MM_LOG ("No subscriptions",ERROR);
else if (!(tf = fopen (newname,"w"))) {
MM_LOG ("Can't create subscription temporary file",ERROR);
fclose (f);
}
else {
while (fgets (tmp,MAILTMPLEN,f)) {
if (s = strchr (tmp,'\n')) *s = '\0';
if (strcmp (tmp,mailbox)) fprintf (tf,"%s\n",tmp);
else found = T; /* found the name */
}
fclose (f);
if (fclose (tf) == EOF)
MM_LOG ("Can't write subscription temporary file",ERROR);
else if (!found) {
sprintf (tmp,"Not subscribed to mailbox %.80s",mailbox);
MM_LOG (tmp,ERROR); /* error if at end */
}
else if (!unlink (old) && !rename (newname,old)) return LONGT;
else MM_LOG ("Can't update subscription database",ERROR);
}
return NIL;
}
/* Read subscription database
* Accepts: pointer to subscription database handle (handle NIL if first time)
* Returns: character string for subscription database or NIL if done
*/
static char sbname[MAILTMPLEN];
char *sm_read (void **sdb)
{
FILE *f = (FILE *) *sdb;
char *s;
if (!f) { /* first time through? */
SUBSCRIPTIONFILE (sbname); /* open subscription database */
/* make sure not already there */
if (f = fopen (sbname,"r")) *sdb = (void *) f;
else return NIL;
}
if (fgets (sbname,MAILTMPLEN,f)) {
if (s = strchr (sbname,'\n')) *s = '\0';
return sbname;
}
fclose (f); /* all done */
*sdb = NIL; /* zap sdb */
return NIL;
}

793
src/c-client/smtp.c Normal file
View File

@@ -0,0 +1,793 @@
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Simple Mail Transfer Protocol (SMTP) routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 27 July 1988
* Last Edited: 28 January 2008
*
* This original version of this file is
* Copyright 1988 Stanford University
* and was developed in the Symbolic Systems Resources Group of the Knowledge
* Systems Laboratory at Stanford University in 1987-88, and was funded by the
* Biomedical Research Technology Program of the National Institutes of Health
* under grant number RR-00785.
*/
#include <ctype.h>
#include <stdio.h>
#include "c-client.h"
/* Constants */
#define SMTPSSLPORT (long) 465 /* former assigned SSL TCP contact port */
#define SMTPGREET (long) 220 /* SMTP successful greeting */
#define SMTPAUTHED (long) 235 /* SMTP successful authentication */
#define SMTPOK (long) 250 /* SMTP OK code */
#define SMTPAUTHREADY (long) 334/* SMTP ready for authentication */
#define SMTPREADY (long) 354 /* SMTP ready for data */
#define SMTPSOFTFATAL (long) 421/* SMTP soft fatal code */
#define SMTPWANTAUTH (long) 505 /* SMTP authentication needed */
#define SMTPWANTAUTH2 (long) 530/* SMTP authentication needed */
#define SMTPUNAVAIL (long) 550 /* SMTP mailbox unavailable */
#define SMTPHARDERROR (long) 554/* SMTP miscellaneous hard failure */
/* Convenient access to protocol-specific data */
#define ESMTP stream->protocol.esmtp
/* Function prototypes */
void *smtp_challenge (void *s,unsigned long *len);
long smtp_response (void *s,char *response,unsigned long size);
long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp);
long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error);
long smtp_send (SENDSTREAM *stream,char *command,char *args);
long smtp_reply (SENDSTREAM *stream);
long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb);
long smtp_fake (SENDSTREAM *stream,char *text);
static long smtp_seterror (SENDSTREAM *stream,long code,char *text);
long smtp_soutr (void *stream,char *s);
/* Mailer parameters */
static unsigned long smtp_maxlogintrials = MAXLOGINTRIALS;
static long smtp_port = 0; /* default port override */
static long smtp_sslport = 0;
#ifndef RFC2821
#define RFC2821 /* RFC 2821 compliance */
#endif
/* SMTP limits, current as of RFC 2821 */
#define SMTPMAXLOCALPART 64
#define SMTPMAXDOMAIN 255
#define SMTPMAXPATH 256
/* I have seen local parts of more than 64 octets, in spite of the SMTP
* limits. So, we'll have a more generous limit that's still guaranteed
* not to pop the buffer, and let the server worry about it. As of this
* writing, it comes out to 240. Anyone with a mailbox name larger than
* that is in serious need of a life or at least a new ISP! 23 June 1998
*/
#define MAXLOCALPART ((MAILTMPLEN - (SMTPMAXDOMAIN + SMTPMAXPATH + 32)) / 2)
/* Mail Transfer Protocol manipulate driver parameters
* Accepts: function code
* function-dependent value
* Returns: function-dependent return value
*/
void *smtp_parameters (long function,void *value)
{
switch ((int) function) {
case SET_MAXLOGINTRIALS:
smtp_maxlogintrials = (unsigned long) value;
break;
case GET_MAXLOGINTRIALS:
value = (void *) smtp_maxlogintrials;
break;
case SET_SMTPPORT:
smtp_port = (long) value;
break;
case GET_SMTPPORT:
value = (void *) smtp_port;
break;
case SET_SSLSMTPPORT:
smtp_sslport = (long) value;
break;
case GET_SSLSMTPPORT:
value = (void *) smtp_sslport;
break;
default:
value = NIL; /* error case */
break;
}
return value;
}
/* Mail Transfer Protocol open connection
* Accepts: network driver
* service host list
* port number
* service name
* SMTP open options
* Returns: SEND stream on success, NIL on failure
*/
SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,
unsigned long port,long options)
{
SENDSTREAM *stream = NIL;
long reply;
char *s,tmp[MAILTMPLEN];
NETSTREAM *netstream;
NETMBX mb;
if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR);
/* maximum domain name is 64 characters */
else do if (strlen (*hostlist) < SMTPMAXDOMAIN) {
sprintf (tmp,"{%.1000s}",*hostlist);
if (!mail_valid_net_parse_work (tmp,&mb,service ? service : "smtp") ||
mb.anoflag || mb.readonlyflag) {
sprintf (tmp,"Invalid host specifier: %.80s",*hostlist);
mm_log (tmp,ERROR);
}
else { /* light tryssl flag if requested */
mb.trysslflag = (options & SOP_TRYSSL) ? T : NIL;
/* explicit port overrides all */
if (mb.port) port = mb.port;
/* else /submit overrides port argument */
else if (!compare_cstring (mb.service,"submit")) {
port = SUBMITTCPPORT; /* override port, use IANA name */
strcpy (mb.service,"submission");
}
/* else port argument overrides SMTP port */
else if (!port) port = smtp_port ? smtp_port : SMTPTCPPORT;
if (netstream = /* try to open ordinary connection */
net_open (&mb,dv,port,
(NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
"*smtps",smtp_sslport ? smtp_sslport : SMTPSSLPORT)) {
stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0,
sizeof (SENDSTREAM));
stream->netstream = netstream;
stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
net_host (netstream) : mb.host);
stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL;
if (options & SOP_SECURE) mb.secflag = T;
/* get name of local host to use */
s = compare_cstring ("localhost",mb.host) ?
net_localhost (netstream) : "localhost";
do reply = smtp_reply (stream);
while ((reply < 100) || (stream->reply[3] == '-'));
if (reply != SMTPGREET){/* get SMTP greeting */
sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply);
mm_log (tmp,ERROR);
stream = smtp_close (stream);
}
/* try EHLO first, then HELO */
else if (((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) &&
((reply = smtp_send (stream,"HELO",s)) != SMTPOK)) {
sprintf (tmp,"SMTP hello failure: %.80s",stream->reply);
mm_log (tmp,ERROR);
stream = smtp_close (stream);
}
else {
NETDRIVER *ssld =(NETDRIVER *)mail_parameters(NIL,GET_SSLDRIVER,NIL);
sslstart_t stls = (sslstart_t) mail_parameters(NIL,GET_SSLSTART,NIL);
ESMTP.ok = T; /* ESMTP server, start TLS if present */
if (!dv && stls && ESMTP.service.starttls &&
!mb.sslflag && !mb.notlsflag &&
(smtp_send (stream,"STARTTLS",NIL) == SMTPGREET)) {
mb.tlsflag = T; /* TLS OK, get into TLS at this end */
stream->netstream->dtb = ssld;
/* TLS started, negotiate it */
if (!(stream->netstream->stream = (*stls)
(stream->netstream->stream,mb.host,
(mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
(mb.novalidate ? NET_NOVALIDATECERT:NIL)))){
/* TLS negotiation failed after STARTTLS */
sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",
mb.host);
mm_log (tmp,ERROR);
/* close without doing QUIT */
if (stream->netstream) net_close (stream->netstream);
stream->netstream = NIL;
stream = smtp_close (stream);
}
/* TLS OK, re-negotiate EHLO */
else if ((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) {
sprintf (tmp,"SMTP EHLO failure after STARTTLS: %.80s",
stream->reply);
mm_log (tmp,ERROR);
stream = smtp_close (stream);
}
else ESMTP.ok = T; /* TLS OK and EHLO successful */
}
else if (mb.tlsflag) {/* user specified /tls but can't do it */
sprintf (tmp,"TLS unavailable with this server: %.80s",mb.host);
mm_log (tmp,ERROR);
stream = smtp_close (stream);
}
/* remote name for authentication */
if (stream && ((mb.secflag || mb.user[0]))) {
if (ESMTP.auth) { /* use authenticator? */
if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
/* remote name for authentication */
strncpy (mb.host,
(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
net_remotehost (netstream) : net_host (netstream),
NETMAXHOST-1);
mb.host[NETMAXHOST-1] = '\0';
}
if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close (stream);
}
else { /* no available authenticators? */
sprintf (tmp,"%sSMTP authentication not available: %.80s",
mb.secflag ? "Secure " : "",mb.host);
mm_log (tmp,ERROR);
stream = smtp_close (stream);
}
}
}
}
}
} while (!stream && *++hostlist);
if (stream) { /* set stream options if have a stream */
if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY |
SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) {
ESMTP.dsn.want = T;
if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T;
if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T;
if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T;
if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T;
}
if (options & SOP_8BITMIME) ESMTP.eightbit.want = T;
}
return stream;
}
/* SMTP authenticate
* Accepts: stream to login
* parsed network mailbox structure
* scratch buffer
* place to return user name
* Returns: T on success, NIL on failure
*/
long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp)
{
unsigned long trial,auths;
char *lsterr = NIL;
char usr[MAILTMPLEN];
AUTHENTICATOR *at;
long ret = NIL;
for (auths = ESMTP.auth, stream->saslcancel = NIL;
!ret && stream->netstream && auths &&
(at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) {
if (lsterr) { /* previous authenticator failed? */
sprintf (tmp,"Retrying using %s authentication after %.80s",
at->name,lsterr);
mm_log (tmp,NIL);
fs_give ((void **) &lsterr);
}
trial = 0; /* initial trial count */
tmp[0] = '\0'; /* empty buffer */
if (stream->netstream) do {
if (lsterr) {
sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
mm_log (tmp,WARN);
fs_give ((void **) &lsterr);
}
stream->saslcancel = NIL;
if (smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) {
/* hide client authentication responses */
if (!(at->flags & AU_SECURE)) stream->sensitive = T;
if ((*at->client) (smtp_challenge,smtp_response,"smtp",mb,stream,
&trial,usr)) {
if (stream->replycode == SMTPAUTHED) {
ESMTP.auth = NIL; /* disable authenticators */
ret = LONGT;
}
/* if main program requested cancellation */
else if (!trial) mm_log ("SMTP Authentication cancelled",ERROR);
}
stream->sensitive = NIL;/* unhide */
}
/* remember response if error and no cancel */
if (!ret && trial) lsterr = cpystr (stream->reply);
} while (!ret && stream->netstream && trial &&
(trial < smtp_maxlogintrials));
}
if (lsterr) { /* previous authenticator failed? */
if (!stream->saslcancel) { /* don't do this if a cancel */
sprintf (tmp,"Can not authenticate to SMTP server: %.80s",lsterr);
mm_log (tmp,ERROR);
}
fs_give ((void **) &lsterr);
}
return ret; /* authentication failed */
}
/* Get challenge to authenticator in binary
* Accepts: stream
* pointer to returned size
* Returns: challenge or NIL if not challenge
*/
void *smtp_challenge (void *s,unsigned long *len)
{
char tmp[MAILTMPLEN];
void *ret = NIL;
SENDSTREAM *stream = (SENDSTREAM *) s;
if ((stream->replycode == SMTPAUTHREADY) &&
!(ret = rfc822_base64 ((unsigned char *) stream->reply + 4,
strlen (stream->reply + 4),len))) {
sprintf (tmp,"SMTP SERVER BUG (invalid challenge): %.80s",stream->reply+4);
mm_log (tmp,ERROR);
}
return ret;
}
/* Send authenticator response in BASE64
* Accepts: MAIL stream
* string to send
* length of string
* Returns: T, always
*/
long smtp_response (void *s,char *response,unsigned long size)
{
SENDSTREAM *stream = (SENDSTREAM *) s;
unsigned long i,j;
char *t,*u;
if (response) { /* make CRLFless BASE64 string */
if (size) {
for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
j < i; j++) if (t[j] > ' ') *u++ = t[j];
*u = '\0'; /* tie off string */
i = smtp_send (stream,t,NIL);
fs_give ((void **) &t);
}
else i = smtp_send (stream,"",NIL);
}
else { /* abort requested */
i = smtp_send (stream,"*",NIL);
stream->saslcancel = T; /* mark protocol-requested SASL cancel */
}
return LONGT;
}
/* Mail Transfer Protocol close connection
* Accepts: SEND stream
* Returns: NIL always
*/
SENDSTREAM *smtp_close (SENDSTREAM *stream)
{
if (stream) { /* send "QUIT" */
if (stream->netstream) { /* do close actions if have netstream */
smtp_send (stream,"QUIT",NIL);
if (stream->netstream) /* could have been closed during "QUIT" */
net_close (stream->netstream);
}
/* clean up */
if (stream->host) fs_give ((void **) &stream->host);
if (stream->reply) fs_give ((void **) &stream->reply);
if (ESMTP.dsn.envid) fs_give ((void **) &ESMTP.dsn.envid);
if (ESMTP.atrn.domains) fs_give ((void **) &ESMTP.atrn.domains);
fs_give ((void **) &stream);/* flush the stream */
}
return NIL;
}
/* Mail Transfer Protocol deliver mail
* Accepts: SEND stream
* delivery option (MAIL, SEND, SAML, SOML)
* message envelope
* message body
* Returns: T on success, NIL on failure
*/
long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *env,BODY *body)
{
RFC822BUFFER buf;
char tmp[SENDBUFLEN+1];
long error = NIL;
long retry = NIL;
buf.f = smtp_soutr; /* initialize buffer */
buf.s = stream->netstream;
buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
tmp[SENDBUFLEN] = '\0'; /* must have additional null guard byte */
if (!(env->to || env->cc || env->bcc)) {
/* no recipients in request */
smtp_seterror (stream,SMTPHARDERROR,"No recipients specified");
return NIL;
}
do { /* make sure stream is in good shape */
smtp_send (stream,"RSET",NIL);
if (retry) { /* need to retry with authentication? */
NETMBX mb;
/* yes, build remote name for authentication */
sprintf (tmp,"{%.200s/smtp%s}<none>",
(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
net_remotehost (stream->netstream) :
net_host (stream->netstream)) :
stream->host,
(stream->netstream->dtb ==
(NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL)) ?
"/ssl" : "");
mail_valid_net_parse (tmp,&mb);
if (!smtp_auth (stream,&mb,tmp)) return NIL;
retry = NIL; /* no retry at this point */
}
strcpy (tmp,"FROM:<"); /* compose "MAIL FROM:<return-path>" */
#ifdef RFC2821
if (env->return_path && env->return_path->host &&
!((strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) ||
(strlen (env->return_path->host) > SMTPMAXDOMAIN))) {
rfc822_cat (tmp,env->return_path->mailbox,NIL);
sprintf (tmp + strlen (tmp),"@%s",env->return_path->host);
}
#else /* old code with A-D-L support */
if (env->return_path && env->return_path->host &&
!((env->return_path->adl &&
(strlen (env->return_path->adl) > SMTPMAXPATH)) ||
(strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) ||
(strlen (env->return_path->host) > SMTPMAXDOMAIN)))
rfc822_address (tmp,env->return_path);
#endif
strcat (tmp,">");
if (ESMTP.ok) {
if (ESMTP.eightbit.ok && ESMTP.eightbit.want)
strcat (tmp," BODY=8BITMIME");
if (ESMTP.dsn.ok && ESMTP.dsn.want) {
strcat (tmp,ESMTP.dsn.full ? " RET=FULL" : " RET=HDRS");
if (ESMTP.dsn.envid)
sprintf (tmp + strlen (tmp)," ENVID=%.100s",ESMTP.dsn.envid);
}
}
/* send "MAIL FROM" command */
switch (smtp_send (stream,type,tmp)) {
case SMTPUNAVAIL: /* mailbox unavailable? */
case SMTPWANTAUTH: /* wants authentication? */
case SMTPWANTAUTH2:
if (ESMTP.auth) retry = T;/* yes, retry with authentication */
case SMTPOK: /* looks good */
break;
default: /* other failure */
return NIL;
}
/* negotiate the recipients */
if (!retry && env->to) retry = smtp_rcpt (stream,env->to,&error);
if (!retry && env->cc) retry = smtp_rcpt (stream,env->cc,&error);
if (!retry && env->bcc) retry = smtp_rcpt (stream,env->bcc,&error);
if (!retry && error) { /* any recipients failed? */
smtp_send (stream,"RSET",NIL);
smtp_seterror (stream,SMTPHARDERROR,"One or more recipients failed");
return NIL;
}
} while (retry);
/* negotiate data command */
if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
/* send message data */
if (!rfc822_output_full (&buf,env,body,
ESMTP.eightbit.ok && ESMTP.eightbit.want)) {
smtp_fake (stream,"SMTP connection broken (message data)");
return NIL; /* can't do much else here */
}
/* send trailing dot */
return (smtp_send (stream,".",NIL) == SMTPOK) ? LONGT : NIL;
}
/* Simple Mail Transfer Protocol send VERBose
* Accepts: SMTP stream
* Returns: T if successful, else NIL
*
* Descriptive text formerly in [al]pine sources:
* At worst, this command may cause the SMTP connection to get nuked. Modern
* sendmail's recognize it, and possibly other SMTP implementations (the "ON"
* arg is for PMDF). What's more, if it works, the reply code and accompanying
* text may vary from server to server.
*/
long smtp_verbose (SENDSTREAM *stream)
{
/* accept any 2xx reply code */
return ((smtp_send (stream,"VERB","ON") / (long) 100) == 2) ? LONGT : NIL;
}
/* Internal routines */
/* Simple Mail Transfer Protocol send recipient
* Accepts: SMTP stream
* address list
* pointer to error flag
* Returns: T if should retry, else NIL
*/
long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error)
{
char *s,tmp[2*MAILTMPLEN],orcpt[MAILTMPLEN];
while (adr) { /* for each address on the list */
/* clear any former error */
if (adr->error) fs_give ((void **) &adr->error);
if (adr->host) { /* ignore group syntax */
/* enforce SMTP limits to protect the buffer */
if (strlen (adr->mailbox) > MAXLOCALPART) {
adr->error = cpystr ("501 Recipient name too long");
*error = T;
}
else if ((strlen (adr->host) > SMTPMAXDOMAIN)) {
adr->error = cpystr ("501 Recipient domain too long");
*error = T;
}
#ifndef RFC2821 /* old code with A-D-L support */
else if (adr->adl && (strlen (adr->adl) > SMTPMAXPATH)) {
adr->error = cpystr ("501 Path too long");
*error = T;
}
#endif
else {
strcpy (tmp,"TO:<"); /* compose "RCPT TO:<return-path>" */
#ifdef RFC2821
rfc822_cat (tmp,adr->mailbox,NIL);
sprintf (tmp + strlen (tmp),"@%s>",adr->host);
#else /* old code with A-D-L support */
rfc822_address (tmp,adr);
strcat (tmp,">");
#endif
/* want notifications */
if (ESMTP.ok && ESMTP.dsn.ok && ESMTP.dsn.want) {
/* yes, start with prefix */
strcat (tmp," NOTIFY=");
s = tmp + strlen (tmp);
if (ESMTP.dsn.notify.failure) strcat (s,"FAILURE,");
if (ESMTP.dsn.notify.delay) strcat (s,"DELAY,");
if (ESMTP.dsn.notify.success) strcat (s,"SUCCESS,");
/* tie off last comma */
if (*s) s[strlen (s) - 1] = '\0';
else strcat (tmp,"NEVER");
if (adr->orcpt.addr) {
sprintf (orcpt,"%.498s;%.498s",
adr->orcpt.type ? adr->orcpt.type : "rfc822",
adr->orcpt.addr);
sprintf (tmp + strlen (tmp)," ORCPT=%.500s",orcpt);
}
}
switch (smtp_send (stream,"RCPT",tmp)) {
case SMTPOK: /* looks good */
break;
case SMTPUNAVAIL: /* mailbox unavailable? */
case SMTPWANTAUTH: /* wants authentication? */
case SMTPWANTAUTH2:
if (ESMTP.auth) return T;
default: /* other failure */
*error = T; /* note that an error occurred */
adr->error = cpystr (stream->reply);
}
}
}
adr = adr->next; /* do any subsequent recipients */
}
return NIL; /* no retry called for */
}
/* Simple Mail Transfer Protocol send command
* Accepts: SEND stream
* text
* Returns: reply code
*/
long smtp_send (SENDSTREAM *stream,char *command,char *args)
{
long ret;
char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0)
+ 3);
/* build the complete command */
if (args) sprintf (s,"%s %s",command,args);
else strcpy (s,command);
if (stream->debug) mail_dlog (s,stream->sensitive);
strcat (s,"\015\012");
/* send the command */
if (stream->netstream && net_soutr (stream->netstream,s)) {
do stream->replycode = smtp_reply (stream);
while ((stream->replycode < 100) || (stream->reply[3] == '-'));
ret = stream->replycode;
}
else ret = smtp_fake (stream,"SMTP connection broken (command)");
fs_give ((void **) &s);
return ret;
}
/* Simple Mail Transfer Protocol get reply
* Accepts: SMTP stream
* Returns: reply code
*/
long smtp_reply (SENDSTREAM *stream)
{
smtpverbose_t pv = (smtpverbose_t) mail_parameters (NIL,GET_SMTPVERBOSE,NIL);
long reply;
/* flush old reply */
if (stream->reply) fs_give ((void **) &stream->reply);
/* get reply */
if (stream->netstream && (stream->reply = net_getline (stream->netstream))) {
if (stream->debug) mm_dlog (stream->reply);
/* return response code */
reply = atol (stream->reply);
if (pv && (reply < 100)) (*pv) (stream->reply);
}
else reply = smtp_fake (stream,"SMTP connection broken (reply)");
return reply;
}
/* Simple Mail Transfer Protocol send EHLO
* Accepts: SMTP stream
* host name to use in EHLO
* NETMBX structure
* Returns: reply code
*/
long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb)
{
unsigned long i,j;
long flags = (mb->secflag ? AU_SECURE : NIL) |
(mb->authuser[0] ? AU_AUTHUSER : NIL);
char *s,*t,*r,tmp[MAILTMPLEN];
/* clear ESMTP data */
memset (&ESMTP,0,sizeof (ESMTP));
if (mb->loser) return 500; /* never do EHLO if a loser */
sprintf (tmp,"EHLO %s",host); /* build the complete command */
if (stream->debug) mm_dlog (tmp);
strcat (tmp,"\015\012");
/* send the command */
if (!net_soutr (stream->netstream,tmp))
return smtp_fake (stream,"SMTP connection broken (EHLO)");
/* got an OK reply? */
do if ((i = smtp_reply (stream)) == SMTPOK) {
/* hack for AUTH= */
if (stream->reply[4] && stream->reply[5] && stream->reply[6] &&
stream->reply[7] && (stream->reply[8] == '=')) stream->reply[8] = ' ';
/* get option code */
if (!(s = strtok_r (stream->reply+4," ",&r)));
/* have option, does it have a value */
else if ((t = strtok_r (NIL," ",&r)) && *t) {
/* EHLO options which take arguments */
if (!compare_cstring (s,"SIZE")) {
if (isdigit (*t)) ESMTP.size.limit = strtoul (t,&t,10);
ESMTP.size.ok = T;
}
else if (!compare_cstring (s,"DELIVERBY")) {
if (isdigit (*t)) ESMTP.deliverby.minby = strtoul (t,&t,10);
ESMTP.deliverby.ok = T;
}
else if (!compare_cstring (s,"ATRN")) {
ESMTP.atrn.domains = cpystr (t);
ESMTP.atrn.ok = T;
}
else if (!compare_cstring (s,"AUTH"))
do if ((j = mail_lookup_auth_name (t,flags)) &&
(--j < MAXAUTHENTICATORS)) ESMTP.auth |= (1 << j);
while ((t = strtok_r (NIL," ",&r)) && *t);
}
/* EHLO options which do not take arguments */
else if (!compare_cstring (s,"SIZE")) ESMTP.size.ok = T;
else if (!compare_cstring (s,"8BITMIME")) ESMTP.eightbit.ok = T;
else if (!compare_cstring (s,"DSN")) ESMTP.dsn.ok = T;
else if (!compare_cstring (s,"ATRN")) ESMTP.atrn.ok = T;
else if (!compare_cstring (s,"SEND")) ESMTP.service.send = T;
else if (!compare_cstring (s,"SOML")) ESMTP.service.soml = T;
else if (!compare_cstring (s,"SAML")) ESMTP.service.saml = T;
else if (!compare_cstring (s,"EXPN")) ESMTP.service.expn = T;
else if (!compare_cstring (s,"HELP")) ESMTP.service.help = T;
else if (!compare_cstring (s,"TURN")) ESMTP.service.turn = T;
else if (!compare_cstring (s,"ETRN")) ESMTP.service.etrn = T;
else if (!compare_cstring (s,"STARTTLS")) ESMTP.service.starttls = T;
else if (!compare_cstring (s,"RELAY")) ESMTP.service.relay = T;
else if (!compare_cstring (s,"PIPELINING")) ESMTP.service.pipe = T;
else if (!compare_cstring (s,"ENHANCEDSTATUSCODES"))
ESMTP.service.ensc = T;
else if (!compare_cstring (s,"BINARYMIME")) ESMTP.service.bmime = T;
else if (!compare_cstring (s,"CHUNKING")) ESMTP.service.chunk = T;
}
while ((i < 100) || (stream->reply[3] == '-'));
/* disable LOGIN if PLAIN also advertised */
if ((j = mail_lookup_auth_name ("PLAIN",NIL)) && (--j < MAXAUTHENTICATORS) &&
(ESMTP.auth & (1 << j)) &&
(j = mail_lookup_auth_name ("LOGIN",NIL)) && (--j < MAXAUTHENTICATORS))
ESMTP.auth &= ~(1 << j);
return i; /* return the response code */
}
/* Simple Mail Transfer Protocol set fake error and abort
* Accepts: SMTP stream
* error text
* Returns: SMTPSOFTFATAL, always
*/
long smtp_fake (SENDSTREAM *stream,char *text)
{
if (stream->netstream) { /* close net connection if still open */
net_close (stream->netstream);
stream->netstream = NIL;
}
/* set last error */
return smtp_seterror (stream,SMTPSOFTFATAL,text);
}
/* Simple Mail Transfer Protocol set error
* Accepts: SMTP stream
* SMTP error code
* error text
* Returns: error code
*/
static long smtp_seterror (SENDSTREAM *stream,long code,char *text)
{
/* flush any old reply */
if (stream->reply ) fs_give ((void **) &stream->reply);
/* set up pseudo-reply string */
stream->reply = (char *) fs_get (20+strlen (text));
sprintf (stream->reply,"%ld %s",code,text);
return code; /* return error code */
}
/* Simple Mail Transfer Protocol filter mail
* Accepts: stream
* string
* Returns: T on success, NIL on failure
*/
long smtp_soutr (void *stream,char *s)
{
char c,*t;
/* "." on first line */
if (s[0] == '.') net_sout (stream,".",1);
/* find lines beginning with a "." */
while (t = strstr (s,"\015\012.")) {
c = *(t += 3); /* remember next character after "." */
*t = '\0'; /* tie off string */
/* output prefix */
if (!net_sout (stream,s,t-s)) return NIL;
*t = c; /* restore delimiter */
s = t - 1; /* push pointer up to the "." */
}
/* output remainder of text */
return *s ? net_soutr (stream,s) : T;
}

76
src/c-client/smtp.h Normal file
View File

@@ -0,0 +1,76 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Simple Mail Transfer Protocol (SMTP) routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 27 July 1988
* Last Edited: 15 August 2007
*
* This original version of this file is
* Copyright 1988 Stanford University
* and was developed in the Symbolic Systems Resources Group of the Knowledge
* Systems Laboratory at Stanford University in 1987-88, and was funded by the
* Biomedical Research Technology Program of the NationalInstitutes of Health
* under grant number RR-00785.
*/
/* Constants (should be in smtp.c) */
#define SMTPTCPPORT (long) 25 /* assigned TCP contact port */
#define SUBMITTCPPORT (long) 587/* assigned TCP contact port */
/* SMTP open options
* For compatibility with the past, SOP_DEBUG must always be 1.
*/
#define SOP_DEBUG (long) 1 /* debug protocol negotiations */
#define SOP_DSN (long) 2 /* DSN requested */
/* DSN notification, none set mean NEVER */
#define SOP_DSN_NOTIFY_FAILURE (long) 4
#define SOP_DSN_NOTIFY_DELAY (long) 8
#define SOP_DSN_NOTIFY_SUCCESS (long) 16
/* DSN return full msg vs. header */
#define SOP_DSN_RETURN_FULL (long) 32
#define SOP_8BITMIME (long) 64 /* 8-bit MIME requested */
#define SOP_SECURE (long) 256 /* don't do non-secure authentication */
#define SOP_TRYSSL (long) 512 /* try SSL first */
#define SOP_TRYALT SOP_TRYSSL /* old name */
/* reserved for application use */
#define SOP_RESERVED (unsigned long) 0xff000000
/* Compatibility support names */
#define smtp_open(hostlist,options) \
smtp_open_full (NIL,hostlist,"smtp",NIL,options)
/* Function prototypes */
void *smtp_parameters (long function,void *value);
SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,
unsigned long port,long options);
SENDSTREAM *smtp_close (SENDSTREAM *stream);
long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *msg,BODY *body);
long smtp_verbose (SENDSTREAM *stream);

70
src/c-client/sslio.h Normal file
View File

@@ -0,0 +1,70 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: SSL routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 7 February 2001
* Last Edited: 30 August 2006
*/
/* SSL driver */
struct ssl_driver { /* must parallel NETDRIVER in mail.h */
SSLSTREAM *(*open) (char *host,char *service,unsigned long port);
SSLSTREAM *(*aopen) (NETMBX *mb,char *service,char *usrbuf);
char *(*getline) (SSLSTREAM *stream);
long (*getbuffer) (SSLSTREAM *stream,unsigned long size,char *buffer);
long (*soutr) (SSLSTREAM *stream,char *string);
long (*sout) (SSLSTREAM *stream,char *string,unsigned long size);
void (*close) (SSLSTREAM *stream);
char *(*host) (SSLSTREAM *stream);
char *(*remotehost) (SSLSTREAM *stream);
unsigned long (*port) (SSLSTREAM *stream);
char *(*localhost) (SSLSTREAM *stream);
};
/* SSL stdio stream */
typedef struct ssl_stdiostream {
SSLSTREAM *sslstream; /* SSL stream */
int octr; /* output counter */
char *optr; /* output pointer */
char obuf[SSLBUFLEN]; /* output buffer */
} SSLSTDIOSTREAM;
/* Function prototypes */
SSLSTREAM *ssl_open (char *host,char *service,unsigned long port);
SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf);
char *ssl_getline (SSLSTREAM *stream);
long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer);
long ssl_getdata (SSLSTREAM *stream);
long ssl_soutr (SSLSTREAM *stream,char *string);
long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size);
void ssl_close (SSLSTREAM *stream);
char *ssl_host (SSLSTREAM *stream);
char *ssl_remotehost (SSLSTREAM *stream);
unsigned long ssl_port (SSLSTREAM *stream);
char *ssl_localhost (SSLSTREAM *stream);
long ssl_server_input_wait (long seconds);

59
src/c-client/tcp.h Normal file
View File

@@ -0,0 +1,59 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: TCP/IP routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 31 January 2007
*/
/* Dummy definition overridden by TCP routines */
#ifndef TCPSTREAM
#define TCPSTREAM void
#endif
/* Function prototypes */
void *tcp_parameters (long function,void *value);
TCPSTREAM *tcp_open (char *host,char *service,unsigned long port);
TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf);
char *tcp_getline (TCPSTREAM *stream);
long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer);
long tcp_getdata (TCPSTREAM *stream);
long tcp_soutr (TCPSTREAM *stream,char *string);
long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size);
void tcp_close (TCPSTREAM *stream);
char *tcp_host (TCPSTREAM *stream);
char *tcp_remotehost (TCPSTREAM *stream);
unsigned long tcp_port (TCPSTREAM *stream);
char *tcp_localhost (TCPSTREAM *stream);
char *tcp_clientaddr (void);
char *tcp_clienthost (void);
long tcp_clientport (void);
char *tcp_serveraddr (void);
char *tcp_serverhost (void);
long tcp_serverport (void);
char *tcp_canonical (char *name);
long tcp_isclienthost (char *host);

2554
src/c-client/utf8.c Normal file

File diff suppressed because it is too large Load Diff

584
src/c-client/utf8.h Normal file
View File

@@ -0,0 +1,584 @@
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: UTF-8 routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 11 June 1997
* Last Edited: 17 January 2008
*/
/* UTF-8 size and conversion routines from UCS-2 values (thus in the BMP).
* Don't use these if UTF-16 data (surrogate pairs) are an issue.
* For UCS-4 values, use the utf8_size() and utf8_put() functions.
*/
#define UTF8_SIZE_BMP(c) ((c & 0xff80) ? ((c & 0xf800) ? 3 : 2) : 1)
#define UTF8_PUT_BMP(b,c) { \
if (c & 0xff80) { /* non-ASCII? */ \
if (c & 0xf800) { /* three byte code */ \
*b++ = 0xe0 | (c >> 12); \
*b++ = 0x80 | ((c >> 6) & 0x3f); \
} \
else *b++ = 0xc0 | ((c >> 6) & 0x3f); \
*b++ = 0x80 | (c & 0x3f); \
} \
else *b++ = c; \
}
/* utf8_text() flag values */
#define U8T_CASECANON 2 /* canonicalize case */
#define U8T_DECOMPOSE 4 /* decompose */
/* full canonicalization */
#define U8T_CANONICAL (U8T_CASECANON | U8T_DECOMPOSE)
/* utf8_get() return values */
/* 0x0000 - 0xffff BMP plane */
#define U8GM_NONBMP 0xffff0000 /* mask for non-BMP values */
/* 0x10000 - 0x10ffff extended planes */
/* 0x110000 - 0x7ffffff non-Unicode */
#define U8G_ERROR 0x80000000 /* error flag */
#define U8G_BADCONT U8G_ERROR+1 /* continuation when not in progress */
#define U8G_INCMPLT U8G_ERROR+2 /* incomplete UTF-8 character */
#define U8G_NOTUTF8 U8G_ERROR+3 /* not a valid UTF-8 octet */
#define U8G_ENDSTRG U8G_ERROR+4 /* end of string */
#define U8G_ENDSTRI U8G_ERROR+5 /* end of string w/ incomplete UTF-8 char */
#define U8G_SURROGA U8G_ERROR+6 /* surrogate codepoint */
#define U8G_NOTUNIC U8G_ERROR+7 /* non-Unicode codepoint */
/* ucs4_width() return values */
#define U4W_ERROR 0x80000000 /* error flags */
#define U4W_NOTUNCD U4W_ERROR+1 /* not a Unicode char */
#define U4W_PRIVATE U4W_ERROR+2 /* private-space plane */
#define U4W_SSPCHAR U4W_ERROR+3 /* Supplementary Special-purpose Plane */
#define U4W_UNASSGN U4W_ERROR+4 /* unassigned space plane */
#define U4W_CONTROL U4W_ERROR+5 /* C0/C1 control */
#define U4W_CTLSRGT U4W_CONTROL /* in case legacy code references this */
/* ISO-2022 engine states */
#define I2S_CHAR 0 /* character */
#define I2S_ESC 1 /* previous character was ESC */
#define I2S_MUL 2 /* previous character was multi-byte code */
#define I2S_INT 3 /* previous character was intermediate */
/* ISO-2022 Gn selections */
#define I2C_G0 0 /* G0 */
#define I2C_G1 1 /* G1 */
#define I2C_G2 2 /* G2 */
#define I2C_G3 3 /* G3 */
#define I2C_SG2 (2 << 2) /* single shift G2 */
#define I2C_SG3 (3 << 2) /* single shift G2 */
/* ISO-2022 octet definitions */
#define I2C_ESC 0x1b /* ESCape */
/* Intermediate character */
#define I2C_STRUCTURE 0x20 /* announce code structure */
#define I2C_C0 0x21 /* C0 */
#define I2C_C1 0x22 /* C1 */
#define I2C_CONTROL 0x23 /* single control function */
#define I2C_MULTI 0x24 /* multi-byte character set */
#define I2C_OTHER 0x25 /* other coding system */
#define I2C_REVISED 0x26 /* revised registration */
#define I2C_G0_94 0x28 /* G0 94-character set */
#define I2C_G1_94 0x29 /* G1 94-character set */
#define I2C_G2_94 0x2A /* G2 94-character set */
#define I2C_G3_94 0x2B /* G3 94-character set */
#define I2C_G0_96 0x2C /* (not in ISO-2022) G0 96-character set */
#define I2C_G1_96 0x2D /* G1 96-character set */
#define I2C_G2_96 0x2E /* G2 96-character set */
#define I2C_G3_96 0x2F /* G3 96-character set */
/* Locking shifts */
#define I2C_SI 0x0f /* lock shift to G0 (Shift In) */
#define I2C_SO 0x0e /* lock shift to G1 (Shift Out) */
/* prefixed by ESC */
#define I2C_LS2 0x6e /* lock shift to G2 */
#define I2C_LS3 0x6f /* lock shift to G3 */
#define I2C_LS1R 0x7e /* lock shift GR to G1 */
#define I2C_LS2R 0x7d /* lock shift GR to G2 */
#define I2C_LS3R 0x7c /* lock shift GR to G3 */
/* Single shifts */
#define I2C_SS2_ALT 0x8e /* single shift to G2 (SS2) */
#define I2C_SS3_ALT 0x8f /* single shift to G3 (SS3) */
#define I2C_SS2_ALT_7 0x19 /* single shift to G2 (SS2) */
#define I2C_SS3_ALT_7 0x1d /* single shift to G3 (SS3) */
/* prefixed by ESC */
#define I2C_SS2 0x4e /* single shift to G2 (SS2) */
#define I2C_SS3 0x4f /* single shift to G3 (SS3) */
/* 94 character sets */
/* 4/0 ISO 646 IRV */
#define I2CS_94_BRITISH 0x41 /* 4/1 ISO 646 British */
#define I2CS_94_ASCII 0x42 /* 4/2 ISO 646 USA (ASCII) */
/* 4/3 NATS Finland/Sweden (primary) */
/* 4/4 NATS Finland/Sweden (secondary) */
/* 4/5 NATS Denmark/Norway (primary) */
/* 4/6 NATS Denmark/Norway (secondary) */
/* 4/7 ISO 646 Swedish SEN 850200 */
/* 4/8 ISO 646 Swedish names */
#define I2CS_94_JIS_BUGROM 0x48 /* 4/8 some buggy software does this */
#define I2CS_94_JIS_KANA 0x49 /* 4/9 JIS X 0201-1976 right half */
#define I2CS_94_JIS_ROMAN 0x4a /* 4/a JIS X 0201-1976 left half */
/* 4/b ISO 646 German */
/* 4/c ISO 646 Portuguese (Olivetti) */
/* 4/d ISO 6438 African */
/* 4/e ISO 5427 Cyrillic (Honeywell-Bull) */
/* 4/f DIN 31624 extended bibliography */
/* 5/0 ISO 5426-1980 Bibliography */
/* 5/1 ISO 5427-1981 Cyrillic*/
/* 5/2 ISO 646 French (withdrawn) */
/* 5/3 ISO 5428-1980 Greek bibliography */
/* 5/4 GB 1988-80 Chinese */
/* 5/5 Latin-Greek (Honeywell-Bull) */
/* 5/6 UK Viewdata/Teletext */
/* 5/7 INIS (IRV subset) */
/* 5/8 ISO 5428 Greek Bibliography */
/* 5/9 ISO 646 Italian (Olivetti) */
/* 5/a ISO 646 Spanish (Olivetti) */
/* 5/b Greek (Olivetti) */
/* 5/c Latin-Greek (Olivetti) */
/* 5/d INIS non-standard extension */
/* 5/e INIS Cyrillic extension */
/* 5/f Arabic CODAR-U IERA */
/* 6/0 ISO 646 Norwegian */
/* 6/1 Norwegian version 2 (withdrawn) */
/* 6/2 Videotex supplementary */
/* 6/3 Videotex supplementary #2 */
/* 6/4 Videotex supplementary #3 */
/* 6/5 APL */
/* 6/6 ISO 646 French */
/* 6/7 ISO 646 Portuguese (IBM) */
/* 6/8 ISO 646 Spanish (IBM) */
/* 6/9 ISO 646 Hungarian */
/* 6/a Greek ELOT (withdrawn) */
/* 6/b ISO 9036 Arabic 7-bit */
/* 6/c ISO 646 IRV supplementary set */
/* 6/d JIS C6229-1984 OCR-A */
/* 6/e JIS C6229-1984 OCR-B */
/* 6/f JIS C6229-1984 OCR-B additional */
/* 7/0 JIS C6229-1984 hand-printed */
/* 7/1 JIS C6229-1984 additional hand-printd */
/* 7/2 JIS C6229-1984 katakana hand-printed */
/* 7/3 E13B Japanese graphic */
/* 7/4 Supplementary Videotex (withdrawn) */
/* 7/5 Teletex primary CCITT T.61 */
/* 7/6 Teletex secondary CCITT T.61 */
/* 7/7 CSA Z 243.4-1985 Alternate primary #1 */
/* 7/8 CSA Z 243.4-1985 Alternate primary #2 */
/* 7/9 Mosaic CCITT T.101 */
/* 7/a Serbocroatian/Slovenian Latin */
/* 7/b Serbocroatian Cyrillic */
/* 7/c Supplementary CCITT T.101 */
/* 7/d Macedonian Cyrillic */
/* 94 character sets - second intermediate byte */
/* 4/0 Greek primary CCITT */
/* 4/1 Cuba */
/* 4/2 ISO/IEC 646 invariant */
/* 4/3 Irish Gaelic 7-bit */
/* 4/4 Turkmen */
/* 94x94 character sets */
#define I2CS_94x94_JIS_OLD 0x40 /* 4/0 JIS X 0208-1978 */
#define I2CS_94x94_GB 0x41 /* 4/1 GB 2312 */
#define I2CS_94x94_JIS_NEW 0x42 /* 4/2 JIS X 0208-1983 */
#define I2CS_94x94_KSC 0x43 /* 4/3 KSC 5601 */
#define I2CS_94x94_JIS_EXT 0x44 /* 4/4 JIS X 0212-1990 */
/* 4/5 CCITT Chinese */
/* 4/6 Blisssymbol Graphic */
#define I2CS_94x94_CNS1 0x47 /* 4/7 CNS 11643 plane 1 */
#define I2CS_94x94_CNS2 0x48 /* 4/8 CNS 11643 plane 2 */
#define I2CS_94x94_CNS3 0x49 /* 4/9 CNS 11643 plane 3 */
#define I2CS_94x94_CNS4 0x4a /* 4/a CNS 11643 plane 4 */
#define I2CS_94x94_CNS5 0x4b /* 4/b CNS 11643 plane 5 */
#define I2CS_94x94_CNS6 0x4c /* 4/c CNS 11643 plane 6 */
#define I2CS_94x94_CNS7 0x4d /* 4/d CNS 11643 plane 7 */
/* 4/e DPRK (North Korea) KGCII */
/* 4/f JGCII plane 1 */
/* 5/0 JGCII plane 2 */
/* 96 character sets */
#define I2CS_96_ISO8859_1 0x41 /* 4/1 Latin-1 (Western Europe) */
#define I2CS_96_ISO8859_2 0x42 /* 4/2 Latin-2 (Czech, Slovak) */
#define I2CS_96_ISO8859_3 0x43 /* 4/3 Latin-3 (Dutch, Turkish) */
#define I2CS_96_ISO8859_4 0x44 /* 4/4 Latin-4 (Scandinavian) */
/* 4/5 CSA Z 243.4-1985 */
#define I2CS_96_ISO8859_7 0x46 /* 4/6 Greek */
#define I2CS_96_ISO8859_6 0x47 /* 4/7 Arabic */
#define I2CS_96_ISO8859_8 0x48 /* 4/8 Hebrew */
/* 4/9 Czechoslovak CSN 369103 */
/* 4/a Supplementary Latin and non-alpha */
/* 4/b Technical */
#define I2CS_96_ISO8859_5 0x4c /* 4/c Cyrillic */
#define I2CS_96_ISO8859_9 0x4d /* 4/d Latin-5 (Finnish, Portuguese) */
/* 4/e ISO 6937-2 residual */
/* 4/f Basic Cyrillic */
/* 5/0 Supplementary Latin 1, 2 and 5 */
/* 5/1 Basic Box */
/* 5/2 Supplementary ISO/IEC 6937 : 1992 */
/* 5/3 CCITT Hebrew supplementary */
#define I2CS_96_TIS620 0x54 /* 5/4 TIS 620 */
/* 5/5 Arabic/French/German */
#define I2CS_96_ISO8859_10 0x56 /* 5/6 Latin-6 (Northern Europe) */
/* 5/7 ??? */
/* 5/8 Sami (Lappish) supplementary */
#define I2CS_96_ISO8859_13 0x59 /* 5/9 Latin-7 (Baltic) */
#define I2CS_96_VSCII 0x5a /* 5/a Vietnamese */
/* 5/b Technical #1 IEC 1289 */
#define I2CS_96_ISO8859_14 0x5c /* 5/c Latin-8 (Celtic) */
/* 5/d Sami supplementary Latin */
/* 5/e Latin/Hebrew */
/* 5/f Celtic supplementary Latin */
/* 6/0 Uralic supplementary Cyrillic */
/* 6/1 Volgaic supplementary Cyrillic */
#define I2CS_96_ISO8859_15 0x62 /* 6/2 Latin-9 (Euro) */
/* 6/3 Latin-1 with Euro */
/* 6/4 Latin-4 with Euro */
/* 6/5 Latin-7 with Euro */
#define I2CS_96_ISO8859_16 0x66 /* 6/6 Latin-10 (Balkan) */
/* 6/7 Ogham */
/* 6/8 Sami supplementary Latin #2 */
/* 7/d Supplementary Mosaic for CCITT 101 */
/* 96x96 character sets */
/* Types of character sets */
#define I2CS_94 0x000 /* 94 character set */
#define I2CS_96 0x100 /* 96 character set */
#define I2CS_MUL 0x200 /* multi-byte */
#define I2CS_94x94 (I2CS_MUL | I2CS_94)
#define I2CS_96x96 (I2CS_MUL | I2CS_96)
/* Character set identifiers stored in Gn */
#define I2CS_BRITISH (I2CS_94 | I2CS_94_BRITISH)
#define I2CS_ASCII (I2CS_94 | I2CS_94_ASCII)
#define I2CS_JIS_BUGROM (I2CS_94 | I2CS_94_JIS_BUGROM)
#define I2CS_JIS_KANA (I2CS_94 | I2CS_94_JIS_KANA)
#define I2CS_JIS_ROMAN (I2CS_94 | I2CS_94_JIS_ROMAN)
#define I2CS_JIS_OLD (I2CS_94x94 | I2CS_94x94_JIS_OLD)
#define I2CS_GB (I2CS_94x94 | I2CS_94x94_GB)
#define I2CS_JIS_NEW (I2CS_94x94 | I2CS_94x94_JIS_NEW)
#define I2CS_KSC (I2CS_94x94 | I2CS_94x94_KSC)
#define I2CS_JIS_EXT (I2CS_94x94 | I2CS_94x94_JIS_EXT)
#define I2CS_CNS1 (I2CS_94x94 | I2CS_94x94_CNS1)
#define I2CS_CNS2 (I2CS_94x94 | I2CS_94x94_CNS2)
#define I2CS_CNS3 (I2CS_94x94 | I2CS_94x94_CNS3)
#define I2CS_CNS4 (I2CS_94x94 | I2CS_94x94_CNS4)
#define I2CS_CNS5 (I2CS_94x94 | I2CS_94x94_CNS5)
#define I2CS_CNS6 (I2CS_94x94 | I2CS_94x94_CNS6)
#define I2CS_CNS7 (I2CS_94x94 | I2CS_94x94_CNS7)
#define I2CS_ISO8859_1 (I2CS_96 | I2CS_96_ISO8859_1)
#define I2CS_ISO8859_2 (I2CS_96 | I2CS_96_ISO8859_2)
#define I2CS_ISO8859_3 (I2CS_96 | I2CS_96_ISO8859_3)
#define I2CS_ISO8859_4 (I2CS_96 | I2CS_96_ISO8859_4)
#define I2CS_ISO8859_7 (I2CS_96 | I2CS_96_ISO8859_7)
#define I2CS_ISO8859_6 (I2CS_96 | I2CS_96_ISO8859_6)
#define I2CS_ISO8859_8 (I2CS_96 | I2CS_96_ISO8859_8)
#define I2CS_ISO8859_5 (I2CS_96 | I2CS_96_ISO8859_5)
#define I2CS_ISO8859_9 (I2CS_96 | I2CS_96_ISO8859_9)
#define I2CS_TIS620 (I2CS_96 | I2CS_96_TIS620)
#define I2CS_ISO8859_10 (I2CS_96 | I2CS_96_ISO8859_10)
#define I2CS_ISO8859_13 (I2CS_96 | I2CS_96_ISO8859_13)
#define I2CS_VSCII (I2CS_96 | I2CS_96_VSCII)
#define I2CS_ISO8859_14 (I2CS_96 | I2CS_96_ISO8859_14)
#define I2CS_ISO8859_15 (I2CS_96 | I2CS_96_ISO8859_15)
#define I2CS_ISO8859_16 (I2CS_96 | I2CS_96_ISO8859_16)
/* Miscellaneous ISO 2022 definitions */
#define EUC_CS2 0x8e /* single shift CS2 */
#define EUC_CS3 0x8f /* single shift CS3 */
#define BITS7 0x7f /* 7-bit value mask */
#define BIT8 0x80 /* 8th bit mask */
/* The following saves us from having to have yet more charset tables */
/* Unicode codepoints */
#define UCS2_C0CONTROL 0x00 /* first C0 control */
#define UCS2_C0CONTROLEND 0x1F /* last C0 control */
#define UCS2_C1CONTROL 0x80 /* first C1 control */
#define UCS2_C1CONTROLEND 0x9F /* last C1 control */
/* ISO 646 substituted Unicode codepoints */
#define UCS2_POUNDSTERLING 0x00a3
#define UCS2_YEN 0x00a5
#define UCS2_OVERLINE 0x203e
#define UCS2_EURO 0x20ac
#define UCS2_KATAKANA 0xff61 /* first katakana codepoint */
#define UCS2_BOM 0xfeff /* byte order mark */
#define UCS2_BOGON 0xfffd /* replacement character */
/* next two codepoints are not Unicode chars */
#define UCS2_BOMCHECK 0xfffe /* used to check byte order with UCS2_BOM */
#define UCS2_NOTCHAR 0xffff /* not a character */
#define UCS4_BMPBASE 0x0000 /* Basic Multilingual Plane */
#define UCS4_SMPBASE 0x10000 /* Supplementary Multilinugual Plane */
#define UCS4_SIPBASE 0x20000 /* Supplementary Ideographic Plane */
/* EastAsianWidth says plane 3 is wide */
#define UCS4_UNABASE 0x40000 /* unassigned space */
#define UCS4_SSPBASE 0xe0000 /* Supplementary Special-purpose Plane */
#define UCS4_PVTBASE 0xf0000 /* private-space (two planes) */
#define UCS4_MAXUNICODE 0x10ffff/* highest Unicode codepoint */
#define UTF16_BASE 0x10000 /* base of codepoints needing surrogates */
#define UTF16_SHIFT 10 /* surrogate shift */
#define UTF16_MASK 0x3ff /* surrogate mask */
#define UTF16_SURR 0xd800 /* UTF-16 surrogate area */
#define UTF16_SURRH 0xd800 /* UTF-16 first high surrogate */
#define UTF16_SURRHEND 0xdbff /* UTF-16 last high surrogate */
#define UTF16_SURRL 0xdc00 /* UTF-16 first low surrogate */
#define UTF16_SURRLEND 0xdfff /* UTF-16 last low surrogate */
#define UTF16_MAXSURR 0xdfff /* end of UTF-16 surrogates */
/* UBOGON is used to represent a codepoint in a character set which does not
* map to Unicode. It is also used for mapping failures, e.g. incomplete
* shift sequences. This name has the same text width as 0x????, for
* convenience in the mapping tables.
*
* NOCHAR is used to represent a codepoint in Unicode which does not map to
* the target character set in a reverse mapping table. This name has the
* same text width as 0x???? in case we ever add static reverse mapping tables.
*/
#define UBOGON UCS2_BOGON
#define NOCHAR UCS2_NOTCHAR
/* Codepoints in non-Unicode character sets */
/* Codepoints in ISO 646 character sets */
/* British ASCII codepoints */
#define BRITISH_POUNDSTERLING 0x23
/* JIS Roman codepoints */
#define JISROMAN_YEN 0x5c
#define JISROMAN_OVERLINE 0x7e
/* Hankaku katakana codepoints & parameters
*
* In earlier versions, MAX_KANA_7 and MAX_KANA_8 were the maximum codepoint
* values. Although this made sense, it was confusing with the "max ku" and
* "max ten" values used in the double-byte tables; there are 1-origin, but
* the calculated values used for "ku" and "ten" are 0-origin (derived by
* substracting the "base"). What this all meant is that for double byte
* characters the limit test is of the form (value < max_ku), but for single
* byte characters (which used the same cell to hold the max ku) the limit
* test was (value <= max_ku).
*
* By making MAX_KANA_[78] be maximum+1, the same (value < max_ku) limit test
* is used throughout. - 6/15/2006
*/
#define MIN_KANA_7 0x21
#define MAX_KANA_7 0x60 /* maximum value + 1 */
#define KANA_7 (UCS2_KATAKANA - MIN_KANA_7)
#define MIN_KANA_8 (MIN_KANA_7 | BIT8)
#define MAX_KANA_8 (MAX_KANA_7 | BIT8)
#define KANA_8 (UCS2_KATAKANA - MIN_KANA_8)
/* Charset scripts */
/* The term "script" is used here in a very loose sense, enough to make
* purists cringe. Basically, the idea is to give the main program some
* idea of how it should treat the characters of text in a charset with
* respect to font, drawing routines, etc.
*
* In some cases, "script" is associated with a charset; in other cases,
* it's more closely tied to a language.
*/
#define SC_UNICODE 0x1 /* Unicode */
#define SC_LATIN_1 0x10 /* Western Europe */
#define SC_LATIN_2 0x20 /* Eastern Europe */
#define SC_LATIN_3 0x40 /* Southern Europe */
#define SC_LATIN_4 0x80 /* Northern Europe */
#define SC_LATIN_5 0x100 /* Turkish */
#define SC_LATIN_6 0x200 /* Nordic */
#define SC_LATIN_7 0x400 /* Baltic */
#define SC_LATIN_8 0x800 /* Celtic */
#define SC_LATIN_9 0x1000 /* Euro */
#define SC_LATIN_0 SC_LATIN_9 /* colloquial name for Latin-9 */
#define SC_ARABIC 0x2000
#define SC_CYRILLIC 0x4000
#define SC_GREEK 0x8000
#define SC_HEBREW 0x10000
#define SC_THAI 0x20000
#define SC_UKRANIAN 0x40000
#define SC_LATIN_10 0x80000 /* Balkan */
#define SC_VIETNAMESE 0x100000
#define SC_CHINESE_SIMPLIFIED 0x1000000
#define SC_CHINESE_TRADITIONAL 0x2000000
#define SC_JAPANESE 0x4000000
#define SC_KOREAN 0x8000000
/* Script table */
typedef struct utf8_scent {
char *name; /* script name */
char *description; /* script description */
unsigned long script; /* script bitmask */
} SCRIPT;
/* Character set table support */
typedef struct utf8_csent {
char *name; /* charset name */
unsigned short type; /* type of charset */
unsigned short flags; /* charset flags */
void *tab; /* additional data */
unsigned long script; /* script(s) implemented by this charset */
char *preferred; /* preferred charset over this one */
} CHARSET;
struct utf8_eucparam {
unsigned int base_ku : 8; /* base row */
unsigned int base_ten : 8; /* base column */
unsigned int max_ku : 8; /* maximum row */
unsigned int max_ten : 8; /* maximum column */
void *tab; /* conversion table */
};
/* Charset types */
#define CT_UNKNOWN 0 /* unknown 8-bit */
#define CT_ASCII 1 /* 7-bit ASCII no table */
#define CT_UCS2 2 /* 2 byte 16-bit Unicode no table */
#define CT_UCS4 3 /* 4 byte 32-bit Unicode no table */
#define CT_1BYTE0 10 /* 1 byte ISO 8859-1 no table */
#define CT_1BYTE 11 /* 1 byte ASCII + table 0x80-0xff */
#define CT_1BYTE8 12 /* 1 byte table 0x00 - 0xff */
#define CT_EUC 100 /* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
#define CT_DBYTE 101 /* 2 byte ASCII + utf8_eucparam */
#define CT_DBYTE2 102 /* 2 byte ASCII + utf8_eucparam plane1/2 */
#define CT_UTF16 1000 /* variable UTF-16 encoded Unicode no table */
#define CT_UTF8 1001 /* variable UTF-8 encoded Unicode no table */
#define CT_UTF7 1002 /* variable UTF-7 encoded Unicode no table */
#define CT_2022 10000 /* variable ISO-2022 encoded no table */
#define CT_SJIS 10001 /* 2 byte Shift-JIS encoded JIS no table */
/* Character set flags */
#define CF_PRIMARY 0x1 /* primary name for this charset */
#define CF_DISPLAY 0x2 /* charset used in displays */
#define CF_POSTING 0x4 /* charset used in email posting */
#define CF_UNSUPRT 0x8 /* charset unsupported (can't convert to it) */
#define CF_NOEMAIL 0x10 /* charset not used in email */
/* UTF-7 engine states */
#define U7_ASCII 0 /* ASCII character */
#define U7_PLUS 1 /* plus seen */
#define U7_UNICODE 2 /* Unicode characters */
#define U7_MINUS 3 /* absorbed minus seen */
/* Function prototypes */
typedef unsigned long (*ucs4cn_t) (unsigned long c);
typedef unsigned long (*ucs4de_t) (unsigned long c,void **more);
SCRIPT *utf8_script (char *script);
const CHARSET *utf8_charset (char *charset);
char *utf8_badcharset (char *charset);
long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags);
long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret,
ucs4cn_t cv,ucs4de_t de);
long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,
unsigned long errch);
long utf8_cstocstext (SIZEDTEXT *text,char *sc,SIZEDTEXT *ret,char *dc,
unsigned long errch);
unsigned short *utf8_rmap (char *charset);
unsigned short *utf8_rmap_cs (const CHARSET *cs);
unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap);
long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret,
unsigned long errch,long iso2022jp);
unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap,
unsigned long errch,long iso2022jp);
long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
SIZEDTEXT *ret,unsigned long errch);
long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
unsigned long errch);
long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len,
unsigned short *rmap,unsigned long errch);
unsigned long utf8_get (unsigned char **s,unsigned long *i);
unsigned long utf8_get_raw (unsigned char **s,unsigned long *i);
unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i);
unsigned long *utf8_csvalidmap (char *charsets[]);
const CHARSET *utf8_infercharset (SIZEDTEXT *src);
long utf8_validate (unsigned char *s,unsigned long i);
void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
ucs4de_t de);
void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
ucs4de_t de);
void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
ucs4de_t de);
void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
ucs4de_t de);
void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
ucs4de_t de);
void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
unsigned long utf8_size (unsigned long c);
unsigned char *utf8_put (unsigned char *s,unsigned long c);
unsigned long ucs4_titlecase (unsigned long c);
long ucs4_width (unsigned long c);
long utf8_strwidth (unsigned char *s);
long utf8_textwidth (SIZEDTEXT *utf8);
unsigned long ucs4_decompose (unsigned long c,void **more);
unsigned long ucs4_decompose_recursive (unsigned long c,void **more);

449
src/c-client/utf8aux.c Normal file
View File

@@ -0,0 +1,449 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: UTF-8 auxillary routines (c-client and MIME2 support)
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 11 June 1997
* Last Edited: 12 October 2007
*/
#include <stdio.h>
#include <ctype.h>
#include "c-client.h"
/* Convert charset labelled stringlist to UTF-8 in place
* Accepts: string list
* charset
*/
static void utf8_stringlist (STRINGLIST *st,char *charset)
{
SIZEDTEXT txt;
/* convert entire stringstruct */
if (st) do if (utf8_text (&st->text,charset,&txt,U8T_CANONICAL)) {
fs_give ((void **) &st->text.data);
st->text.data = txt.data; /* transfer this text */
st->text.size = txt.size;
} while (st = st->next);
}
/* Convert charset labelled searchpgm to UTF-8 in place
* Accepts: search program
* charset
*/
void utf8_searchpgm (SEARCHPGM *pgm,char *charset)
{
SIZEDTEXT txt;
SEARCHHEADER *hl;
SEARCHOR *ol;
SEARCHPGMLIST *pl;
if (pgm) { /* must have a search program */
utf8_stringlist (pgm->bcc,charset);
utf8_stringlist (pgm->cc,charset);
utf8_stringlist (pgm->from,charset);
utf8_stringlist (pgm->to,charset);
utf8_stringlist (pgm->subject,charset);
for (hl = pgm->header; hl; hl = hl->next) {
if (utf8_text (&hl->line,charset,&txt,U8T_CANONICAL)) {
fs_give ((void **) &hl->line.data);
hl->line.data = txt.data;
hl->line.size = txt.size;
}
if (utf8_text (&hl->text,charset,&txt,U8T_CANONICAL)) {
fs_give ((void **) &hl->text.data);
hl->text.data = txt.data;
hl->text.size = txt.size;
}
}
utf8_stringlist (pgm->body,charset);
utf8_stringlist (pgm->text,charset);
for (ol = pgm->or; ol; ol = ol->next) {
utf8_searchpgm (ol->first,charset);
utf8_searchpgm (ol->second,charset);
}
for (pl = pgm->not; pl; pl = pl->next) utf8_searchpgm (pl->pgm,charset);
utf8_stringlist (pgm->return_path,charset);
utf8_stringlist (pgm->sender,charset);
utf8_stringlist (pgm->reply_to,charset);
utf8_stringlist (pgm->in_reply_to,charset);
utf8_stringlist (pgm->message_id,charset);
utf8_stringlist (pgm->newsgroups,charset);
utf8_stringlist (pgm->followup_to,charset);
utf8_stringlist (pgm->references,charset);
}
}
/* Convert MIME-2 sized text to UTF-8
* Accepts: source sized text
* charset
* flags (same as utf8_text())
* Returns: T if successful, NIL if failure
*/
#define MINENCWORD 9
#define MAXENCWORD 75
/* This resizing algorithm is stupid, but hopefully it should never be triggered
* except for a pathological header. The main concern is that we don't get a
* buffer overflow.
*/
#define DSIZE 65536 /* real headers should never be this big */
#define FUZZ 10 /* paranoia fuzz */
long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags)
{
unsigned char *s,*se,*e,*ee,*t,*te;
char *cs,*ce,*ls;
SIZEDTEXT txt,rtxt;
unsigned long i;
size_t dsize = min (DSIZE,((src->size / 4) + 1) * 9);
/* always create buffer if canonicalizing */
dst->data = (flags & U8T_CANONICAL) ?
(unsigned char *) fs_get ((size_t) dsize) : NIL;
dst->size = 0; /* nothing written yet */
/* look for encoded words */
for (s = src->data, se = src->data + src->size; s < se; s++) {
if (((se - s) > MINENCWORD) && (*s == '=') && (s[1] == '?') &&
(cs = (char *) mime2_token (s+2,se,(unsigned char **) &ce)) &&
(e = mime2_token ((unsigned char *) ce+1,se,&ee)) &&
(te = mime2_text (t = e+2,se)) && (ee == e + 1) &&
((te - s) < MAXENCWORD)) {
if (mime2_decode (e,t,te,&txt)) {
*ce = '\0'; /* temporarily tie off charset */
if (ls = strchr (cs,'*')) *ls = '\0';
/* convert to UTF-8 as best we can */
if (!utf8_text (&txt,cs,&rtxt,flags)) utf8_text (&txt,NIL,&rtxt,flags);
if (dst->data) { /* make sure existing buffer fits */
while (dsize <= (dst->size + rtxt.size + FUZZ)) {
dsize += DSIZE; /* kick it up */
fs_resize ((void **) &dst->data,dsize);
}
}
else { /* make a new buffer */
while (dsize <= (dst->size + rtxt.size)) dsize += DSIZE;
memcpy (dst->data = (unsigned char *) fs_get (dsize),src->data,
dst->size = s - src->data);
}
for (i = 0; i < rtxt.size; i++) dst->data[dst->size++] = rtxt.data[i];
/* all done with converted text */
if (rtxt.data != txt.data) fs_give ((void **) &rtxt.data);
if (ls) *ls = '*'; /* restore language tag delimiter */
*ce = '?'; /* restore charset delimiter */
/* all done with decoded text */
fs_give ((void **) &txt.data);
s = te+1; /* continue scan after encoded word */
/* skip leading whitespace */
for (t = s + 1; (t < se) && ((*t == ' ') || (*t == '\t')); t++);
/* see if likely continuation encoded word */
if (t < (se - MINENCWORD)) switch (*t) {
case '=': /* possible encoded word? */
if (t[1] == '?') s = t - 1;
break;
case '\015': /* CR, eat a following LF */
if (t[1] == '\012') t++;
case '\012': /* possible end of logical line */
if ((t[1] == ' ') || (t[1] == '\t')) {
do t++;
while ((t < (se - MINENCWORD)) && ((t[1] == ' ')||(t[1] == '\t')));
if ((t < (se - MINENCWORD)) && (t[1] == '=') && (t[2] == '?'))
s = t; /* definitely looks like continuation */
}
}
}
else { /* restore original text */
if (dst->data) fs_give ((void **) &dst->data);
dst->data = src->data;
dst->size = src->size;
return NIL; /* syntax error: MIME-2 decoding failure */
}
}
else do if (dst->data) { /* stash ASCII characters until LWSP */
if (dsize < (dst->size + FUZZ)) {
dsize += DSIZE; /* kick it up */
fs_resize ((void **) &dst->data,dsize);
}
/* kludge: assumes ASCII doesn't decompose and titlecases to one byte */
dst->data[dst->size++] = (flags & U8T_CASECANON) ?
(unsigned char) ucs4_titlecase (*s) : *s;
}
while ((*s != ' ') && (*s != '\t') && (*s != '\015') && (*s != '\012') &&
(++s < se));
}
if (dst->data) dst->data[dst->size] = '\0';
else { /* nothing converted, return identity */
dst->data = src->data;
dst->size = src->size;
}
return T; /* success */
}
/* Decode MIME-2 text
* Accepts: Encoding
* text
* text end
* destination sized text
* Returns: T if successful, else NIL
*/
long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te,
SIZEDTEXT *txt)
{
unsigned char *q;
txt->data = NIL; /* initially no returned data */
switch (*e) { /* dispatch based upon encoding */
case 'Q': case 'q': /* sort-of QUOTED-PRINTABLE */
txt->data = (unsigned char *) fs_get ((size_t) (te - t) + 1);
for (q = t,txt->size = 0; q < te; q++) switch (*q) {
case '=': /* quoted character */
/* both must be hex */
if (!isxdigit (q[1]) || !isxdigit (q[2])) {
fs_give ((void **) &txt->data);
return NIL; /* syntax error: bad quoted character */
}
/* assemble character */
txt->data[txt->size++] = hex2byte (q[1],q[2]);
q += 2; /* advance past quoted character */
break;
case '_': /* convert to space */
txt->data[txt->size++] = ' ';
break;
default: /* ordinary character */
txt->data[txt->size++] = *q;
break;
}
txt->data[txt->size] = '\0';
break;
case 'B': case 'b': /* BASE64 */
if (txt->data = (unsigned char *) rfc822_base64 (t,te - t,&txt->size))
break;
default: /* any other encoding is unknown */
return NIL; /* syntax error: unknown encoding */
}
return T;
}
/* Get MIME-2 token from encoded word
* Accepts: current text pointer
* text limit pointer
* pointer to returned end pointer
* Returns: current text pointer & end pointer if success, else NIL
*/
unsigned char *mime2_token (unsigned char *s,unsigned char *se,
unsigned char **t)
{
for (*t = s; **t != '?'; ++*t) {
if ((*t < se) && isgraph (**t)) switch (**t) {
case '(': case ')': case '<': case '>': case '@': case ',': case ';':
case ':': case '\\': case '"': case '/': case '[': case ']': case '.':
case '=':
return NIL; /* none of these are valid in tokens */
}
else return NIL; /* out of text or CTL or space */
}
return s;
}
/* Get MIME-2 text from encoded word
* Accepts: current text pointer
* text limit pointer
* pointer to returned end pointer
* Returns: end pointer if success, else NIL
*/
unsigned char *mime2_text (unsigned char *s,unsigned char *se)
{
unsigned char *t = se - 1;
/* search for closing ?, make sure valid */
while ((s < t) && (*s != '?') && isgraph (*s++));
return ((s < t) && (*s == '?') && (s[1] == '=') &&
((se == (s + 2)) || (s[2] == ' ') || (s[2] == '\t') ||
(s[2] == '\015') || (s[2] == '\012'))) ? s : NIL;
}
/* Convert UTF-16 string to Modified Base64
* Accepts: destination pointer
* source string
* source length in octets
* Returns: updated destination pointer
*/
static unsigned char *utf16_to_mbase64 (unsigned char *t,unsigned char *s,
size_t i)
{
char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
*t++ = '&'; /* write shift-in */
while (i >= 3) { /* process tuplets */
*t++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */
/* byte 2: low 2 bits (1), high 4 bits (2) */
*t++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f];
/* byte 3: low 4 bits (2), high 2 bits (3) */
*t++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f];
*t++ = v[s[2] & 0x3f]; /* byte 4: low 6 bits (3) */
s += 3;
i -= 3;
}
if (i) {
*t++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */
/* byte 2: low 2 bits (1), high 4 bits (2) */
*t++ = v[((s[0] << 4) + (--i ? (s[1] >> 4) : 0)) & 0x3f];
/* byte 3: low 4 bits (2) */
if (i) *t++ = v[(s[1] << 2) & 0x3f];
}
*t++ = '-'; /* write shift-out */
return t;
}
/* Poot a UTF-16 value to a buffer
* Accepts: buffer pointer
* value
* Returns: updated pointer
*/
static unsigned char *utf16_poot (unsigned char *s,unsigned long c)
{
*s++ = (unsigned char) (c >> 8);
*s++ = (unsigned char) (c & 0xff);
return s;
}
/* Convert UTF-8 to Modified UTF-7
* Accepts: UTF-8 string
* Returns: Modified UTF-7 string on success, NIL if invalid UTF-8
*/
#define MAXUNIUTF8 4 /* maximum length of Unicode UTF-8 sequence */
unsigned char *utf8_to_mutf7 (unsigned char *src)
{
unsigned char *u16buf,*utf16;
unsigned char *ret,*t;
unsigned long j,c;
unsigned char *s = src;
unsigned long i = 0;
int nonascii = 0;
while (*s) { /* pass one: count destination octets */
if (*s & 0x80) { /* non-ASCII character? */
j = MAXUNIUTF8; /* get single UCS-4 codepoint */
if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL;
/* tally number of UTF-16 octets */
nonascii += (c & U8GM_NONBMP) ? 4 : 2;
}
else { /* ASCII character */
if (nonascii) { /* add pending Modified BASE64 size + shifts */
i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2;
nonascii = 0; /* back to ASCII */
}
if (*s == '&') i += 2; /* two octets if the escape */
else ++i; /* otherwise just count another octet */
++s; /* advance to next source octet */
}
}
if (nonascii) /* add pending Modified BASE64 size + shifts */
i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2;
/* create return buffer */
t = ret = (unsigned char *) fs_get (i + 1);
/* and scratch buffer */
utf16 = u16buf = (unsigned char *) fs_get (i + 1);
for (s = src; *s;) { /* pass two: copy destination octets */
if (*s & 0x80) { /* non-ASCII character? */
j = MAXUNIUTF8; /* get single UCS-4 codepoint */
if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL;
if (c & U8GM_NONBMP) { /* non-BMP? */
c -= UTF16_BASE; /* yes, convert to surrogate */
utf16 = utf16_poot (utf16_poot (utf16,(c >> UTF16_SHIFT)+UTF16_SURRH),
(c & UTF16_MASK) + UTF16_SURRL);
}
else utf16 = utf16_poot (utf16,c);
}
else { /* ASCII character */
if (utf16 != u16buf) { /* add pending Modified BASE64 size + shifts */
t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf);
utf16 = u16buf; /* reset buffer */
}
*t++ = *s; /* copy the character */
if (*s == '&') *t++ = '-';/* special sequence if the escape */
++s; /* advance to next source octet */
}
}
/* add pending Modified BASE64 size + shifts */
if (utf16 != u16buf) t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf);
*t = '\0'; /* tie off destination */
if (i != (t - ret)) fatal ("utf8_to_mutf7 botch");
fs_give ((void **) &u16buf);
return ret;
}
/* Convert Modified UTF-7 to UTF-8
* Accepts: Modified UTF-7 string
* Returns: UTF-8 string on success, NIL if invalid Modified UTF-7
*/
unsigned char *utf8_from_mutf7 (unsigned char *src)
{
SIZEDTEXT utf8,utf7;
unsigned char *s;
int mbase64 = 0;
/* disallow bogus strings */
if (mail_utf7_valid (src)) return NIL;
/* initialize SIZEDTEXTs */
memset (&utf7,0,sizeof (SIZEDTEXT));
memset (&utf8,0,sizeof (SIZEDTEXT));
/* make copy of source */
for (s = cpytxt (&utf7,src,strlen (src)); *s; ++s) switch (*s) {
case '&': /* Modified UTF-7 uses & instead of + */
*s = '+';
mbase64 = T; /* note that we are in Modified BASE64 */
break;
case '+': /* temporarily swap text + to & */
if (!mbase64) *s = '&';
break;
case '-': /* shift back to ASCII */
mbase64 = NIL;
break;
case ',': /* Modified UTF-7 uses , instead of / ... */
if (mbase64) *s = '/'; /* ...in Modified BASE64 */
break;
}
/* do the conversion */
utf8_text_utf7 (&utf7,&utf8,NIL,NIL);
/* no longer need copy of source */
fs_give ((void **) &utf7.data);
/* post-process: switch & and + */
for (s = utf8.data; *s; ++s) switch (*s) {
case '&':
*s = '+';
break;
case '+':
*s = '&';
break;
}
return utf8.data;
}

44
src/c-client/utf8aux.h Normal file
View File

@@ -0,0 +1,44 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: UTF-8 auxillary routines (c-client and MIME2 support)
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 11 June 1997
* Last Edited: 9 October 2007
*/
/* Following routines are in utf8aux.c as these depend upon c-client.
* Splitting these routines out makes it possible for pico to link with utf8.o
* and a few rump routines (e.g., fs_get()) but not all the rest of c-client
* (which pico does not need).
*/
void utf8_searchpgm (SEARCHPGM *pgm,char *charset);
long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags);
unsigned char *mime2_token (unsigned char *s,unsigned char *se,
unsigned char **t);
unsigned char *mime2_text (unsigned char *s,unsigned char *se);
long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te,
SIZEDTEXT *txt);
unsigned char *utf8_to_mutf7 (unsigned char *src);
unsigned char *utf8_from_mutf7 (unsigned char *src);

2016
src/charset/big5.c Normal file

File diff suppressed because it is too large Load Diff

8590
src/charset/cns11643.c Normal file

File diff suppressed because it is too large Load Diff

2909
src/charset/decomtab.c Normal file

File diff suppressed because it is too large Load Diff

1114
src/charset/gb_12345.c Normal file

File diff suppressed because it is too large Load Diff

2795
src/charset/gb_2312.c Normal file

File diff suppressed because it is too large Load Diff

347
src/charset/ibm.c Normal file
View File

@@ -0,0 +1,347 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: IBM conversion tables
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 4 November 2002
* Last Edited: 30 August 2006
*/
/* IBM Latin US */
static const unsigned short ibm_437tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Greek */
static const unsigned short ibm_737tab[128] = {
0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,
0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
0x03c1,0x03c3,0x03c2,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03c9,0x03ac,0x03ad,0x03ae,0x03ca,0x03af,0x03cc,0x03cd,
0x03cb,0x03ce,0x0386,0x0388,0x0389,0x038a,0x038c,0x038e,
0x038f,0x00b1,0x2265,0x2264,0x03aa,0x03ab,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Baltic Rim */
static const unsigned short ibm_775tab[128] = {
0x0106,0x00fc,0x00e9,0x0101,0x00e4,0x0123,0x00e5,0x0107,
0x0142,0x0113,0x0156,0x0157,0x012b,0x0179,0x00c4,0x00c5,
0x00c9,0x00e6,0x00c6,0x014d,0x00f6,0x0122,0x00a2,0x015a,
0x015b,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x00a4,
0x0100,0x012a,0x00f3,0x017b,0x017c,0x017a,0x201d,0x00a6,
0x00a9,0x00ae,0x00ac,0x00bd,0x00bc,0x0141,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x0104,0x010c,0x0118,
0x0116,0x2563,0x2551,0x2557,0x255d,0x012e,0x0160,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0172,0x016a,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x017d,
0x0105,0x010d,0x0119,0x0117,0x012f,0x0161,0x0173,0x016b,
0x017e,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x00d3,0x00df,0x014c,0x0143,0x00f5,0x00d5,0x00b5,0x0144,
0x0136,0x0137,0x013b,0x013c,0x0146,0x0112,0x0145,0x2019,
0x00ad,0x00b1,0x201c,0x00be,0x00b6,0x00a7,0x00f7,0x201e,
0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
};
/* IBM Latin 1 */
static const unsigned short ibm_850tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192,
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0,
0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce,
0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580,
0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe,
0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4,
0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8,
0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
};
/* IBM Latin 2 */
static const unsigned short ibm_852tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x016f,0x0107,0x00e7,
0x0142,0x00eb,0x0150,0x0151,0x00ee,0x0179,0x00c4,0x0106,
0x00c9,0x0139,0x013a,0x00f4,0x00f6,0x013d,0x013e,0x015a,
0x015b,0x00d6,0x00dc,0x0164,0x0165,0x0141,0x00d7,0x010d,
0x00e1,0x00ed,0x00f3,0x00fa,0x0104,0x0105,0x017d,0x017e,
0x0118,0x0119,0x00ac,0x017a,0x010c,0x015f,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x011a,
0x015e,0x2563,0x2551,0x2557,0x255d,0x017b,0x017c,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0102,0x0103,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
0x0111,0x0110,0x010e,0x00cb,0x010f,0x0147,0x00cd,0x00ce,
0x011b,0x2518,0x250c,0x2588,0x2584,0x0162,0x016e,0x2580,
0x00d3,0x00df,0x00d4,0x0143,0x0144,0x0148,0x0160,0x0161,
0x0154,0x00da,0x0155,0x0170,0x00fd,0x00dd,0x0163,0x00b4,
0x00ad,0x02dd,0x02db,0x02c7,0x02d8,0x00a7,0x00f7,0x00b8,
0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0
};
/* IBM Cyrillic */
static const unsigned short ibm_855tab[128] = {
0x0452,0x0402,0x0453,0x0403,0x0451,0x0401,0x0454,0x0404,
0x0455,0x0405,0x0456,0x0406,0x0457,0x0407,0x0458,0x0408,
0x0459,0x0409,0x045a,0x040a,0x045b,0x040b,0x045c,0x040c,
0x045e,0x040e,0x045f,0x040f,0x044e,0x042e,0x044a,0x042a,
0x0430,0x0410,0x0431,0x0411,0x0446,0x0426,0x0434,0x0414,
0x0435,0x0415,0x0444,0x0424,0x0433,0x0413,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x0445,0x0425,0x0438,
0x0418,0x2563,0x2551,0x2557,0x255d,0x0439,0x0419,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x043a,0x041a,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
0x043b,0x041b,0x043c,0x041c,0x043d,0x041d,0x043e,0x041e,
0x043f,0x2518,0x250c,0x2588,0x2584,0x041f,0x044f,0x2580,
0x042f,0x0440,0x0420,0x0441,0x0421,0x0442,0x0422,0x0443,
0x0423,0x0436,0x0416,0x0432,0x0412,0x044c,0x042c,0x2116,
0x00ad,0x044b,0x042b,0x0437,0x0417,0x0448,0x0428,0x044d,
0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0
};
/* IBM Turkish */
static const unsigned short ibm_857tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x0131,0x00c4,0x00c5,
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
0x0130,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x015e,0x015f,
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x011e,0x011f,
0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0,
0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
0x00ba,0x00aa,0x00ca,0x00cb,0x00c8,UBOGON,0x00cd,0x00ce,
0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580,
0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,UBOGON,
0x00d7,0x00da,0x00db,0x00d9,0x00ec,0x00ff,0x00af,0x00b4,
0x00ad,0x00b1,UBOGON,0x00be,0x00b6,0x00a7,0x00f7,0x00b8,
0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
};
/* IBM Portuguese */
static const unsigned short ibm_860tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e3,0x00e0,0x00c1,0x00e7,
0x00ea,0x00ca,0x00e8,0x00cd,0x00d4,0x00ec,0x00c3,0x00c2,
0x00c9,0x00c0,0x00c8,0x00f4,0x00f5,0x00f2,0x00da,0x00f9,
0x00cc,0x00d5,0x00dc,0x00a2,0x00a3,0x00d9,0x20a7,0x00d3,
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
0x00bf,0x00d2,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Icelandic */
static const unsigned short ibm_861tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
0x00ea,0x00eb,0x00e8,0x00d0,0x00f0,0x00de,0x00c4,0x00c5,
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00fe,0x00fb,0x00dd,
0x00fd,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192,
0x00e1,0x00ed,0x00f3,0x00fa,0x00c1,0x00cd,0x00d3,0x00da,
0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Hebrew */
static const unsigned short ibm_862tab[128] = {
0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
0x05e8,0x05e9,0x05ea,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Canada/French */
static const unsigned short ibm_863tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00c2,0x00e0,0x00b6,0x00e7,
0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x2017,0x00c0,0x00a7,
0x00c9,0x00c8,0x00ca,0x00f4,0x00cb,0x00cf,0x00fb,0x00f9,
0x00a4,0x00d4,0x00dc,0x00a2,0x00a3,0x00d9,0x00db,0x0192,
0x00a6,0x00b4,0x00f3,0x00fa,0x00a8,0x00b8,0x00b3,0x00af,
0x00ce,0x2310,0x00ac,0x00bd,0x00bc,0x00be,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Arabic */
static const unsigned short ibm_864tab[128] = {
0x00b0,0x00b7,0x2219,0x221a,0x2592,0x2500,0x2502,0x253c,
0x2524,0x252c,0x251c,0x2534,0x2510,0x250c,0x2514,0x2518,
0x03b2,0x221e,0x03c6,0x00b1,0x00bd,0x00bc,0x2248,0x00ab,
0x00bb,0xfef7,0xfef8,UBOGON,UBOGON,0xfefb,0xfefc,UBOGON,
0x00a0,0x00ad,0xfe82,0x00a3,0x00a4,0xfe84,UBOGON,UBOGON,
0xfe8e,0xfe8f,0xfe95,0xfe99,0x060c,0xfe9d,0xfea1,0xfea5,
0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
0x0668,0x0669,0xfed1,0x061b,0xfeb1,0xfeb5,0xfeb9,0x061f,
0x00a2,0xfe80,0xfe81,0xfe83,0xfe85,0xfeca,0xfe8b,0xfe8d,
0xfe91,0xfe93,0xfe97,0xfe9b,0xfe9f,0xfea3,0xfea7,0xfea9,
0xfeab,0xfead,0xfeaf,0xfeb3,0xfeb7,0xfebb,0xfebf,0xfec1,
0xfec5,0xfecb,0xfecf,0x00a6,0x00ac,0x00f7,0x00d7,0xfec9,
0x0640,0xfed3,0xfed7,0xfedb,0xfedf,0xfee3,0xfee7,0xfeeb,
0xfeed,0xfeef,0xfef3,0xfebd,0xfecc,0xfece,0xfecd,0xfee1,
0xfe7d,0x0651,0xfee5,0xfee9,0xfeec,0xfef0,0xfef2,0xfed0,
0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,UBOGON
};
/* IBM Nordic */
static const unsigned short ibm_865tab[128] = {
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192,
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00a4,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
};
/* IBM Cyrillic/Russian */
static const unsigned short ibm_866tab[128] = {
0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040e,0x045e,
0x00b0,0x2219,0x00b7,0x221a,0x2116,0x00a4,0x25a0,0x00a0
};
/* IBM Greek 2 */
static const unsigned short ibm_869tab[128] = {
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0386,UBOGON,
0x00b7,0x00ac,0x00a6,0x2018,0x2019,0x0388,0x2015,0x0389,
0x038a,0x03aa,0x038c,UBOGON,UBOGON,0x038e,0x03ab,0x00a9,
0x038f,0x00b2,0x00b3,0x03ac,0x00a3,0x03ad,0x03ae,0x03af,
0x03ca,0x0390,0x03cc,0x03cd,0x0391,0x0392,0x0393,0x0394,
0x0395,0x0396,0x0397,0x00bd,0x0398,0x0399,0x00ab,0x00bb,
0x2591,0x2592,0x2593,0x2502,0x2524,0x039a,0x039b,0x039c,
0x039d,0x2563,0x2551,0x2557,0x255d,0x039e,0x039f,0x2510,
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x03a0,0x03a1,
0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x03a3,
0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,
0x03b3,0x2518,0x250c,0x2588,0x2584,0x03b4,0x03b5,0x2580,
0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,
0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c2,0x03c4,0x0384,
0x00ad,0x00b1,0x03c5,0x03c6,0x03c7,0x00a7,0x03c8,0x0385,
0x00b0,0x00a8,0x03c9,0x03cb,0x03b0,0x03ce,0x25a0,0x00a0
};
/* IBM Thai */
static const unsigned short ibm_874tab[128] = {
0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
};

308
src/charset/iso_8859.c Normal file
View File

@@ -0,0 +1,308 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: ISO-8859 conversion tables
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 3 July 1997
* Last Edited: 30 August 2006
*/
/* ISO-8859 conversion tables */
/* Latin-2 (East European) */
static const unsigned short iso8859_2tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x0104,0x02d8,0x0141,0x00a4,0x013d,0x015a,0x00a7,
0x00a8,0x0160,0x015e,0x0164,0x0179,0x00ad,0x017d,0x017b,
0x00b0,0x0105,0x02db,0x0142,0x00b4,0x013e,0x015b,0x02c7,
0x00b8,0x0161,0x015f,0x0165,0x017a,0x02dd,0x017e,0x017c,
0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7,
0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e,
0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7,
0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df,
0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7,
0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f,
0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7,
0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9
};
/* Latin-3 (South European) */
static const unsigned short iso8859_3tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x0126,0x02d8,0x00a3,0x00a4,UBOGON,0x0124,0x00a7,
0x00a8,0x0130,0x015e,0x011e,0x0134,0x00ad,UBOGON,0x017b,
0x00b0,0x0127,0x00b2,0x00b3,0x00b4,0x00b5,0x0125,0x00b7,
0x00b8,0x0131,0x015f,0x011f,0x0135,0x00bd,UBOGON,0x017c,
0x00c0,0x00c1,0x00c2,UBOGON,0x00c4,0x010a,0x0108,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
UBOGON,0x00d1,0x00d2,0x00d3,0x00d4,0x0120,0x00d6,0x00d7,
0x011c,0x00d9,0x00da,0x00db,0x00dc,0x016c,0x015c,0x00df,
0x00e0,0x00e1,0x00e2,UBOGON,0x00e4,0x010b,0x0109,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
UBOGON,0x00f1,0x00f2,0x00f3,0x00f4,0x0121,0x00f6,0x00f7,
0x011d,0x00f9,0x00fa,0x00fb,0x00fc,0x016d,0x015d,0x02d9
};
/* Latin-4 (North European) */
static const unsigned short iso8859_4tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x0104,0x0138,0x0156,0x00a4,0x0128,0x013b,0x00a7,
0x00a8,0x0160,0x0112,0x0122,0x0166,0x00ad,0x017d,0x00af,
0x00b0,0x0105,0x02db,0x0157,0x00b4,0x0129,0x013c,0x02c7,
0x00b8,0x0161,0x0113,0x0123,0x0167,0x014a,0x017e,0x014b,
0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e,
0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x012a,
0x0110,0x0145,0x014c,0x0136,0x00d4,0x00d5,0x00d6,0x00d7,
0x00d8,0x0172,0x00da,0x00db,0x00dc,0x0168,0x016a,0x00df,
0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f,
0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x012b,
0x0111,0x0146,0x014d,0x0137,0x00f4,0x00f5,0x00f6,0x00f7,
0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x0169,0x016b,0x02d9
};
/* Cyrillic */
static const unsigned short iso8859_5tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
0x0408,0x0409,0x040a,0x040b,0x040c,0x00ad,0x040e,0x040f,
0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
0x2116,0x0451,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,
0x0458,0x0459,0x045a,0x045b,0x045c,0x00a7,0x045e,0x045f
};
/* Arabic */
static const unsigned short iso8859_6tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,UBOGON,UBOGON,UBOGON,0x00a4,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,0x060c,0x00ad,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,0x061b,UBOGON,UBOGON,UBOGON,0x061f,
UBOGON,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
0x0638,0x0639,0x063a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
0x0650,0x0651,0x0652,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
};
/* Greek */
static const unsigned short iso8859_7tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x2018,0x2019,0x00a3,UBOGON,UBOGON,0x00a6,0x00a7,
0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,UBOGON,0x2015,
0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x0385,0x0386,0x00b7,
0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f,
0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON
};
/* Hebrew */
static const unsigned short iso8859_8tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2017,
0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON
};
/* Latin-5 (Turkish) */
static const unsigned short iso8859_9tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df,
0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff
};
/* Latin-6 (Nordic) */
static const unsigned short iso8859_10tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x0104,0x0112,0x0122,0x012a,0x0128,0x0136,0x00a7,
0x013b,0x0110,0x0160,0x0166,0x017d,0x00ad,0x016a,0x014a,
0x00b0,0x0105,0x0113,0x0123,0x012b,0x0129,0x0137,0x00b7,
0x013c,0x0111,0x0161,0x0167,0x017e,0x2015,0x016b,0x014b,
0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e,
0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x00cf,
0x00d0,0x0145,0x014c,0x00d3,0x00d4,0x00d5,0x00d6,0x0168,
0x00d8,0x0172,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f,
0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x00ef,
0x00f0,0x0146,0x014d,0x00f3,0x00f4,0x00f5,0x00f6,0x0169,
0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x0138
};
/* Thai */
#define iso8859_11tab tis620tab
/* reserved for ISCII Indian */
/* Latin-7 (Baltic) */
static const unsigned short iso8859_13tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x201d,0x00a2,0x00a3,0x00a4,0x201e,0x00a6,0x00a7,
0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6,
0x00b0,0x00b1,0x00b2,0x00b3,0x201c,0x00b5,0x00b6,0x00b7,
0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6,
0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112,
0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b,
0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7,
0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df,
0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113,
0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c,
0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7,
0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x2019
};
/* Latin-8 (Celtic) */
static const unsigned short iso8859_14tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x1e02,0x1e03,0x00a3,0x010a,0x010b,0x1e0a,0x00a7,
0x1e80,0x00a9,0x1e82,0x1e0b,0x1ef2,0x00ad,0x00ae,0x0178,
0x1e1e,0x1e1f,0x0120,0x0121,0x1e40,0x1e41,0x00b6,0x1e56,
0x1e81,0x1e57,0x1e83,0x1e60,0x1ef3,0x1e84,0x1e85,0x1e61,
0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
0x0174,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x1e6a,
0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x0176,0x00df,
0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
0x0175,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x1e6b,
0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x0177,0x00ff
};
/* Latin-9 a.k.a. Latin-0 (Euro) */
static const unsigned short iso8859_15tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x00a1,0x00a2,0x00a3,0x20ac,0x00a5,0x0160,0x00a7,
0x0161,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x017d,0x00b5,0x00b6,0x00b7,
0x017e,0x00b9,0x00ba,0x00bb,0x0152,0x0153,0x0178,0x00bf,
0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff
};
/* Latin-10 (Balkan) */
static const unsigned short iso8859_16tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
0x00a0,0x0104,0x0105,0x0141,0x20ac,0x201e,0x0160,0x00a7,
0x0161,0x00a9,0x0218,0x00ab,0x0179,0x00ad,0x017a,0x017b,
0x00b0,0x00b1,0x010c,0x0142,0x017d,0x201d,0x00b6,0x00b7,
0x017e,0x010d,0x0219,0x00bb,0x0152,0x0153,0x0178,0x017c,
0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x0106,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
0x0110,0x0143,0x00d2,0x00d3,0x00d4,0x0150,0x00d6,0x015a,
0x0170,0x00d9,0x00da,0x00db,0x00dc,0x0118,0x021a,0x00df,
0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x0107,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
0x0111,0x0144,0x00f2,0x00f3,0x00f4,0x0151,0x00f6,0x015b,
0x0171,0x00f9,0x00fa,0x00fb,0x00fc,0x0119,0x021b,0x00ff
};

1092
src/charset/jis_0208.c Normal file

File diff suppressed because it is too large Load Diff

962
src/charset/jis_0212.c Normal file
View File

@@ -0,0 +1,962 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: JIS X0212 conversion table
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 4 August 1997
* Last Edited: 30 August 2006
*/
/* JIS X0212 is the supplemental industrial standard of Japan. */
#define BASE_JIS0212_KU 0x22
#define BASE_JIS0212_TEN 0x21
#define MAX_JIS0212_KU 76
#define MAX_JIS0212_TEN 94
#define JIS0212TOUNICODE(c,c1,ku,ten) \
((((ku = (c & 0x7f) - BASE_JIS0212_KU) < MAX_JIS0212_KU) && \
((ten = (c1 & 0x7f) - BASE_JIS0212_TEN) < MAX_JIS0212_TEN)) ? \
jis0212tab[ku][ten] : UBOGON)
static const unsigned short jis0212tab[MAX_JIS0212_KU][MAX_JIS0212_TEN] = {
{ /* ku 02 */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,0x02d8,0x02c7,0x00b8,0x02d9,0x02dd,0x00af,
0x02db,0x02da,0x007e,0x0384,0x0385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,0x00a1,0x00a6,0x00bf,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,0x00ba,0x00aa,0x00a9,0x00ae,0x2122,0x00a4,
0x2116,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 03 */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 04 */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 05 */
/* Note: ku/ten codepoints 05/87 - 05/90 are proposed for addition to
* JIS X 0212; I don't know if they've been formally accepted yet.
* They represent katakana VA, VI, VE, and VO, and are in the BMP but
* not in Unicode's JIS conversion tables. They're useful enough that
* I decided to put them here.
*/
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30f7,0x30f8,0x30f9,0x30fa,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 06 */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,0x0386,0x0388,0x0389,0x038a,0x03aa,UBOGON,
0x038c,UBOGON,0x038e,0x03ab,UBOGON,0x038f,UBOGON,UBOGON,UBOGON,UBOGON,
0x03ac,0x03ad,0x03ae,0x03af,0x03ca,0x0390,0x03cc,0x03c2,0x03cd,0x03cb,
0x03b0,0x03ce,UBOGON,UBOGON
},
{ /* ku 07 */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,0x0408,
0x0409,0x040a,0x040b,0x040c,0x040e,0x040f,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,0x0458,0x0459,0x045a,
0x045b,0x045c,0x045e,0x045f
},
{ /* ku 08 */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 09 */
0x00c6,0x0110,UBOGON,0x0126,UBOGON,0x0132,UBOGON,0x0141,0x013f,UBOGON,
0x014a,0x00d8,0x0152,UBOGON,0x0166,0x00de,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,0x00e6,0x0111,0x00f0,0x0127,0x0131,0x0133,0x0138,0x0142,
0x0140,0x0149,0x014b,0x00f8,0x0153,0x00df,0x0167,0x00fe,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 0a */
0x00c1,0x00c0,0x00c4,0x00c2,0x0102,0x01cd,0x0100,0x0104,0x00c5,0x00c3,
0x0106,0x0108,0x010c,0x00c7,0x010a,0x010e,0x00c9,0x00c8,0x00cb,0x00ca,
0x011a,0x0116,0x0112,0x0118,UBOGON,0x011c,0x011e,0x0122,0x0120,0x0124,
0x00cd,0x00cc,0x00cf,0x00ce,0x01cf,0x0130,0x012a,0x012e,0x0128,0x0134,
0x0136,0x0139,0x013d,0x013b,0x0143,0x0147,0x0145,0x00d1,0x00d3,0x00d2,
0x00d6,0x00d4,0x01d1,0x0150,0x014c,0x00d5,0x0154,0x0158,0x0156,0x015a,
0x015c,0x0160,0x015e,0x0164,0x0162,0x00da,0x00d9,0x00dc,0x00db,0x016c,
0x01d3,0x0170,0x016a,0x0172,0x016e,0x0168,0x01d7,0x01db,0x01d9,0x01d5,
0x0174,0x00dd,0x0178,0x0176,0x0179,0x017d,0x017b,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 0b */
0x00e1,0x00e0,0x00e4,0x00e2,0x0103,0x01ce,0x0101,0x0105,0x00e5,0x00e3,
0x0107,0x0109,0x010d,0x00e7,0x010b,0x010f,0x00e9,0x00e8,0x00eb,0x00ea,
0x011b,0x0117,0x0113,0x0119,0x01f5,0x011d,0x011f,UBOGON,0x0121,0x0125,
0x00ed,0x00ec,0x00ef,0x00ee,0x01d0,UBOGON,0x012b,0x012f,0x0129,0x0135,
0x0137,0x013a,0x013e,0x013c,0x0144,0x0148,0x0146,0x00f1,0x00f3,0x00f2,
0x00f6,0x00f4,0x01d2,0x0151,0x014d,0x00f5,0x0155,0x0159,0x0157,0x015b,
0x015d,0x0161,0x015f,0x0165,0x0163,0x00fa,0x00f9,0x00fc,0x00fb,0x016d,
0x01d4,0x0171,0x016b,0x0173,0x016f,0x0169,0x01d8,0x01dc,0x01da,0x01d6,
0x0175,0x00fd,0x00ff,0x0177,0x017a,0x017e,0x017c,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 0c */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 0d */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 0e */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 0f */
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
},
{ /* ku 10 */
0x4e02,0x4e04,0x4e05,0x4e0c,0x4e12,0x4e1f,0x4e23,0x4e24,0x4e28,0x4e2b,
0x4e2e,0x4e2f,0x4e30,0x4e35,0x4e40,0x4e41,0x4e44,0x4e47,0x4e51,0x4e5a,
0x4e5c,0x4e63,0x4e68,0x4e69,0x4e74,0x4e75,0x4e79,0x4e7f,0x4e8d,0x4e96,
0x4e97,0x4e9d,0x4eaf,0x4eb9,0x4ec3,0x4ed0,0x4eda,0x4edb,0x4ee0,0x4ee1,
0x4ee2,0x4ee8,0x4eef,0x4ef1,0x4ef3,0x4ef5,0x4efd,0x4efe,0x4eff,0x4f00,
0x4f02,0x4f03,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f15,0x4f16,0x4f17,0x4f19,
0x4f2e,0x4f31,0x4f60,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f40,
0x4f42,0x4f48,0x4f49,0x4f4b,0x4f4c,0x4f52,0x4f54,0x4f56,0x4f58,0x4f5f,
0x4f63,0x4f6a,0x4f6c,0x4f6e,0x4f71,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d,
0x4f7e,0x4f81,0x4f82,0x4f84
},
{ /* ku 11 */
0x4f85,0x4f89,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92,0x4f93,0x4f94,0x4f97,
0x4f99,0x4f9a,0x4f9e,0x4f9f,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbc,0x4fbd,
0x4fbe,0x4fc0,0x4fc1,0x4fc5,0x4fc6,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd,
0x4fcf,0x4fd2,0x4fdc,0x4fe0,0x4fe2,0x4ff0,0x4ff2,0x4ffc,0x4ffd,0x4fff,
0x5000,0x5001,0x5004,0x5007,0x500a,0x500c,0x500e,0x5010,0x5013,0x5017,
0x5018,0x501b,0x501c,0x501d,0x501e,0x5022,0x5027,0x502e,0x5030,0x5032,
0x5033,0x5035,0x5040,0x5041,0x5042,0x5045,0x5046,0x504a,0x504c,0x504e,
0x5051,0x5052,0x5053,0x5057,0x5059,0x505f,0x5060,0x5062,0x5063,0x5066,
0x5067,0x506a,0x506d,0x5070,0x5071,0x503b,0x5081,0x5083,0x5084,0x5086,
0x508a,0x508e,0x508f,0x5090
},
{ /* ku 12 */
0x5092,0x5093,0x5094,0x5096,0x509b,0x509c,0x509e,0x509f,0x50a0,0x50a1,
0x50a2,0x50aa,0x50af,0x50b0,0x50b9,0x50ba,0x50bd,0x50c0,0x50c3,0x50c4,
0x50c7,0x50cc,0x50ce,0x50d0,0x50d3,0x50d4,0x50d8,0x50dc,0x50dd,0x50df,
0x50e2,0x50e4,0x50e6,0x50e8,0x50e9,0x50ef,0x50f1,0x50f6,0x50fa,0x50fe,
0x5103,0x5106,0x5107,0x5108,0x510b,0x510c,0x510d,0x510e,0x50f2,0x5110,
0x5117,0x5119,0x511b,0x511c,0x511d,0x511e,0x5123,0x5127,0x5128,0x512c,
0x512d,0x512f,0x5131,0x5133,0x5134,0x5135,0x5138,0x5139,0x5142,0x514a,
0x514f,0x5153,0x5155,0x5157,0x5158,0x515f,0x5164,0x5166,0x517e,0x5183,
0x5184,0x518b,0x518e,0x5198,0x519d,0x51a1,0x51a3,0x51ad,0x51b8,0x51ba,
0x51bc,0x51be,0x51bf,0x51c2
},
{ /* ku 13 */
0x51c8,0x51cf,0x51d1,0x51d2,0x51d3,0x51d5,0x51d8,0x51de,0x51e2,0x51e5,
0x51ee,0x51f2,0x51f3,0x51f4,0x51f7,0x5201,0x5202,0x5205,0x5212,0x5213,
0x5215,0x5216,0x5218,0x5222,0x5228,0x5231,0x5232,0x5235,0x523c,0x5245,
0x5249,0x5255,0x5257,0x5258,0x525a,0x525c,0x525f,0x5260,0x5261,0x5266,
0x526e,0x5277,0x5278,0x5279,0x5280,0x5282,0x5285,0x528a,0x528c,0x5293,
0x5295,0x5296,0x5297,0x5298,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7,
0x52af,0x52b0,0x52b6,0x52b7,0x52b8,0x52ba,0x52bb,0x52bd,0x52c0,0x52c4,
0x52c6,0x52c8,0x52cc,0x52cf,0x52d1,0x52d4,0x52d6,0x52db,0x52dc,0x52e1,
0x52e5,0x52e8,0x52e9,0x52ea,0x52ec,0x52f0,0x52f1,0x52f4,0x52f6,0x52f7,
0x5300,0x5303,0x530a,0x530b
},
{ /* ku 14 */
0x530c,0x5311,0x5313,0x5318,0x531b,0x531c,0x531e,0x531f,0x5325,0x5327,
0x5328,0x5329,0x532b,0x532c,0x532d,0x5330,0x5332,0x5335,0x533c,0x533d,
0x533e,0x5342,0x534c,0x534b,0x5359,0x535b,0x5361,0x5363,0x5365,0x536c,
0x536d,0x5372,0x5379,0x537e,0x5383,0x5387,0x5388,0x538e,0x5393,0x5394,
0x5399,0x539d,0x53a1,0x53a4,0x53aa,0x53ab,0x53af,0x53b2,0x53b4,0x53b5,
0x53b7,0x53b8,0x53ba,0x53bd,0x53c0,0x53c5,0x53cf,0x53d2,0x53d3,0x53d5,
0x53da,0x53dd,0x53de,0x53e0,0x53e6,0x53e7,0x53f5,0x5402,0x5413,0x541a,
0x5421,0x5427,0x5428,0x542a,0x542f,0x5431,0x5434,0x5435,0x5443,0x5444,
0x5447,0x544d,0x544f,0x545e,0x5462,0x5464,0x5466,0x5467,0x5469,0x546b,
0x546d,0x546e,0x5474,0x547f
},
{ /* ku 15 */
0x5481,0x5483,0x5485,0x5488,0x5489,0x548d,0x5491,0x5495,0x5496,0x549c,
0x549f,0x54a1,0x54a6,0x54a7,0x54a9,0x54aa,0x54ad,0x54ae,0x54b1,0x54b7,
0x54b9,0x54ba,0x54bb,0x54bf,0x54c6,0x54ca,0x54cd,0x54ce,0x54e0,0x54ea,
0x54ec,0x54ef,0x54f6,0x54fc,0x54fe,0x54ff,0x5500,0x5501,0x5505,0x5508,
0x5509,0x550c,0x550d,0x550e,0x5515,0x552a,0x552b,0x5532,0x5535,0x5536,
0x553b,0x553c,0x553d,0x5541,0x5547,0x5549,0x554a,0x554d,0x5550,0x5551,
0x5558,0x555a,0x555b,0x555e,0x5560,0x5561,0x5564,0x5566,0x557f,0x5581,
0x5582,0x5586,0x5588,0x558e,0x558f,0x5591,0x5592,0x5593,0x5594,0x5597,
0x55a3,0x55a4,0x55ad,0x55b2,0x55bf,0x55c1,0x55c3,0x55c6,0x55c9,0x55cb,
0x55cc,0x55ce,0x55d1,0x55d2
},
{ /* ku 16 */
0x55d3,0x55d7,0x55d8,0x55db,0x55de,0x55e2,0x55e9,0x55f6,0x55ff,0x5605,
0x5608,0x560a,0x560d,0x560e,0x560f,0x5610,0x5611,0x5612,0x5619,0x562c,
0x5630,0x5633,0x5635,0x5637,0x5639,0x563b,0x563c,0x563d,0x563f,0x5640,
0x5641,0x5643,0x5644,0x5646,0x5649,0x564b,0x564d,0x564f,0x5654,0x565e,
0x5660,0x5661,0x5662,0x5663,0x5666,0x5669,0x566d,0x566f,0x5671,0x5672,
0x5675,0x5684,0x5685,0x5688,0x568b,0x568c,0x5695,0x5699,0x569a,0x569d,
0x569e,0x569f,0x56a6,0x56a7,0x56a8,0x56a9,0x56ab,0x56ac,0x56ad,0x56b1,
0x56b3,0x56b7,0x56be,0x56c5,0x56c9,0x56ca,0x56cb,0x56cf,0x56d0,0x56cc,
0x56cd,0x56d9,0x56dc,0x56dd,0x56df,0x56e1,0x56e4,0x56e5,0x56e6,0x56e7,
0x56e8,0x56f1,0x56eb,0x56ed
},
{ /* ku 17 */
0x56f6,0x56f7,0x5701,0x5702,0x5707,0x570a,0x570c,0x5711,0x5715,0x571a,
0x571b,0x571d,0x5720,0x5722,0x5723,0x5724,0x5725,0x5729,0x572a,0x572c,
0x572e,0x572f,0x5733,0x5734,0x573d,0x573e,0x573f,0x5745,0x5746,0x574c,
0x574d,0x5752,0x5762,0x5765,0x5767,0x5768,0x576b,0x576d,0x576e,0x576f,
0x5770,0x5771,0x5773,0x5774,0x5775,0x5777,0x5779,0x577a,0x577b,0x577c,
0x577e,0x5781,0x5783,0x578c,0x5794,0x5797,0x5799,0x579a,0x579c,0x579d,
0x579e,0x579f,0x57a1,0x5795,0x57a7,0x57a8,0x57a9,0x57ac,0x57b8,0x57bd,
0x57c7,0x57c8,0x57cc,0x57cf,0x57d5,0x57dd,0x57de,0x57e4,0x57e6,0x57e7,
0x57e9,0x57ed,0x57f0,0x57f5,0x57f6,0x57f8,0x57fd,0x57fe,0x57ff,0x5803,
0x5804,0x5808,0x5809,0x57e1
},
{ /* ku 18 */
0x580c,0x580d,0x581b,0x581e,0x581f,0x5820,0x5826,0x5827,0x582d,0x5832,
0x5839,0x583f,0x5849,0x584c,0x584d,0x584f,0x5850,0x5855,0x585f,0x5861,
0x5864,0x5867,0x5868,0x5878,0x587c,0x587f,0x5880,0x5881,0x5887,0x5888,
0x5889,0x588a,0x588c,0x588d,0x588f,0x5890,0x5894,0x5896,0x589d,0x58a0,
0x58a1,0x58a2,0x58a6,0x58a9,0x58b1,0x58b2,0x58c4,0x58bc,0x58c2,0x58c8,
0x58cd,0x58ce,0x58d0,0x58d2,0x58d4,0x58d6,0x58da,0x58dd,0x58e1,0x58e2,
0x58e9,0x58f3,0x5905,0x5906,0x590b,0x590c,0x5912,0x5913,0x5914,0x8641,
0x591d,0x5921,0x5923,0x5924,0x5928,0x592f,0x5930,0x5933,0x5935,0x5936,
0x593f,0x5943,0x5946,0x5952,0x5953,0x5959,0x595b,0x595d,0x595e,0x595f,
0x5961,0x5963,0x596b,0x596d
},
{ /* ku 19 */
0x596f,0x5972,0x5975,0x5976,0x5979,0x597b,0x597c,0x598b,0x598c,0x598e,
0x5992,0x5995,0x5997,0x599f,0x59a4,0x59a7,0x59ad,0x59ae,0x59af,0x59b0,
0x59b3,0x59b7,0x59ba,0x59bc,0x59c1,0x59c3,0x59c4,0x59c8,0x59ca,0x59cd,
0x59d2,0x59dd,0x59de,0x59df,0x59e3,0x59e4,0x59e7,0x59ee,0x59ef,0x59f1,
0x59f2,0x59f4,0x59f7,0x5a00,0x5a04,0x5a0c,0x5a0d,0x5a0e,0x5a12,0x5a13,
0x5a1e,0x5a23,0x5a24,0x5a27,0x5a28,0x5a2a,0x5a2d,0x5a30,0x5a44,0x5a45,
0x5a47,0x5a48,0x5a4c,0x5a50,0x5a55,0x5a5e,0x5a63,0x5a65,0x5a67,0x5a6d,
0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a8b,0x5a90,0x5a93,0x5a96,0x5a99,0x5a9c,
0x5a9e,0x5a9f,0x5aa0,0x5aa2,0x5aa7,0x5aac,0x5ab1,0x5ab2,0x5ab3,0x5ab5,
0x5ab8,0x5aba,0x5abb,0x5abf
},
{ /* ku 1a */
0x5ac4,0x5ac6,0x5ac8,0x5acf,0x5ada,0x5adc,0x5ae0,0x5ae5,0x5aea,0x5aee,
0x5af5,0x5af6,0x5afd,0x5b00,0x5b01,0x5b08,0x5b17,0x5b34,0x5b19,0x5b1b,
0x5b1d,0x5b21,0x5b25,0x5b2d,0x5b38,0x5b41,0x5b4b,0x5b4c,0x5b52,0x5b56,
0x5b5e,0x5b68,0x5b6e,0x5b6f,0x5b7c,0x5b7d,0x5b7e,0x5b7f,0x5b81,0x5b84,
0x5b86,0x5b8a,0x5b8e,0x5b90,0x5b91,0x5b93,0x5b94,0x5b96,0x5ba8,0x5ba9,
0x5bac,0x5bad,0x5baf,0x5bb1,0x5bb2,0x5bb7,0x5bba,0x5bbc,0x5bc0,0x5bc1,
0x5bcd,0x5bcf,0x5bd6,0x5bd7,0x5bd8,0x5bd9,0x5bda,0x5be0,0x5bef,0x5bf1,
0x5bf4,0x5bfd,0x5c0c,0x5c17,0x5c1e,0x5c1f,0x5c23,0x5c26,0x5c29,0x5c2b,
0x5c2c,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c59,0x5c5a,0x5c5c,0x5c62,
0x5c63,0x5c67,0x5c68,0x5c69
},
{ /* ku 1b */
0x5c6d,0x5c70,0x5c74,0x5c75,0x5c7a,0x5c7b,0x5c7c,0x5c7d,0x5c87,0x5c88,
0x5c8a,0x5c8f,0x5c92,0x5c9d,0x5c9f,0x5ca0,0x5ca2,0x5ca3,0x5ca6,0x5caa,
0x5cb2,0x5cb4,0x5cb5,0x5cba,0x5cc9,0x5ccb,0x5cd2,0x5cdd,0x5cd7,0x5cee,
0x5cf1,0x5cf2,0x5cf4,0x5d01,0x5d06,0x5d0d,0x5d12,0x5d2b,0x5d23,0x5d24,
0x5d26,0x5d27,0x5d31,0x5d34,0x5d39,0x5d3d,0x5d3f,0x5d42,0x5d43,0x5d46,
0x5d48,0x5d55,0x5d51,0x5d59,0x5d4a,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d64,
0x5d6a,0x5d6d,0x5d70,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d83,0x5d88,
0x5d8a,0x5d92,0x5d93,0x5d94,0x5d95,0x5d99,0x5d9b,0x5d9f,0x5da0,0x5da7,
0x5dab,0x5db0,0x5db4,0x5db8,0x5db9,0x5dc3,0x5dc7,0x5dcb,0x5dd0,0x5dce,
0x5dd8,0x5dd9,0x5de0,0x5de4
},
{ /* ku 1c */
0x5de9,0x5df8,0x5df9,0x5e00,0x5e07,0x5e0d,0x5e12,0x5e14,0x5e15,0x5e18,
0x5e1f,0x5e20,0x5e2e,0x5e28,0x5e32,0x5e35,0x5e3e,0x5e4b,0x5e50,0x5e49,
0x5e51,0x5e56,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e68,0x5e6a,0x5e6b,0x5e6c,
0x5e6d,0x5e6e,0x5e70,0x5e80,0x5e8b,0x5e8e,0x5ea2,0x5ea4,0x5ea5,0x5ea8,
0x5eaa,0x5eac,0x5eb1,0x5eb3,0x5ebd,0x5ebe,0x5ebf,0x5ec6,0x5ecc,0x5ecb,
0x5ece,0x5ed1,0x5ed2,0x5ed4,0x5ed5,0x5edc,0x5ede,0x5ee5,0x5eeb,0x5f02,
0x5f06,0x5f07,0x5f08,0x5f0e,0x5f19,0x5f1c,0x5f1d,0x5f21,0x5f22,0x5f23,
0x5f24,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f34,0x5f36,0x5f3b,0x5f3d,
0x5f3f,0x5f40,0x5f44,0x5f45,0x5f47,0x5f4d,0x5f50,0x5f54,0x5f58,0x5f5b,
0x5f60,0x5f63,0x5f64,0x5f67
},
{ /* ku 1d */
0x5f6f,0x5f72,0x5f74,0x5f75,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f89,0x5f8d,
0x5f8f,0x5f96,0x5f9c,0x5f9d,0x5fa2,0x5fa7,0x5fab,0x5fa4,0x5fac,0x5faf,
0x5fb0,0x5fb1,0x5fb8,0x5fc4,0x5fc7,0x5fc8,0x5fc9,0x5fcb,0x5fd0,0x5fd1,
0x5fd2,0x5fd3,0x5fd4,0x5fde,0x5fe1,0x5fe2,0x5fe8,0x5fe9,0x5fea,0x5fec,
0x5fed,0x5fee,0x5fef,0x5ff2,0x5ff3,0x5ff6,0x5ffa,0x5ffc,0x6007,0x600a,
0x600d,0x6013,0x6014,0x6017,0x6018,0x601a,0x601f,0x6024,0x602d,0x6033,
0x6035,0x6040,0x6047,0x6048,0x6049,0x604c,0x6051,0x6054,0x6056,0x6057,
0x605d,0x6061,0x6067,0x6071,0x607e,0x607f,0x6082,0x6086,0x6088,0x608a,
0x608e,0x6091,0x6093,0x6095,0x6098,0x609d,0x609e,0x60a2,0x60a4,0x60a5,
0x60a8,0x60b0,0x60b1,0x60b7
},
{ /* ku 1e */
0x60bb,0x60be,0x60c2,0x60c4,0x60c8,0x60c9,0x60ca,0x60cb,0x60ce,0x60cf,
0x60d4,0x60d5,0x60d9,0x60db,0x60dd,0x60de,0x60e2,0x60e5,0x60f2,0x60f5,
0x60f8,0x60fc,0x60fd,0x6102,0x6107,0x610a,0x610c,0x6110,0x6111,0x6112,
0x6113,0x6114,0x6116,0x6117,0x6119,0x611c,0x611e,0x6122,0x612a,0x612b,
0x6130,0x6131,0x6135,0x6136,0x6137,0x6139,0x6141,0x6145,0x6146,0x6149,
0x615e,0x6160,0x616c,0x6172,0x6178,0x617b,0x617c,0x617f,0x6180,0x6181,
0x6183,0x6184,0x618b,0x618d,0x6192,0x6193,0x6197,0x6198,0x619c,0x619d,
0x619f,0x61a0,0x61a5,0x61a8,0x61aa,0x61ad,0x61b8,0x61b9,0x61bc,0x61c0,
0x61c1,0x61c2,0x61ce,0x61cf,0x61d5,0x61dc,0x61dd,0x61de,0x61df,0x61e1,
0x61e2,0x61e7,0x61e9,0x61e5
},
{ /* ku 1f */
0x61ec,0x61ed,0x61ef,0x6201,0x6203,0x6204,0x6207,0x6213,0x6215,0x621c,
0x6220,0x6222,0x6223,0x6227,0x6229,0x622b,0x6239,0x623d,0x6242,0x6243,
0x6244,0x6246,0x624c,0x6250,0x6251,0x6252,0x6254,0x6256,0x625a,0x625c,
0x6264,0x626d,0x626f,0x6273,0x627a,0x627d,0x628d,0x628e,0x628f,0x6290,
0x62a6,0x62a8,0x62b3,0x62b6,0x62b7,0x62ba,0x62be,0x62bf,0x62c4,0x62ce,
0x62d5,0x62d6,0x62da,0x62ea,0x62f2,0x62f4,0x62fc,0x62fd,0x6303,0x6304,
0x630a,0x630b,0x630d,0x6310,0x6313,0x6316,0x6318,0x6329,0x632a,0x632d,
0x6335,0x6336,0x6339,0x633c,0x6341,0x6342,0x6343,0x6344,0x6346,0x634a,
0x634b,0x634e,0x6352,0x6353,0x6354,0x6358,0x635b,0x6365,0x6366,0x636c,
0x636d,0x6371,0x6374,0x6375
},
{ /* ku 20 */
0x6378,0x637c,0x637d,0x637f,0x6382,0x6384,0x6387,0x638a,0x6390,0x6394,
0x6395,0x6399,0x639a,0x639e,0x63a4,0x63a6,0x63ad,0x63ae,0x63af,0x63bd,
0x63c1,0x63c5,0x63c8,0x63ce,0x63d1,0x63d3,0x63d4,0x63d5,0x63dc,0x63e0,
0x63e5,0x63ea,0x63ec,0x63f2,0x63f3,0x63f5,0x63f8,0x63f9,0x6409,0x640a,
0x6410,0x6412,0x6414,0x6418,0x641e,0x6420,0x6422,0x6424,0x6425,0x6429,
0x642a,0x642f,0x6430,0x6435,0x643d,0x643f,0x644b,0x644f,0x6451,0x6452,
0x6453,0x6454,0x645a,0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6463,
0x646d,0x6473,0x6474,0x647b,0x647d,0x6485,0x6487,0x648f,0x6490,0x6491,
0x6498,0x6499,0x649b,0x649d,0x649f,0x64a1,0x64a3,0x64a6,0x64a8,0x64ac,
0x64b3,0x64bd,0x64be,0x64bf
},
{ /* ku 21 */
0x64c4,0x64c9,0x64ca,0x64cb,0x64cc,0x64ce,0x64d0,0x64d1,0x64d5,0x64d7,
0x64e4,0x64e5,0x64e9,0x64ea,0x64ed,0x64f0,0x64f5,0x64f7,0x64fb,0x64ff,
0x6501,0x6504,0x6508,0x6509,0x650a,0x650f,0x6513,0x6514,0x6516,0x6519,
0x651b,0x651e,0x651f,0x6522,0x6526,0x6529,0x652e,0x6531,0x653a,0x653c,
0x653d,0x6543,0x6547,0x6549,0x6550,0x6552,0x6554,0x655f,0x6560,0x6567,
0x656b,0x657a,0x657d,0x6581,0x6585,0x658a,0x6592,0x6595,0x6598,0x659d,
0x65a0,0x65a3,0x65a6,0x65ae,0x65b2,0x65b3,0x65b4,0x65bf,0x65c2,0x65c8,
0x65c9,0x65ce,0x65d0,0x65d4,0x65d6,0x65d8,0x65df,0x65f0,0x65f2,0x65f4,
0x65f5,0x65f9,0x65fe,0x65ff,0x6600,0x6604,0x6608,0x6609,0x660d,0x6611,
0x6612,0x6615,0x6616,0x661d
},
{ /* ku 22 */
0x661e,0x6621,0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c,
0x662e,0x6630,0x6631,0x6633,0x6639,0x6637,0x6640,0x6645,0x6646,0x664a,
0x664c,0x6651,0x664e,0x6657,0x6658,0x6659,0x665b,0x665c,0x6660,0x6661,
0x66fb,0x666a,0x666b,0x666c,0x667e,0x6673,0x6675,0x667f,0x6677,0x6678,
0x6679,0x667b,0x6680,0x667c,0x668b,0x668c,0x668d,0x6690,0x6692,0x6699,
0x669a,0x669b,0x669c,0x669f,0x66a0,0x66a4,0x66ad,0x66b1,0x66b2,0x66b5,
0x66bb,0x66bf,0x66c0,0x66c2,0x66c3,0x66c8,0x66cc,0x66ce,0x66cf,0x66d4,
0x66db,0x66df,0x66e8,0x66eb,0x66ec,0x66ee,0x66fa,0x6705,0x6707,0x670e,
0x6713,0x6719,0x671c,0x6720,0x6722,0x6733,0x673e,0x6745,0x6747,0x6748,
0x674c,0x6754,0x6755,0x675d
},
{ /* ku 23 */
0x6766,0x676c,0x676e,0x6774,0x6776,0x677b,0x6781,0x6784,0x678e,0x678f,
0x6791,0x6793,0x6796,0x6798,0x6799,0x679b,0x67b0,0x67b1,0x67b2,0x67b5,
0x67bb,0x67bc,0x67bd,0x67f9,0x67c0,0x67c2,0x67c3,0x67c5,0x67c8,0x67c9,
0x67d2,0x67d7,0x67d9,0x67dc,0x67e1,0x67e6,0x67f0,0x67f2,0x67f6,0x67f7,
0x6852,0x6814,0x6819,0x681d,0x681f,0x6828,0x6827,0x682c,0x682d,0x682f,
0x6830,0x6831,0x6833,0x683b,0x683f,0x6844,0x6845,0x684a,0x684c,0x6855,
0x6857,0x6858,0x685b,0x686b,0x686e,0x686f,0x6870,0x6871,0x6872,0x6875,
0x6879,0x687a,0x687b,0x687c,0x6882,0x6884,0x6886,0x6888,0x6896,0x6898,
0x689a,0x689c,0x68a1,0x68a3,0x68a5,0x68a9,0x68aa,0x68ae,0x68b2,0x68bb,
0x68c5,0x68c8,0x68cc,0x68cf
},
{ /* ku 24 */
0x68d0,0x68d1,0x68d3,0x68d6,0x68d9,0x68dc,0x68dd,0x68e5,0x68e8,0x68ea,
0x68eb,0x68ec,0x68ed,0x68f0,0x68f1,0x68f5,0x68f6,0x68fb,0x68fc,0x68fd,
0x6906,0x6909,0x690a,0x6910,0x6911,0x6913,0x6916,0x6917,0x6931,0x6933,
0x6935,0x6938,0x693b,0x6942,0x6945,0x6949,0x694e,0x6957,0x695b,0x6963,
0x6964,0x6965,0x6966,0x6968,0x6969,0x696c,0x6970,0x6971,0x6972,0x697a,
0x697b,0x697f,0x6980,0x698d,0x6992,0x6996,0x6998,0x69a1,0x69a5,0x69a6,
0x69a8,0x69ab,0x69ad,0x69af,0x69b7,0x69b8,0x69ba,0x69bc,0x69c5,0x69c8,
0x69d1,0x69d6,0x69d7,0x69e2,0x69e5,0x69ee,0x69ef,0x69f1,0x69f3,0x69f5,
0x69fe,0x6a00,0x6a01,0x6a03,0x6a0f,0x6a11,0x6a15,0x6a1a,0x6a1d,0x6a20,
0x6a24,0x6a28,0x6a30,0x6a32
},
{ /* ku 25 */
0x6a34,0x6a37,0x6a3b,0x6a3e,0x6a3f,0x6a45,0x6a46,0x6a49,0x6a4a,0x6a4e,
0x6a50,0x6a51,0x6a52,0x6a55,0x6a56,0x6a5b,0x6a64,0x6a67,0x6a6a,0x6a71,
0x6a73,0x6a7e,0x6a81,0x6a83,0x6a86,0x6a87,0x6a89,0x6a8b,0x6a91,0x6a9b,
0x6a9d,0x6a9e,0x6a9f,0x6aa5,0x6aab,0x6aaf,0x6ab0,0x6ab1,0x6ab4,0x6abd,
0x6abe,0x6abf,0x6ac6,0x6ac9,0x6ac8,0x6acc,0x6ad0,0x6ad4,0x6ad5,0x6ad6,
0x6adc,0x6add,0x6ae4,0x6ae7,0x6aec,0x6af0,0x6af1,0x6af2,0x6afc,0x6afd,
0x6b02,0x6b03,0x6b06,0x6b07,0x6b09,0x6b0f,0x6b10,0x6b11,0x6b17,0x6b1b,
0x6b1e,0x6b24,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b35,0x6b36,0x6b3b,0x6b3f,
0x6b46,0x6b4a,0x6b4d,0x6b52,0x6b56,0x6b58,0x6b5d,0x6b60,0x6b67,0x6b6b,
0x6b6e,0x6b70,0x6b75,0x6b7d
},
{ /* ku 26 */
0x6b7e,0x6b82,0x6b85,0x6b97,0x6b9b,0x6b9f,0x6ba0,0x6ba2,0x6ba3,0x6ba8,
0x6ba9,0x6bac,0x6bad,0x6bae,0x6bb0,0x6bb8,0x6bb9,0x6bbd,0x6bbe,0x6bc3,
0x6bc4,0x6bc9,0x6bcc,0x6bd6,0x6bda,0x6be1,0x6be3,0x6be6,0x6be7,0x6bee,
0x6bf1,0x6bf7,0x6bf9,0x6bff,0x6c02,0x6c04,0x6c05,0x6c09,0x6c0d,0x6c0e,
0x6c10,0x6c12,0x6c19,0x6c1f,0x6c26,0x6c27,0x6c28,0x6c2c,0x6c2e,0x6c33,
0x6c35,0x6c36,0x6c3a,0x6c3b,0x6c3f,0x6c4a,0x6c4b,0x6c4d,0x6c4f,0x6c52,
0x6c54,0x6c59,0x6c5b,0x6c5c,0x6c6b,0x6c6d,0x6c6f,0x6c74,0x6c76,0x6c78,
0x6c79,0x6c7b,0x6c85,0x6c86,0x6c87,0x6c89,0x6c94,0x6c95,0x6c97,0x6c98,
0x6c9c,0x6c9f,0x6cb0,0x6cb2,0x6cb4,0x6cc2,0x6cc6,0x6ccd,0x6ccf,0x6cd0,
0x6cd1,0x6cd2,0x6cd4,0x6cd6
},
{ /* ku 27 */
0x6cda,0x6cdc,0x6ce0,0x6ce7,0x6ce9,0x6ceb,0x6cec,0x6cee,0x6cf2,0x6cf4,
0x6d04,0x6d07,0x6d0a,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d1a,0x6d26,0x6d27,
0x6d28,0x6c67,0x6d2e,0x6d2f,0x6d31,0x6d39,0x6d3c,0x6d3f,0x6d57,0x6d5e,
0x6d5f,0x6d61,0x6d65,0x6d67,0x6d6f,0x6d70,0x6d7c,0x6d82,0x6d87,0x6d91,
0x6d92,0x6d94,0x6d96,0x6d97,0x6d98,0x6daa,0x6dac,0x6db4,0x6db7,0x6db9,
0x6dbd,0x6dbf,0x6dc4,0x6dc8,0x6dca,0x6dce,0x6dcf,0x6dd6,0x6ddb,0x6ddd,
0x6ddf,0x6de0,0x6de2,0x6de5,0x6de9,0x6def,0x6df0,0x6df4,0x6df6,0x6dfc,
0x6e00,0x6e04,0x6e1e,0x6e22,0x6e27,0x6e32,0x6e36,0x6e39,0x6e3b,0x6e3c,
0x6e44,0x6e45,0x6e48,0x6e49,0x6e4b,0x6e4f,0x6e51,0x6e52,0x6e53,0x6e54,
0x6e57,0x6e5c,0x6e5d,0x6e5e
},
{ /* ku 28 */
0x6e62,0x6e63,0x6e68,0x6e73,0x6e7b,0x6e7d,0x6e8d,0x6e93,0x6e99,0x6ea0,
0x6ea7,0x6ead,0x6eae,0x6eb1,0x6eb3,0x6ebb,0x6ebf,0x6ec0,0x6ec1,0x6ec3,
0x6ec7,0x6ec8,0x6eca,0x6ecd,0x6ece,0x6ecf,0x6eeb,0x6eed,0x6eee,0x6ef9,
0x6efb,0x6efd,0x6f04,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f16,0x6f18,0x6f1a,
0x6f1b,0x6f26,0x6f29,0x6f2a,0x6f2f,0x6f30,0x6f33,0x6f36,0x6f3b,0x6f3c,
0x6f2d,0x6f4f,0x6f51,0x6f52,0x6f53,0x6f57,0x6f59,0x6f5a,0x6f5d,0x6f5e,
0x6f61,0x6f62,0x6f68,0x6f6c,0x6f7d,0x6f7e,0x6f83,0x6f87,0x6f88,0x6f8b,
0x6f8c,0x6f8d,0x6f90,0x6f92,0x6f93,0x6f94,0x6f96,0x6f9a,0x6f9f,0x6fa0,
0x6fa5,0x6fa6,0x6fa7,0x6fa8,0x6fae,0x6faf,0x6fb0,0x6fb5,0x6fb6,0x6fbc,
0x6fc5,0x6fc7,0x6fc8,0x6fca
},
{ /* ku 29 */
0x6fda,0x6fde,0x6fe8,0x6fe9,0x6ff0,0x6ff5,0x6ff9,0x6ffc,0x6ffd,0x7000,
0x7005,0x7006,0x7007,0x700d,0x7017,0x7020,0x7023,0x702f,0x7034,0x7037,
0x7039,0x703c,0x7043,0x7044,0x7048,0x7049,0x704a,0x704b,0x7054,0x7055,
0x705d,0x705e,0x704e,0x7064,0x7065,0x706c,0x706e,0x7075,0x7076,0x707e,
0x7081,0x7085,0x7086,0x7094,0x7095,0x7096,0x7097,0x7098,0x709b,0x70a4,
0x70ab,0x70b0,0x70b1,0x70b4,0x70b7,0x70ca,0x70d1,0x70d3,0x70d4,0x70d5,
0x70d6,0x70d8,0x70dc,0x70e4,0x70fa,0x7103,0x7104,0x7105,0x7106,0x7107,
0x710b,0x710c,0x710f,0x711e,0x7120,0x712b,0x712d,0x712f,0x7130,0x7131,
0x7138,0x7141,0x7145,0x7146,0x7147,0x714a,0x714b,0x7150,0x7152,0x7157,
0x715a,0x715c,0x715e,0x7160
},
{ /* ku 2a */
0x7168,0x7179,0x7180,0x7185,0x7187,0x718c,0x7192,0x719a,0x719b,0x71a0,
0x71a2,0x71af,0x71b0,0x71b2,0x71b3,0x71ba,0x71bf,0x71c0,0x71c1,0x71c4,
0x71cb,0x71cc,0x71d3,0x71d6,0x71d9,0x71da,0x71dc,0x71f8,0x71fe,0x7200,
0x7207,0x7208,0x7209,0x7213,0x7217,0x721a,0x721d,0x721f,0x7224,0x722b,
0x722f,0x7234,0x7238,0x7239,0x7241,0x7242,0x7243,0x7245,0x724e,0x724f,
0x7250,0x7253,0x7255,0x7256,0x725a,0x725c,0x725e,0x7260,0x7263,0x7268,
0x726b,0x726e,0x726f,0x7271,0x7277,0x7278,0x727b,0x727c,0x727f,0x7284,
0x7289,0x728d,0x728e,0x7293,0x729b,0x72a8,0x72ad,0x72ae,0x72b1,0x72b4,
0x72be,0x72c1,0x72c7,0x72c9,0x72cc,0x72d5,0x72d6,0x72d8,0x72df,0x72e5,
0x72f3,0x72f4,0x72fa,0x72fb
},
{ /* ku 2b */
0x72fe,0x7302,0x7304,0x7305,0x7307,0x730b,0x730d,0x7312,0x7313,0x7318,
0x7319,0x731e,0x7322,0x7324,0x7327,0x7328,0x732c,0x7331,0x7332,0x7335,
0x733a,0x733b,0x733d,0x7343,0x734d,0x7350,0x7352,0x7356,0x7358,0x735d,
0x735e,0x735f,0x7360,0x7366,0x7367,0x7369,0x736b,0x736c,0x736e,0x736f,
0x7371,0x7377,0x7379,0x737c,0x7380,0x7381,0x7383,0x7385,0x7386,0x738e,
0x7390,0x7393,0x7395,0x7397,0x7398,0x739c,0x739e,0x739f,0x73a0,0x73a2,
0x73a5,0x73a6,0x73aa,0x73ab,0x73ad,0x73b5,0x73b7,0x73b9,0x73bc,0x73bd,
0x73bf,0x73c5,0x73c6,0x73c9,0x73cb,0x73cc,0x73cf,0x73d2,0x73d3,0x73d6,
0x73d9,0x73dd,0x73e1,0x73e3,0x73e6,0x73e7,0x73e9,0x73f4,0x73f5,0x73f7,
0x73f9,0x73fa,0x73fb,0x73fd
},
{ /* ku 2c */
0x73ff,0x7400,0x7401,0x7404,0x7407,0x740a,0x7411,0x741a,0x741b,0x7424,
0x7426,0x7428,0x7429,0x742a,0x742b,0x742c,0x742d,0x742e,0x742f,0x7430,
0x7431,0x7439,0x7440,0x7443,0x7444,0x7446,0x7447,0x744b,0x744d,0x7451,
0x7452,0x7457,0x745d,0x7462,0x7466,0x7467,0x7468,0x746b,0x746d,0x746e,
0x7471,0x7472,0x7480,0x7481,0x7485,0x7486,0x7487,0x7489,0x748f,0x7490,
0x7491,0x7492,0x7498,0x7499,0x749a,0x749c,0x749f,0x74a0,0x74a1,0x74a3,
0x74a6,0x74a8,0x74a9,0x74aa,0x74ab,0x74ae,0x74af,0x74b1,0x74b2,0x74b5,
0x74b9,0x74bb,0x74bf,0x74c8,0x74c9,0x74cc,0x74d0,0x74d3,0x74d8,0x74da,
0x74db,0x74de,0x74df,0x74e4,0x74e8,0x74ea,0x74eb,0x74ef,0x74f4,0x74fa,
0x74fb,0x74fc,0x74ff,0x7506
},
{ /* ku 2d */
0x7512,0x7516,0x7517,0x7520,0x7521,0x7524,0x7527,0x7529,0x752a,0x752f,
0x7536,0x7539,0x753d,0x753e,0x753f,0x7540,0x7543,0x7547,0x7548,0x754e,
0x7550,0x7552,0x7557,0x755e,0x755f,0x7561,0x756f,0x7571,0x7579,0x757a,
0x757b,0x757c,0x757d,0x757e,0x7581,0x7585,0x7590,0x7592,0x7593,0x7595,
0x7599,0x759c,0x75a2,0x75a4,0x75b4,0x75ba,0x75bf,0x75c0,0x75c1,0x75c4,
0x75c6,0x75cc,0x75ce,0x75cf,0x75d7,0x75dc,0x75df,0x75e0,0x75e1,0x75e4,
0x75e7,0x75ec,0x75ee,0x75ef,0x75f1,0x75f9,0x7600,0x7602,0x7603,0x7604,
0x7607,0x7608,0x760a,0x760c,0x760f,0x7612,0x7613,0x7615,0x7616,0x7619,
0x761b,0x761c,0x761d,0x761e,0x7623,0x7625,0x7626,0x7629,0x762d,0x7632,
0x7633,0x7635,0x7638,0x7639
},
{ /* ku 2e */
0x763a,0x763c,0x764a,0x7640,0x7641,0x7643,0x7644,0x7645,0x7649,0x764b,
0x7655,0x7659,0x765f,0x7664,0x7665,0x766d,0x766e,0x766f,0x7671,0x7674,
0x7681,0x7685,0x768c,0x768d,0x7695,0x769b,0x769c,0x769d,0x769f,0x76a0,
0x76a2,0x76a3,0x76a4,0x76a5,0x76a6,0x76a7,0x76a8,0x76aa,0x76ad,0x76bd,
0x76c1,0x76c5,0x76c9,0x76cb,0x76cc,0x76ce,0x76d4,0x76d9,0x76e0,0x76e6,
0x76e8,0x76ec,0x76f0,0x76f1,0x76f6,0x76f9,0x76fc,0x7700,0x7706,0x770a,
0x770e,0x7712,0x7714,0x7715,0x7717,0x7719,0x771a,0x771c,0x7722,0x7728,
0x772d,0x772e,0x772f,0x7734,0x7735,0x7736,0x7739,0x773d,0x773e,0x7742,
0x7745,0x7746,0x774a,0x774d,0x774e,0x774f,0x7752,0x7756,0x7757,0x775c,
0x775e,0x775f,0x7760,0x7762
},
{ /* ku 2f */
0x7764,0x7767,0x776a,0x776c,0x7770,0x7772,0x7773,0x7774,0x777a,0x777d,
0x7780,0x7784,0x778c,0x778d,0x7794,0x7795,0x7796,0x779a,0x779f,0x77a2,
0x77a7,0x77aa,0x77ae,0x77af,0x77b1,0x77b5,0x77be,0x77c3,0x77c9,0x77d1,
0x77d2,0x77d5,0x77d9,0x77de,0x77df,0x77e0,0x77e4,0x77e6,0x77ea,0x77ec,
0x77f0,0x77f1,0x77f4,0x77f8,0x77fb,0x7805,0x7806,0x7809,0x780d,0x780e,
0x7811,0x781d,0x7821,0x7822,0x7823,0x782d,0x782e,0x7830,0x7835,0x7837,
0x7843,0x7844,0x7847,0x7848,0x784c,0x784e,0x7852,0x785c,0x785e,0x7860,
0x7861,0x7863,0x7864,0x7868,0x786a,0x786e,0x787a,0x787e,0x788a,0x788f,
0x7894,0x7898,0x78a1,0x789d,0x789e,0x789f,0x78a4,0x78a8,0x78ac,0x78ad,
0x78b0,0x78b1,0x78b2,0x78b3
},
{ /* ku 30 */
0x78bb,0x78bd,0x78bf,0x78c7,0x78c8,0x78c9,0x78cc,0x78ce,0x78d2,0x78d3,
0x78d5,0x78d6,0x78e4,0x78db,0x78df,0x78e0,0x78e1,0x78e6,0x78ea,0x78f2,
0x78f3,0x7900,0x78f6,0x78f7,0x78fa,0x78fb,0x78ff,0x7906,0x790c,0x7910,
0x791a,0x791c,0x791e,0x791f,0x7920,0x7925,0x7927,0x7929,0x792d,0x7931,
0x7934,0x7935,0x793b,0x793d,0x793f,0x7944,0x7945,0x7946,0x794a,0x794b,
0x794f,0x7951,0x7954,0x7958,0x795b,0x795c,0x7967,0x7969,0x796b,0x7972,
0x7979,0x797b,0x797c,0x797e,0x798b,0x798c,0x7991,0x7993,0x7994,0x7995,
0x7996,0x7998,0x799b,0x799c,0x79a1,0x79a8,0x79a9,0x79ab,0x79af,0x79b1,
0x79b4,0x79b8,0x79bb,0x79c2,0x79c4,0x79c7,0x79c8,0x79ca,0x79cf,0x79d4,
0x79d6,0x79da,0x79dd,0x79de
},
{ /* ku 31 */
0x79e0,0x79e2,0x79e5,0x79ea,0x79eb,0x79ed,0x79f1,0x79f8,0x79fc,0x7a02,
0x7a03,0x7a07,0x7a09,0x7a0a,0x7a0c,0x7a11,0x7a15,0x7a1b,0x7a1e,0x7a21,
0x7a27,0x7a2b,0x7a2d,0x7a2f,0x7a30,0x7a34,0x7a35,0x7a38,0x7a39,0x7a3a,
0x7a44,0x7a45,0x7a47,0x7a48,0x7a4c,0x7a55,0x7a56,0x7a59,0x7a5c,0x7a5d,
0x7a5f,0x7a60,0x7a65,0x7a67,0x7a6a,0x7a6d,0x7a75,0x7a78,0x7a7e,0x7a80,
0x7a82,0x7a85,0x7a86,0x7a8a,0x7a8b,0x7a90,0x7a91,0x7a94,0x7a9e,0x7aa0,
0x7aa3,0x7aac,0x7ab3,0x7ab5,0x7ab9,0x7abb,0x7abc,0x7ac6,0x7ac9,0x7acc,
0x7ace,0x7ad1,0x7adb,0x7ae8,0x7ae9,0x7aeb,0x7aec,0x7af1,0x7af4,0x7afb,
0x7afd,0x7afe,0x7b07,0x7b14,0x7b1f,0x7b23,0x7b27,0x7b29,0x7b2a,0x7b2b,
0x7b2d,0x7b2e,0x7b2f,0x7b30
},
{ /* ku 32 */
0x7b31,0x7b34,0x7b3d,0x7b3f,0x7b40,0x7b41,0x7b47,0x7b4e,0x7b55,0x7b60,
0x7b64,0x7b66,0x7b69,0x7b6a,0x7b6d,0x7b6f,0x7b72,0x7b73,0x7b77,0x7b84,
0x7b89,0x7b8e,0x7b90,0x7b91,0x7b96,0x7b9b,0x7b9e,0x7ba0,0x7ba5,0x7bac,
0x7baf,0x7bb0,0x7bb2,0x7bb5,0x7bb6,0x7bba,0x7bbb,0x7bbc,0x7bbd,0x7bc2,
0x7bc5,0x7bc8,0x7bca,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bda,0x7bdb,0x7be8,
0x7bea,0x7bf2,0x7bf4,0x7bf5,0x7bf8,0x7bf9,0x7bfa,0x7bfc,0x7bfe,0x7c01,
0x7c02,0x7c03,0x7c04,0x7c06,0x7c09,0x7c0b,0x7c0c,0x7c0e,0x7c0f,0x7c19,
0x7c1b,0x7c20,0x7c25,0x7c26,0x7c28,0x7c2c,0x7c31,0x7c33,0x7c34,0x7c36,
0x7c39,0x7c3a,0x7c46,0x7c4a,0x7c55,0x7c51,0x7c52,0x7c53,0x7c59,0x7c5a,
0x7c5b,0x7c5c,0x7c5d,0x7c5e
},
{ /* ku 33 */
0x7c61,0x7c63,0x7c67,0x7c69,0x7c6d,0x7c6e,0x7c70,0x7c72,0x7c79,0x7c7c,
0x7c7d,0x7c86,0x7c87,0x7c8f,0x7c94,0x7c9e,0x7ca0,0x7ca6,0x7cb0,0x7cb6,
0x7cb7,0x7cba,0x7cbb,0x7cbc,0x7cbf,0x7cc4,0x7cc7,0x7cc8,0x7cc9,0x7ccd,
0x7ccf,0x7cd3,0x7cd4,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdd,0x7ce6,0x7ce9,
0x7ceb,0x7cf5,0x7d03,0x7d07,0x7d08,0x7d09,0x7d0f,0x7d11,0x7d12,0x7d13,
0x7d16,0x7d1d,0x7d1e,0x7d23,0x7d26,0x7d2a,0x7d2d,0x7d31,0x7d3c,0x7d3d,
0x7d3e,0x7d40,0x7d41,0x7d47,0x7d48,0x7d4d,0x7d51,0x7d53,0x7d57,0x7d59,
0x7d5a,0x7d5c,0x7d5d,0x7d65,0x7d67,0x7d6a,0x7d70,0x7d78,0x7d7a,0x7d7b,
0x7d7f,0x7d81,0x7d82,0x7d83,0x7d85,0x7d86,0x7d88,0x7d8b,0x7d8c,0x7d8d,
0x7d91,0x7d96,0x7d97,0x7d9d
},
{ /* ku 34 */
0x7d9e,0x7da6,0x7da7,0x7daa,0x7db3,0x7db6,0x7db7,0x7db9,0x7dc2,0x7dc3,
0x7dc4,0x7dc5,0x7dc6,0x7dcc,0x7dcd,0x7dce,0x7dd7,0x7dd9,0x7e00,0x7de2,
0x7de5,0x7de6,0x7dea,0x7deb,0x7ded,0x7df1,0x7df5,0x7df6,0x7df9,0x7dfa,
0x7e08,0x7e10,0x7e11,0x7e15,0x7e17,0x7e1c,0x7e1d,0x7e20,0x7e27,0x7e28,
0x7e2c,0x7e2d,0x7e2f,0x7e33,0x7e36,0x7e3f,0x7e44,0x7e45,0x7e47,0x7e4e,
0x7e50,0x7e52,0x7e58,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e6b,0x7e6e,0x7e6f,
0x7e73,0x7e78,0x7e7e,0x7e81,0x7e86,0x7e87,0x7e8a,0x7e8d,0x7e91,0x7e95,
0x7e98,0x7e9a,0x7e9d,0x7e9e,0x7f3c,0x7f3b,0x7f3d,0x7f3e,0x7f3f,0x7f43,
0x7f44,0x7f47,0x7f4f,0x7f52,0x7f53,0x7f5b,0x7f5c,0x7f5d,0x7f61,0x7f63,
0x7f64,0x7f65,0x7f66,0x7f6d
},
{ /* ku 35 */
0x7f71,0x7f7d,0x7f7e,0x7f7f,0x7f80,0x7f8b,0x7f8d,0x7f8f,0x7f90,0x7f91,
0x7f96,0x7f97,0x7f9c,0x7fa1,0x7fa2,0x7fa6,0x7faa,0x7fad,0x7fb4,0x7fbc,
0x7fbf,0x7fc0,0x7fc3,0x7fc8,0x7fce,0x7fcf,0x7fdb,0x7fdf,0x7fe3,0x7fe5,
0x7fe8,0x7fec,0x7fee,0x7fef,0x7ff2,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8007,
0x8008,0x800a,0x800d,0x800e,0x800f,0x8011,0x8013,0x8014,0x8016,0x801d,
0x801e,0x801f,0x8020,0x8024,0x8026,0x802c,0x802e,0x8030,0x8034,0x8035,
0x8037,0x8039,0x803a,0x803c,0x803e,0x8040,0x8044,0x8060,0x8064,0x8066,
0x806d,0x8071,0x8075,0x8081,0x8088,0x808e,0x809c,0x809e,0x80a6,0x80a7,
0x80ab,0x80b8,0x80b9,0x80c8,0x80cd,0x80cf,0x80d2,0x80d4,0x80d5,0x80d7,
0x80d8,0x80e0,0x80ed,0x80ee
},
{ /* ku 36 */
0x80f0,0x80f2,0x80f3,0x80f6,0x80f9,0x80fa,0x80fe,0x8103,0x810b,0x8116,
0x8117,0x8118,0x811c,0x811e,0x8120,0x8124,0x8127,0x812c,0x8130,0x8135,
0x813a,0x813c,0x8145,0x8147,0x814a,0x814c,0x8152,0x8157,0x8160,0x8161,
0x8167,0x8168,0x8169,0x816d,0x816f,0x8177,0x8181,0x8190,0x8184,0x8185,
0x8186,0x818b,0x818e,0x8196,0x8198,0x819b,0x819e,0x81a2,0x81ae,0x81b2,
0x81b4,0x81bb,0x81cb,0x81c3,0x81c5,0x81ca,0x81ce,0x81cf,0x81d5,0x81d7,
0x81db,0x81dd,0x81de,0x81e1,0x81e4,0x81eb,0x81ec,0x81f0,0x81f1,0x81f2,
0x81f5,0x81f6,0x81f8,0x81f9,0x81fd,0x81ff,0x8200,0x8203,0x820f,0x8213,
0x8214,0x8219,0x821a,0x821d,0x8221,0x8222,0x8228,0x8232,0x8234,0x823a,
0x8243,0x8244,0x8245,0x8246
},
{ /* ku 37 */
0x824b,0x824e,0x824f,0x8251,0x8256,0x825c,0x8260,0x8263,0x8267,0x826d,
0x8274,0x827b,0x827d,0x827f,0x8280,0x8281,0x8283,0x8284,0x8287,0x8289,
0x828a,0x828e,0x8291,0x8294,0x8296,0x8298,0x829a,0x829b,0x82a0,0x82a1,
0x82a3,0x82a4,0x82a7,0x82a8,0x82a9,0x82aa,0x82ae,0x82b0,0x82b2,0x82b4,
0x82b7,0x82ba,0x82bc,0x82be,0x82bf,0x82c6,0x82d0,0x82d5,0x82da,0x82e0,
0x82e2,0x82e4,0x82e8,0x82ea,0x82ed,0x82ef,0x82f6,0x82f7,0x82fd,0x82fe,
0x8300,0x8301,0x8307,0x8308,0x830a,0x830b,0x8354,0x831b,0x831d,0x831e,
0x831f,0x8321,0x8322,0x832c,0x832d,0x832e,0x8330,0x8333,0x8337,0x833a,
0x833c,0x833d,0x8342,0x8343,0x8344,0x8347,0x834d,0x834e,0x8351,0x8355,
0x8356,0x8357,0x8370,0x8378
},
{ /* ku 38 */
0x837d,0x837f,0x8380,0x8382,0x8384,0x8386,0x838d,0x8392,0x8394,0x8395,
0x8398,0x8399,0x839b,0x839c,0x839d,0x83a6,0x83a7,0x83a9,0x83ac,0x83be,
0x83bf,0x83c0,0x83c7,0x83c9,0x83cf,0x83d0,0x83d1,0x83d4,0x83dd,0x8353,
0x83e8,0x83ea,0x83f6,0x83f8,0x83f9,0x83fc,0x8401,0x8406,0x840a,0x840f,
0x8411,0x8415,0x8419,0x83ad,0x842f,0x8439,0x8445,0x8447,0x8448,0x844a,
0x844d,0x844f,0x8451,0x8452,0x8456,0x8458,0x8459,0x845a,0x845c,0x8460,
0x8464,0x8465,0x8467,0x846a,0x8470,0x8473,0x8474,0x8476,0x8478,0x847c,
0x847d,0x8481,0x8485,0x8492,0x8493,0x8495,0x849e,0x84a6,0x84a8,0x84a9,
0x84aa,0x84af,0x84b1,0x84b4,0x84ba,0x84bd,0x84be,0x84c0,0x84c2,0x84c7,
0x84c8,0x84cc,0x84cf,0x84d3
},
{ /* ku 39 */
0x84dc,0x84e7,0x84ea,0x84ef,0x84f0,0x84f1,0x84f2,0x84f7,0x8532,0x84fa,
0x84fb,0x84fd,0x8502,0x8503,0x8507,0x850c,0x850e,0x8510,0x851c,0x851e,
0x8522,0x8523,0x8524,0x8525,0x8527,0x852a,0x852b,0x852f,0x8533,0x8534,
0x8536,0x853f,0x8546,0x854f,0x8550,0x8551,0x8552,0x8553,0x8556,0x8559,
0x855c,0x855d,0x855e,0x855f,0x8560,0x8561,0x8562,0x8564,0x856b,0x856f,
0x8579,0x857a,0x857b,0x857d,0x857f,0x8581,0x8585,0x8586,0x8589,0x858b,
0x858c,0x858f,0x8593,0x8598,0x859d,0x859f,0x85a0,0x85a2,0x85a5,0x85a7,
0x85b4,0x85b6,0x85b7,0x85b8,0x85bc,0x85bd,0x85be,0x85bf,0x85c2,0x85c7,
0x85ca,0x85cb,0x85ce,0x85ad,0x85d8,0x85da,0x85df,0x85e0,0x85e6,0x85e8,
0x85ed,0x85f3,0x85f6,0x85fc
},
{ /* ku 3a */
0x85ff,0x8600,0x8604,0x8605,0x860d,0x860e,0x8610,0x8611,0x8612,0x8618,
0x8619,0x861b,0x861e,0x8621,0x8627,0x8629,0x8636,0x8638,0x863a,0x863c,
0x863d,0x8640,0x8642,0x8646,0x8652,0x8653,0x8656,0x8657,0x8658,0x8659,
0x865d,0x8660,0x8661,0x8662,0x8663,0x8664,0x8669,0x866c,0x866f,0x8675,
0x8676,0x8677,0x867a,0x868d,0x8691,0x8696,0x8698,0x869a,0x869c,0x86a1,
0x86a6,0x86a7,0x86a8,0x86ad,0x86b1,0x86b3,0x86b4,0x86b5,0x86b7,0x86b8,
0x86b9,0x86bf,0x86c0,0x86c1,0x86c3,0x86c5,0x86d1,0x86d2,0x86d5,0x86d7,
0x86da,0x86dc,0x86e0,0x86e3,0x86e5,0x86e7,0x8688,0x86fa,0x86fc,0x86fd,
0x8704,0x8705,0x8707,0x870b,0x870e,0x870f,0x8710,0x8713,0x8714,0x8719,
0x871e,0x871f,0x8721,0x8723
},
{ /* ku 3b */
0x8728,0x872e,0x872f,0x8731,0x8732,0x8739,0x873a,0x873c,0x873d,0x873e,
0x8740,0x8743,0x8745,0x874d,0x8758,0x875d,0x8761,0x8764,0x8765,0x876f,
0x8771,0x8772,0x877b,0x8783,0x8784,0x8785,0x8786,0x8787,0x8788,0x8789,
0x878b,0x878c,0x8790,0x8793,0x8795,0x8797,0x8798,0x8799,0x879e,0x87a0,
0x87a3,0x87a7,0x87ac,0x87ad,0x87ae,0x87b1,0x87b5,0x87be,0x87bf,0x87c1,
0x87c8,0x87c9,0x87ca,0x87ce,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87df,
0x87e2,0x87e3,0x87e4,0x87ea,0x87eb,0x87ed,0x87f1,0x87f3,0x87f8,0x87fa,
0x87ff,0x8801,0x8803,0x8806,0x8809,0x880a,0x880b,0x8810,0x8819,0x8812,
0x8813,0x8814,0x8818,0x881a,0x881b,0x881c,0x881e,0x881f,0x8828,0x882d,
0x882e,0x8830,0x8832,0x8835
},
{ /* ku 3c */
0x883a,0x883c,0x8841,0x8843,0x8845,0x8848,0x8849,0x884a,0x884b,0x884e,
0x8851,0x8855,0x8856,0x8858,0x885a,0x885c,0x885f,0x8860,0x8864,0x8869,
0x8871,0x8879,0x887b,0x8880,0x8898,0x889a,0x889b,0x889c,0x889f,0x88a0,
0x88a8,0x88aa,0x88ba,0x88bd,0x88be,0x88c0,0x88ca,0x88cb,0x88cc,0x88cd,
0x88ce,0x88d1,0x88d2,0x88d3,0x88db,0x88de,0x88e7,0x88ef,0x88f0,0x88f1,
0x88f5,0x88f7,0x8901,0x8906,0x890d,0x890e,0x890f,0x8915,0x8916,0x8918,
0x8919,0x891a,0x891c,0x8920,0x8926,0x8927,0x8928,0x8930,0x8931,0x8932,
0x8935,0x8939,0x893a,0x893e,0x8940,0x8942,0x8945,0x8946,0x8949,0x894f,
0x8952,0x8957,0x895a,0x895b,0x895c,0x8961,0x8962,0x8963,0x896b,0x896e,
0x8970,0x8973,0x8975,0x897a
},
{ /* ku 3d */
0x897b,0x897c,0x897d,0x8989,0x898d,0x8990,0x8994,0x8995,0x899b,0x899c,
0x899f,0x89a0,0x89a5,0x89b0,0x89b4,0x89b5,0x89b6,0x89b7,0x89bc,0x89d4,
0x89d5,0x89d6,0x89d7,0x89d8,0x89e5,0x89e9,0x89eb,0x89ed,0x89f1,0x89f3,
0x89f6,0x89f9,0x89fd,0x89ff,0x8a04,0x8a05,0x8a07,0x8a0f,0x8a11,0x8a12,
0x8a14,0x8a15,0x8a1e,0x8a20,0x8a22,0x8a24,0x8a26,0x8a2b,0x8a2c,0x8a2f,
0x8a35,0x8a37,0x8a3d,0x8a3e,0x8a40,0x8a43,0x8a45,0x8a47,0x8a49,0x8a4d,
0x8a4e,0x8a53,0x8a56,0x8a57,0x8a58,0x8a5c,0x8a5d,0x8a61,0x8a65,0x8a67,
0x8a75,0x8a76,0x8a77,0x8a79,0x8a7a,0x8a7b,0x8a7e,0x8a7f,0x8a80,0x8a83,
0x8a86,0x8a8b,0x8a8f,0x8a90,0x8a92,0x8a96,0x8a97,0x8a99,0x8a9f,0x8aa7,
0x8aa9,0x8aae,0x8aaf,0x8ab3
},
{ /* ku 3e */
0x8ab6,0x8ab7,0x8abb,0x8abe,0x8ac3,0x8ac6,0x8ac8,0x8ac9,0x8aca,0x8ad1,
0x8ad3,0x8ad4,0x8ad5,0x8ad7,0x8add,0x8adf,0x8aec,0x8af0,0x8af4,0x8af5,
0x8af6,0x8afc,0x8aff,0x8b05,0x8b06,0x8b0b,0x8b11,0x8b1c,0x8b1e,0x8b1f,
0x8b0a,0x8b2d,0x8b30,0x8b37,0x8b3c,0x8b42,0x8b43,0x8b44,0x8b45,0x8b46,
0x8b48,0x8b52,0x8b53,0x8b54,0x8b59,0x8b4d,0x8b5e,0x8b63,0x8b6d,0x8b76,
0x8b78,0x8b79,0x8b7c,0x8b7e,0x8b81,0x8b84,0x8b85,0x8b8b,0x8b8d,0x8b8f,
0x8b94,0x8b95,0x8b9c,0x8b9e,0x8b9f,0x8c38,0x8c39,0x8c3d,0x8c3e,0x8c45,
0x8c47,0x8c49,0x8c4b,0x8c4f,0x8c51,0x8c53,0x8c54,0x8c57,0x8c58,0x8c5b,
0x8c5d,0x8c59,0x8c63,0x8c64,0x8c66,0x8c68,0x8c69,0x8c6d,0x8c73,0x8c75,
0x8c76,0x8c7b,0x8c7e,0x8c86
},
{ /* ku 3f */
0x8c87,0x8c8b,0x8c90,0x8c92,0x8c93,0x8c99,0x8c9b,0x8c9c,0x8ca4,0x8cb9,
0x8cba,0x8cc5,0x8cc6,0x8cc9,0x8ccb,0x8ccf,0x8cd6,0x8cd5,0x8cd9,0x8cdd,
0x8ce1,0x8ce8,0x8cec,0x8cef,0x8cf0,0x8cf2,0x8cf5,0x8cf7,0x8cf8,0x8cfe,
0x8cff,0x8d01,0x8d03,0x8d09,0x8d12,0x8d17,0x8d1b,0x8d65,0x8d69,0x8d6c,
0x8d6e,0x8d7f,0x8d82,0x8d84,0x8d88,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d9e,
0x8d9f,0x8da0,0x8da6,0x8dab,0x8dac,0x8daf,0x8db2,0x8db5,0x8db7,0x8db9,
0x8dbb,0x8dc0,0x8dc5,0x8dc6,0x8dc7,0x8dc8,0x8dca,0x8dce,0x8dd1,0x8dd4,
0x8dd5,0x8dd7,0x8dd9,0x8de4,0x8de5,0x8de7,0x8dec,0x8df0,0x8dbc,0x8df1,
0x8df2,0x8df4,0x8dfd,0x8e01,0x8e04,0x8e05,0x8e06,0x8e0b,0x8e11,0x8e14,
0x8e16,0x8e20,0x8e21,0x8e22
},
{ /* ku 40 */
0x8e23,0x8e26,0x8e27,0x8e31,0x8e33,0x8e36,0x8e37,0x8e38,0x8e39,0x8e3d,
0x8e40,0x8e41,0x8e4b,0x8e4d,0x8e4e,0x8e4f,0x8e54,0x8e5b,0x8e5c,0x8e5d,
0x8e5e,0x8e61,0x8e62,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e70,0x8e71,0x8e79,
0x8e7a,0x8e7b,0x8e82,0x8e83,0x8e89,0x8e90,0x8e92,0x8e95,0x8e9a,0x8e9b,
0x8e9d,0x8e9e,0x8ea2,0x8ea7,0x8ea9,0x8ead,0x8eae,0x8eb3,0x8eb5,0x8eba,
0x8ebb,0x8ec0,0x8ec1,0x8ec3,0x8ec4,0x8ec7,0x8ecf,0x8ed1,0x8ed4,0x8edc,
0x8ee8,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8ef9,0x8efa,0x8eed,0x8f00,0x8f02,
0x8f07,0x8f08,0x8f0f,0x8f10,0x8f16,0x8f17,0x8f18,0x8f1e,0x8f20,0x8f21,
0x8f23,0x8f25,0x8f27,0x8f28,0x8f2c,0x8f2d,0x8f2e,0x8f34,0x8f35,0x8f36,
0x8f37,0x8f3a,0x8f40,0x8f41
},
{ /* ku 41 */
0x8f43,0x8f47,0x8f4f,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f58,0x8f5d,
0x8f5e,0x8f65,0x8f9d,0x8fa0,0x8fa1,0x8fa4,0x8fa5,0x8fa6,0x8fb5,0x8fb6,
0x8fb8,0x8fbe,0x8fc0,0x8fc1,0x8fc6,0x8fca,0x8fcb,0x8fcd,0x8fd0,0x8fd2,
0x8fd3,0x8fd5,0x8fe0,0x8fe3,0x8fe4,0x8fe8,0x8fee,0x8ff1,0x8ff5,0x8ff6,
0x8ffb,0x8ffe,0x9002,0x9004,0x9008,0x900c,0x9018,0x901b,0x9028,0x9029,
0x902f,0x902a,0x902c,0x902d,0x9033,0x9034,0x9037,0x903f,0x9043,0x9044,
0x904c,0x905b,0x905d,0x9062,0x9066,0x9067,0x906c,0x9070,0x9074,0x9079,
0x9085,0x9088,0x908b,0x908c,0x908e,0x9090,0x9095,0x9097,0x9098,0x9099,
0x909b,0x90a0,0x90a1,0x90a2,0x90a5,0x90b0,0x90b2,0x90b3,0x90b4,0x90b6,
0x90bd,0x90cc,0x90be,0x90c3
},
{ /* ku 42 */
0x90c4,0x90c5,0x90c7,0x90c8,0x90d5,0x90d7,0x90d8,0x90d9,0x90dc,0x90dd,
0x90df,0x90e5,0x90d2,0x90f6,0x90eb,0x90ef,0x90f0,0x90f4,0x90fe,0x90ff,
0x9100,0x9104,0x9105,0x9106,0x9108,0x910d,0x9110,0x9114,0x9116,0x9117,
0x9118,0x911a,0x911c,0x911e,0x9120,0x9125,0x9122,0x9123,0x9127,0x9129,
0x912e,0x912f,0x9131,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d,
0x9143,0x9147,0x9148,0x914f,0x9153,0x9157,0x9159,0x915a,0x915b,0x9161,
0x9164,0x9167,0x916d,0x9174,0x9179,0x917a,0x917b,0x9181,0x9183,0x9185,
0x9186,0x918a,0x918e,0x9191,0x9193,0x9194,0x9195,0x9198,0x919e,0x91a1,
0x91a6,0x91a8,0x91ac,0x91ad,0x91ae,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6,
0x91bb,0x91bc,0x91bd,0x91bf
},
{ /* ku 43 */
0x91c2,0x91c3,0x91c5,0x91d3,0x91d4,0x91d7,0x91d9,0x91da,0x91de,0x91e4,
0x91e5,0x91e9,0x91ea,0x91ec,0x91ed,0x91ee,0x91ef,0x91f0,0x91f1,0x91f7,
0x91f9,0x91fb,0x91fd,0x9200,0x9201,0x9204,0x9205,0x9206,0x9207,0x9209,
0x920a,0x920c,0x9210,0x9212,0x9213,0x9216,0x9218,0x921c,0x921d,0x9223,
0x9224,0x9225,0x9226,0x9228,0x922e,0x922f,0x9230,0x9233,0x9235,0x9236,
0x9238,0x9239,0x923a,0x923c,0x923e,0x9240,0x9242,0x9243,0x9246,0x9247,
0x924a,0x924d,0x924e,0x924f,0x9251,0x9258,0x9259,0x925c,0x925d,0x9260,
0x9261,0x9265,0x9267,0x9268,0x9269,0x926e,0x926f,0x9270,0x9275,0x9276,
0x9277,0x9278,0x9279,0x927b,0x927c,0x927d,0x927f,0x9288,0x9289,0x928a,
0x928d,0x928e,0x9292,0x9297
},
{ /* ku 44 */
0x9299,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92af,0x92b2,
0x92b6,0x92b8,0x92ba,0x92bb,0x92bc,0x92bd,0x92bf,0x92c0,0x92c1,0x92c2,
0x92c3,0x92c5,0x92c6,0x92c7,0x92c8,0x92cb,0x92cc,0x92cd,0x92ce,0x92d0,
0x92d3,0x92d5,0x92d7,0x92d8,0x92d9,0x92dc,0x92dd,0x92df,0x92e0,0x92e1,
0x92e3,0x92e5,0x92e7,0x92e8,0x92ec,0x92ee,0x92f0,0x92f9,0x92fb,0x92ff,
0x9300,0x9302,0x9308,0x930d,0x9311,0x9314,0x9315,0x931c,0x931d,0x931e,
0x931f,0x9321,0x9324,0x9325,0x9327,0x9329,0x932a,0x9333,0x9334,0x9336,
0x9337,0x9347,0x9348,0x9349,0x9350,0x9351,0x9352,0x9355,0x9357,0x9358,
0x935a,0x935e,0x9364,0x9365,0x9367,0x9369,0x936a,0x936d,0x936f,0x9370,
0x9371,0x9373,0x9374,0x9376
},
{ /* ku 45 */
0x937a,0x937d,0x937f,0x9380,0x9381,0x9382,0x9388,0x938a,0x938b,0x938d,
0x938f,0x9392,0x9395,0x9398,0x939b,0x939e,0x93a1,0x93a3,0x93a4,0x93a6,
0x93a8,0x93ab,0x93b4,0x93b5,0x93b6,0x93ba,0x93a9,0x93c1,0x93c4,0x93c5,
0x93c6,0x93c7,0x93c9,0x93ca,0x93cb,0x93cc,0x93cd,0x93d3,0x93d9,0x93dc,
0x93de,0x93df,0x93e2,0x93e6,0x93e7,0x93f9,0x93f7,0x93f8,0x93fa,0x93fb,
0x93fd,0x9401,0x9402,0x9404,0x9408,0x9409,0x940d,0x940e,0x940f,0x9415,
0x9416,0x9417,0x941f,0x942e,0x942f,0x9431,0x9432,0x9433,0x9434,0x943b,
0x943f,0x943d,0x9443,0x9445,0x9448,0x944a,0x944c,0x9455,0x9459,0x945c,
0x945f,0x9461,0x9463,0x9468,0x946b,0x946d,0x946e,0x946f,0x9471,0x9472,
0x9484,0x9483,0x9578,0x9579
},
{ /* ku 46 */
0x957e,0x9584,0x9588,0x958c,0x958d,0x958e,0x959d,0x959e,0x959f,0x95a1,
0x95a6,0x95a9,0x95ab,0x95ac,0x95b4,0x95b6,0x95ba,0x95bd,0x95bf,0x95c6,
0x95c8,0x95c9,0x95cb,0x95d0,0x95d1,0x95d2,0x95d3,0x95d9,0x95da,0x95dd,
0x95de,0x95df,0x95e0,0x95e4,0x95e6,0x961d,0x961e,0x9622,0x9624,0x9625,
0x9626,0x962c,0x9631,0x9633,0x9637,0x9638,0x9639,0x963a,0x963c,0x963d,
0x9641,0x9652,0x9654,0x9656,0x9657,0x9658,0x9661,0x966e,0x9674,0x967b,
0x967c,0x967e,0x967f,0x9681,0x9682,0x9683,0x9684,0x9689,0x9691,0x9696,
0x969a,0x969d,0x969f,0x96a4,0x96a5,0x96a6,0x96a9,0x96ae,0x96af,0x96b3,
0x96ba,0x96ca,0x96d2,0x5db2,0x96d8,0x96da,0x96dd,0x96de,0x96df,0x96e9,
0x96ef,0x96f1,0x96fa,0x9702
},
{ /* ku 47 */
0x9703,0x9705,0x9709,0x971a,0x971b,0x971d,0x9721,0x9722,0x9723,0x9728,
0x9731,0x9733,0x9741,0x9743,0x974a,0x974e,0x974f,0x9755,0x9757,0x9758,
0x975a,0x975b,0x9763,0x9767,0x976a,0x976e,0x9773,0x9776,0x9777,0x9778,
0x977b,0x977d,0x977f,0x9780,0x9789,0x9795,0x9796,0x9797,0x9799,0x979a,
0x979e,0x979f,0x97a2,0x97ac,0x97ae,0x97b1,0x97b2,0x97b5,0x97b6,0x97b8,
0x97b9,0x97ba,0x97bc,0x97be,0x97bf,0x97c1,0x97c4,0x97c5,0x97c7,0x97c9,
0x97ca,0x97cc,0x97cd,0x97ce,0x97d0,0x97d1,0x97d4,0x97d7,0x97d8,0x97d9,
0x97dd,0x97de,0x97e0,0x97db,0x97e1,0x97e4,0x97ef,0x97f1,0x97f4,0x97f7,
0x97f8,0x97fa,0x9807,0x980a,0x9819,0x980d,0x980e,0x9814,0x9816,0x981c,
0x981e,0x9820,0x9823,0x9826
},
{ /* ku 48 */
0x982b,0x982e,0x982f,0x9830,0x9832,0x9833,0x9835,0x9825,0x983e,0x9844,
0x9847,0x984a,0x9851,0x9852,0x9853,0x9856,0x9857,0x9859,0x985a,0x9862,
0x9863,0x9865,0x9866,0x986a,0x986c,0x98ab,0x98ad,0x98ae,0x98b0,0x98b4,
0x98b7,0x98b8,0x98ba,0x98bb,0x98bf,0x98c2,0x98c5,0x98c8,0x98cc,0x98e1,
0x98e3,0x98e5,0x98e6,0x98e7,0x98ea,0x98f3,0x98f6,0x9902,0x9907,0x9908,
0x9911,0x9915,0x9916,0x9917,0x991a,0x991b,0x991c,0x991f,0x9922,0x9926,
0x9927,0x992b,0x9931,0x9932,0x9933,0x9934,0x9935,0x9939,0x993a,0x993b,
0x993c,0x9940,0x9941,0x9946,0x9947,0x9948,0x994d,0x994e,0x9954,0x9958,
0x9959,0x995b,0x995c,0x995e,0x995f,0x9960,0x999b,0x999d,0x999f,0x99a6,
0x99b0,0x99b1,0x99b2,0x99b5
},
{ /* ku 49 */
0x99b9,0x99ba,0x99bd,0x99bf,0x99c3,0x99c9,0x99d3,0x99d4,0x99d9,0x99da,
0x99dc,0x99de,0x99e7,0x99ea,0x99eb,0x99ec,0x99f0,0x99f4,0x99f5,0x99f9,
0x99fd,0x99fe,0x9a02,0x9a03,0x9a04,0x9a0b,0x9a0c,0x9a10,0x9a11,0x9a16,
0x9a1e,0x9a20,0x9a22,0x9a23,0x9a24,0x9a27,0x9a2d,0x9a2e,0x9a33,0x9a35,
0x9a36,0x9a38,0x9a47,0x9a41,0x9a44,0x9a4a,0x9a4b,0x9a4c,0x9a4e,0x9a51,
0x9a54,0x9a56,0x9a5d,0x9aaa,0x9aac,0x9aae,0x9aaf,0x9ab2,0x9ab4,0x9ab5,
0x9ab6,0x9ab9,0x9abb,0x9abe,0x9abf,0x9ac1,0x9ac3,0x9ac6,0x9ac8,0x9ace,
0x9ad0,0x9ad2,0x9ad5,0x9ad6,0x9ad7,0x9adb,0x9adc,0x9ae0,0x9ae4,0x9ae5,
0x9ae7,0x9ae9,0x9aec,0x9af2,0x9af3,0x9af5,0x9af9,0x9afa,0x9afd,0x9aff,
0x9b00,0x9b01,0x9b02,0x9b03
},
{ /* ku 4a */
0x9b04,0x9b05,0x9b08,0x9b09,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b12,
0x9b16,0x9b19,0x9b1b,0x9b1c,0x9b20,0x9b26,0x9b2b,0x9b2d,0x9b33,0x9b34,
0x9b35,0x9b37,0x9b39,0x9b3a,0x9b3d,0x9b48,0x9b4b,0x9b4c,0x9b55,0x9b56,
0x9b57,0x9b5b,0x9b5e,0x9b61,0x9b63,0x9b65,0x9b66,0x9b68,0x9b6a,0x9b6b,
0x9b6c,0x9b6d,0x9b6e,0x9b73,0x9b75,0x9b77,0x9b78,0x9b79,0x9b7f,0x9b80,
0x9b84,0x9b85,0x9b86,0x9b87,0x9b89,0x9b8a,0x9b8b,0x9b8d,0x9b8f,0x9b90,
0x9b94,0x9b9a,0x9b9d,0x9b9e,0x9ba6,0x9ba7,0x9ba9,0x9bac,0x9bb0,0x9bb1,
0x9bb2,0x9bb7,0x9bb8,0x9bbb,0x9bbc,0x9bbe,0x9bbf,0x9bc1,0x9bc7,0x9bc8,
0x9bce,0x9bd0,0x9bd7,0x9bd8,0x9bdd,0x9bdf,0x9be5,0x9be7,0x9bea,0x9beb,
0x9bef,0x9bf3,0x9bf7,0x9bf8
},
{ /* ku 4b */
0x9bf9,0x9bfa,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c0b,0x9c0f,0x9c11,0x9c16,
0x9c18,0x9c19,0x9c1a,0x9c1c,0x9c1e,0x9c22,0x9c23,0x9c26,0x9c27,0x9c28,
0x9c29,0x9c2a,0x9c31,0x9c35,0x9c36,0x9c37,0x9c3d,0x9c41,0x9c43,0x9c44,
0x9c45,0x9c49,0x9c4a,0x9c4e,0x9c4f,0x9c50,0x9c53,0x9c54,0x9c56,0x9c58,
0x9c5b,0x9c5d,0x9c5e,0x9c5f,0x9c63,0x9c69,0x9c6a,0x9c5c,0x9c6b,0x9c68,
0x9c6e,0x9c70,0x9c72,0x9c75,0x9c77,0x9c7b,0x9ce6,0x9cf2,0x9cf7,0x9cf9,
0x9d0b,0x9d02,0x9d11,0x9d17,0x9d18,0x9d1c,0x9d1d,0x9d1e,0x9d2f,0x9d30,
0x9d32,0x9d33,0x9d34,0x9d3a,0x9d3c,0x9d45,0x9d3d,0x9d42,0x9d43,0x9d47,
0x9d4a,0x9d53,0x9d54,0x9d5f,0x9d63,0x9d62,0x9d65,0x9d69,0x9d6a,0x9d6b,
0x9d70,0x9d76,0x9d77,0x9d7b
},
{ /* ku 4c */
0x9d7c,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d8a,0x9d8d,0x9d8e,0x9d92,0x9d93,
0x9d95,0x9d96,0x9d97,0x9d98,0x9da1,0x9daa,0x9dac,0x9dae,0x9db1,0x9db5,
0x9db9,0x9dbc,0x9dbf,0x9dc3,0x9dc7,0x9dc9,0x9dca,0x9dd4,0x9dd5,0x9dd6,
0x9dd7,0x9dda,0x9dde,0x9ddf,0x9de0,0x9de5,0x9de7,0x9de9,0x9deb,0x9dee,
0x9df0,0x9df3,0x9df4,0x9dfe,0x9e0a,0x9e02,0x9e07,0x9e0e,0x9e10,0x9e11,
0x9e12,0x9e15,0x9e16,0x9e19,0x9e1c,0x9e1d,0x9e7a,0x9e7b,0x9e7c,0x9e80,
0x9e82,0x9e83,0x9e84,0x9e85,0x9e87,0x9e8e,0x9e8f,0x9e96,0x9e98,0x9e9b,
0x9e9e,0x9ea4,0x9ea8,0x9eac,0x9eae,0x9eaf,0x9eb0,0x9eb3,0x9eb4,0x9eb5,
0x9ec6,0x9ec8,0x9ecb,0x9ed5,0x9edf,0x9ee4,0x9ee7,0x9eec,0x9eed,0x9eee,
0x9ef0,0x9ef1,0x9ef2,0x9ef5
},
{ /* ku 4d */
0x9ef8,0x9eff,0x9f02,0x9f03,0x9f09,0x9f0f,0x9f10,0x9f11,0x9f12,0x9f14,
0x9f16,0x9f17,0x9f19,0x9f1a,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f2a,0x9f2b,
0x9f2f,0x9f31,0x9f32,0x9f34,0x9f37,0x9f39,0x9f3a,0x9f3c,0x9f3d,0x9f3f,
0x9f41,0x9f43,0x9f44,0x9f45,0x9f46,0x9f47,0x9f53,0x9f55,0x9f56,0x9f57,
0x9f58,0x9f5a,0x9f5d,0x9f5e,0x9f68,0x9f69,0x9f6d,0x9f6e,0x9f6f,0x9f70,
0x9f71,0x9f73,0x9f75,0x9f7a,0x9f7d,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f94,
0x9f96,0x9f97,0x9f9e,0x9fa1,0x9fa2,0x9fa3,0x9fa5,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON
}
};

48
src/charset/koi8_r.c Normal file
View File

@@ -0,0 +1,48 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: KOI8-R conversion table
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 3 July 1997
* Last Edited: 30 August 2006
*/
/* KOI8-R is a de-facto standard of Russia */
static const unsigned short koi8rtab[128] = {
0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556,
0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,
0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565,
0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9,
0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
};

48
src/charset/koi8_u.c Normal file
View File

@@ -0,0 +1,48 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: KOI8-U conversion table
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 25 August 1997
* Last Edited: 30 August 2006
*/
/* KOI8-U is a de-facto standard of Ukraine */
static const unsigned short koi8utab[128] = {
0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
0x2550,0x2551,0x2552,0x0451,0x0454,0x2554,0x0456,0x0457,
0x2557,0x2558,0x2559,0x255a,0x255b,0x0491,0x255d,0x255e,
0x255f,0x2560,0x2561,0x0401,0x0403,0x2563,0x0406,0x0407,
0x2566,0x2567,0x2568,0x2569,0x256a,0x0490,0x256c,0x00a9,
0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
};

2673
src/charset/ksc_5601.c Normal file

File diff suppressed because it is too large Load Diff

51
src/charset/tis_620.c Normal file
View File

@@ -0,0 +1,51 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: TIS 620-2529 conversion table
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 24 October 1997
* Last Edited: 30 August 2006
*/
/* TIS 620-2529 is the "Thai Industrial Standard for Thai Character Code
* for Computer", published by the Thai Industrial Standards Institute,
* Ministry of Industry of Thailand.
*/
static const unsigned short tis620tab[128] = {
0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
UBOGON,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
};

1487
src/charset/tmap.c Normal file

File diff suppressed because it is too large Load Diff

67
src/charset/viscii.c Normal file
View File

@@ -0,0 +1,67 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: VISCII conversion table
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 2 June 1998
* Last Edited: 30 August 2006
*/
/* VISCII is the VIetnamese Standard Code for Information Interchange,
* defined by the Vietnamese Standardization Working Group, RFC-1456,
* May 1993.
*/
static const unsigned short visciitab[256] = {
0x0000,0x0001,0x1eb2,0x0003,0x0004,0x1eb4,0x1eaa,0x0007,
0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
0x0010,0x0011,0x0012,0x0013,0x1ef6,0x0015,0x0016,0x0017,
0x0018,0x1ef8,0x001a,0x001b,0x001c,0x001d,0x1ef4,0x001f,
0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,
0x1ea0,0x1eae,0x1eb0,0x1eb6,0x1ea4,0x1ea6,0x1ea8,0x1eac,
0x1ebc,0x1eb8,0x1ebe,0x1ec0,0x1ec2,0x1ec4,0x1ec6,0x1ed0,
0x1ed2,0x1ed4,0x1ed6,0x1ed8,0x1ee2,0x1eda,0x1edc,0x1ede,
0x1eca,0x1ece,0x1ecc,0x1ec8,0x1ee6,0x0168,0x1ee4,0x1ef2,
0x00d5,0x1eaf,0x1eb1,0x1eb7,0x1ea5,0x1ea7,0x1ea9,0x1ead,
0x1ebd,0x1eb9,0x1ebf,0x1ec1,0x1ec3,0x1ec5,0x1ec7,0x1ed1,
0x1ed3,0x1ed5,0x1ed7,0x1ee0,0x01a0,0x1ed9,0x1edd,0x1edf,
0x1ecb,0x1ef0,0x1ee8,0x1eea,0x1eec,0x01a1,0x1edb,0x01af,
0x00c0,0x00c1,0x00c2,0x00c3,0x1ea2,0x0102,0x1eb3,0x1eb5,
0x00c8,0x00c9,0x00ca,0x1eba,0x00cc,0x00cd,0x0128,0x1ef3,
0x0110,0x1ee9,0x00d2,0x00d3,0x00d4,0x1ea1,0x1ef7,0x1eeb,
0x1eed,0x00d9,0x00da,0x1ef9,0x1ef5,0x00dd,0x1ee1,0x01b0,
0x00e0,0x00e1,0x00e2,0x00e3,0x1ea3,0x0103,0x1eef,0x1eab,
0x00e8,0x00e9,0x00ea,0x1ebb,0x00ec,0x00ed,0x0129,0x1ec9,
0x0111,0x1ef1,0x00f2,0x00f3,0x00f4,0x00f5,0x1ecf,0x1ecd,
0x1ee5,0x00f9,0x00fa,0x0169,0x1ee7,0x00fd,0x1ee3,0x1eee
};

4136
src/charset/widths.c Normal file

File diff suppressed because it is too large Load Diff

228
src/charset/windows.c Normal file
View File

@@ -0,0 +1,228 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Windows conversion tables
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 16 October 2000
* Last Edited: 30 August 2006
*/
/* Windows Thai */
static const unsigned short windows_874tab[128] = {
0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
};
/* Windows Latin-2 */
static const unsigned short windows_1250tab[128] = {
0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021,
UBOGON,0x2030,0x0160,0x2039,0x015a,0x0164,0x017d,0x0179,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
UBOGON,0x2122,0x0161,0x203a,0x015b,0x0165,0x017e,0x017a,
0x00a0,0x02c7,0x02d8,0x0141,0x00a4,0x0104,0x00a6,0x00a7,
0x00a8,0x00a9,0x015e,0x00ab,0x00ac,0x00ad,0x00ae,0x017b,
0x00b0,0x00b1,0x02db,0x0142,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x0105,0x015f,0x00bb,0x013d,0x02dd,0x013e,0x017c,
0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7,
0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e,
0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7,
0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df,
0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7,
0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f,
0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7,
0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9
};
/* Windows Cyrillic */
static const unsigned short windows_1251tab[128] = {
0x0402,0x0403,0x201a,0x0453,0x201e,0x2026,0x2020,0x2021,
0x20ac,0x2030,0x0409,0x2039,0x040a,0x040c,0x040b,0x040f,
0x0452,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
UBOGON,0x2122,0x0459,0x203a,0x045a,0x045c,0x045b,0x045f,
0x00a0,0x040e,0x045e,0x0408,0x00a4,0x0490,0x00a6,0x00a7,
0x0401,0x00a9,0x0404,0x00ab,0x00ac,0x00ad,0x00ae,0x0407,
0x00b0,0x00b1,0x0406,0x0456,0x0491,0x00b5,0x00b6,0x00b7,
0x0451,0x2116,0x0454,0x00bb,0x0458,0x0405,0x0455,0x0457,
0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f
};
/* Windows Latin-1 */
static const unsigned short windows_1252tab[128] = {
0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,0x017d,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,0x017e,0x0178,
0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff
};
/* Windows Greek */
static const unsigned short windows_1253tab[128] = {
0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
UBOGON,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
UBOGON,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON,
0x00a0,0x0385,0x0386,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,0x00ae,0x2015,
0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x00b5,0x00b6,0x00b7,
0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f,
0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON
};
/* Windows Turkish */
static const unsigned short windows_1254tab[128] = {
0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,UBOGON,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,UBOGON,0x0178,
0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df,
0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff
};
/* Windows Hebrew */
static const unsigned short windows_1255tab[128] = {
0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
0x02c6,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
0x02dc,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON,
0x00a0,0x00a1,0x00a2,0x00a3,0x20aa,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
0x05b8,0x05b9,UBOGON,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
0x05c0,0x05c1,0x05c2,0x05c3,0x05f0,0x05f1,0x05f2,0x05f3,
0x05f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON
};
/* Windows Arabic */
static const unsigned short windows_1256tab[128] = {
0x20ac,0x067e,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
0x02c6,0x2030,0x0679,0x2039,0x0152,0x0686,0x0698,0x0688,
0x06af,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
0x06a9,0x2122,0x0691,0x203a,0x0153,0x200c,0x200d,0x06ba,
0x00a0,0x060c,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x06be,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x061b,0x00bb,0x00bc,0x00bd,0x00be,0x061f,
0x06c1,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x00d7,
0x0637,0x0638,0x0639,0x063a,0x0640,0x0641,0x0642,0x0643,
0x00e0,0x0644,0x00e2,0x0645,0x0646,0x0647,0x0648,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x0649,0x064a,0x00ee,0x00ef,
0x064b,0x064c,0x064d,0x064e,0x00f4,0x064f,0x0650,0x00f7,
0x0651,0x00f9,0x0652,0x00fb,0x00fc,0x200e,0x200f,0x06d2
};
/* Windows Baltic */
static const unsigned short windows_1257tab[128] = {
0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021,
UBOGON,0x2030,UBOGON,0x2039,UBOGON,0x00a8,0x02c7,0x00b8,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
UBOGON,0x2122,UBOGON,0x203a,UBOGON,0x00af,0x02db,UBOGON,
0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,UBOGON,0x00a6,0x00a7,
0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6,
0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112,
0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b,
0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7,
0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df,
0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113,
0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c,
0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7,
0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x02d9
};
/* Windows Vietnamese */
static const unsigned short windows_1258tab[128] = {
0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
0x02c6,0x2030,UBOGON,0x2039,0x0152,UBOGON,UBOGON,UBOGON,
UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
0x02dc,0x2122,UBOGON,0x203a,0x0153,UBOGON,UBOGON,0x0178,
0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x00c5,0x00c6,0x00c7,
0x00c8,0x00c9,0x00ca,0x00cb,0x0300,0x00cd,0x00ce,0x00cf,
0x0110,0x00d1,0x0309,0x00d3,0x00d4,0x01a0,0x00d6,0x00d7,
0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x01af,0x0303,0x00df,
0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x00e5,0x00e6,0x00e7,
0x00e8,0x00e9,0x00ea,0x00eb,0x0301,0x00ed,0x00ee,0x00ef,
0x0111,0x00f1,0x0323,0x00f3,0x00f4,0x01a1,0x00f6,0x00f7,
0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x01b0,0x20ab,0x00ff
};

53
src/dmail/Makefile Normal file
View File

@@ -0,0 +1,53 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: dmail Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 5 April 1993
# Last Edited: 10 September 2007
C = ../c-client
CCLIENTLIB = $C/c-client.a
SHELL = /bin/sh
# Get local definitions from c-client directory
CC = `cat $C/CCTYPE`
CFLAGS = -I$C `cat $C/CFLAGS`
LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
dmail: $(CCLIENTLIB) dmail.o dquota.o
$(CC) $(CFLAGS) -o dmail dmail.o dquota.o $(LDFLAGS)
dmail.o: $C/mail.h $C/misc.h $C/osdep.h dquota.h
dquota.o: dquota.h
$(CCLIENTLIB):
cd $C;make
clean:
rm -f *.o dmail
# A monument to a hack of long ago and far away...
love:
@echo 'not war?'

121
src/dmail/dmail.1 Normal file
View File

@@ -0,0 +1,121 @@
.ig
* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
..
.TH DMAIL 1 "June 18, 2007"
.SH NAME
dmail \- procmail Mail Delivery Module
.nh
.SH SYNOPSIS
.B dmail
.I [\-D] [\-f from_name] [-s] [-k keyword_list] [user][+folder]
.SH DESCRIPTION
.I dmail
delivers mail to a user's INBOX or a designated folder.
.I dmail
may be configured as a drop-in replacement for
.IR binmail (1),
.IR mail.local (1)
for use with a mail delivery filter such as
.IR procmail (1) .
.PP
Because of security considerations (see below)
.I dmail
is not intended to be used for direct delivery by the mailer daemon;
.IR tmail (1)
is the preferred tool for this purpose. If
.I dmail
is used for mailer daemon delivery, the mailer daemon must invoke
.I dmail
with the
.I dmail
process' user id set to the recipient's user id.
.PP
When
.I dmail
exits, it returns exit status values to enable
.IR procmail (1)
to determine whether a message was delivered successfully or had a
temporary (requeue for later delivery) or permanent (return to sender)
failure.
.PP
If the
.I user
name is present, it must be the same as the logged-in user name.
.PP
If the
.I +folder
extension is included in the user argument (or appears by itself if there
is no user argument),
.I dmail
will attempt to deliver to the designated folder. If the folder does not
exist or the extension is not included, the message is delivered to the
user's INBOX.
If delivery is to INBOX and no INBOX currently exists,
.I dmail
will create a new INBOX.
.I dmail
recognizes the format of an existing INBOX or folder, and appends the new
message in that format.
.PP
The \fB-D\fR flag specifies debugging; this enables additional message
telemetry.
.PP
The \fB-f\fR or \fB-r\fR flag is used to specify a Return-Path. The header
.br
Return-Path: <\fIfrom_name\fR>
.br
is prepended to the message before delivery.
.PP
The
.B -s
flag specifies that the message will be flagged as being "seen".
.PP
The \fB-k\fR flag is used to specify delivery keywords, which are set on
the message at delivery time if and
.B only
if the keywords are already defined in the mailbox. Multiple keywords can be
specified by using a quoted string, e.g.,
.br
dmail -k "$Junk Discard" +junkbox
.br
.SH RESTRICTIONS
Absolute pathnames and
.I ~user
specifications are not permitted in
.I +folder
extensions.
.SH SECURITY CONSIDERATIONS
Unlike
.I tmail
you can use
.I dmail
to deliver to IMAP4 namespace names via
.I +folder
extensions. This means that it is possible to deliver to
.IR mh (1)
format mailboxes.
.PP
However, this can also include such namespaces as #shared, #public,
and #ftp. In most cases, it is undesirable to allow anybody sending
mail to the user to deliver to these namespaces. Consequently, there
needs to be a rule in place in the configuration of either
.IR sendmail (8)
or
.IR procmail (1)
to prevent such abuse.
.SH AUTHOR
Mark Crispin, MRC@CAC.Washington.EDU
.SH "SEE ALSO"
binmail(1)
.br
procmail(1)

661
src/dmail/dmail.c Normal file
View File

@@ -0,0 +1,661 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Procmail-Callable Mail Delivery Module
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 5 April 1993
* Last Edited: 30 October 2008
*/
#include <stdio.h>
#include <pwd.h>
#include <errno.h>
extern int errno; /* just in case */
#include <sysexits.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "c-client.h"
#include "dquota.h"
/* Globals */
char *version = "18"; /* dmail edit version */
int debug = NIL; /* debugging (don't fork) */
int flagseen = NIL; /* flag message as seen */
int trycreate = NIL; /* flag saying gotta create before appending */
int critical = NIL; /* flag saying in critical code */
char *sender = NIL; /* message origin */
char *keywords = NIL; /* keyword list */
long precedence = 0; /* delivery precedence - used by quota hook */
/* Function prototypes */
void file_string_init (STRING *s,void *data,unsigned long size);
char file_string_next (STRING *s);
void file_string_setpos (STRING *s,unsigned long i);
int main (int argc,char *argv[]);
int deliver (FILE *f,unsigned long msglen,char *user);
long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
char *tmp);
int delivery_unsafe (char *path,struct stat *sbuf,char *tmp);
int fail (char *string,int code);
/* File string driver for file stringstructs */
STRINGDRIVER file_string = {
file_string_init, /* initialize string structure */
file_string_next, /* get next byte in string structure */
file_string_setpos /* set position in string structure */
};
/* Cache buffer for file stringstructs */
#define CHUNKLEN 16384
char chunk[CHUNKLEN];
/* Initialize file string structure for file stringstruct
* Accepts: string structure
* pointer to string
* size of string
*/
void file_string_init (STRING *s,void *data,unsigned long size)
{
s->data = data; /* note fd */
s->size = size; /* note size */
s->chunk = chunk;
s->chunksize = (unsigned long) CHUNKLEN;
SETPOS (s,0); /* set initial position */
}
/* Get next character from file stringstruct
* Accepts: string structure
* Returns: character, string structure chunk refreshed
*/
char file_string_next (STRING *s)
{
char c = *s->curpos++; /* get next byte */
SETPOS (s,GETPOS (s)); /* move to next chunk */
return c; /* return the byte */
}
/* Set string pointer position for file stringstruct
* Accepts: string structure
* new position
*/
void file_string_setpos (STRING *s,unsigned long i)
{
if (i > s->size) i = s->size; /* don't permit setting beyond EOF */
s->offset = i; /* set new offset */
s->curpos = s->chunk; /* reset position */
/* set size of data */
if (s->cursize = min (s->chunksize,SIZE (s))) {
/* move to that position in the file */
fseek ((FILE *) s->data,s->offset,SEEK_SET);
fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
}
}
/* Main program */
int main (int argc,char *argv[])
{
FILE *f = NIL;
int c,ret = 0;
unsigned long msglen;
char *s,tmp[MAILTMPLEN];
uid_t ruid = getuid ();
struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL;
openlog ("dmail",LOG_PID,LOG_MAIL);
/* must not be root or daemon! */
if (!ruid || (pwd && (pwd->pw_uid == ruid)))
_exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE));
#include "linkage.c"
/* process all flags */
for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) {
case 'D': /* debug */
debug = T; /* extra debugging */
break;
case 's': /* deliver as seen */
flagseen = T;
break;
case 'f':
case 'r': /* flag giving return path */
if (sender) _exit (fail ("duplicate -r",EX_USAGE));
if (argc--) sender = cpystr (*++argv);
else _exit (fail ("missing argument to -r",EX_USAGE));
break;
case 'k':
if (keywords) _exit (fail ("duplicate -k",EX_USAGE));
if (argc--) keywords = cpystr (*++argv);
else _exit (fail ("missing argument to -k",EX_USAGE));
break;
case 'p':
if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
precedence = atol (s);
else _exit (fail ("missing argument to -p",EX_USAGE));
break;
default: /* anything else */
_exit (fail ("unknown switch",EX_USAGE));
}
if (argc > 1) _exit (fail ("too many recipients",EX_USAGE));
else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL));
/* build delivery headers */
if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
/* start Received line: */
fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version,
(argc == 1) ? *argv : myusername ());
rfc822_date (tmp);
fputs (tmp,f);
fputs ("\015\012",f);
/* copy text from standard input */
if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
(s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
else if (s[-1] == '\015') { /* nuke leading "From " line */
if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
(tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
while ((c = getchar ()) != EOF) putc (c,f);
}
else {
if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
(tmp[3] != 'm') || (tmp[4] != ' ')) {
*s++ = '\015'; /* overwrite NL with CRLF */
*s++ = '\012';
*s = '\0'; /* tie off string */
fputs (tmp,f); /* write line */
}
}
/* copy text from standard input */
while ((c = getchar ()) != EOF) {
/* add CR if needed */
if (c == '\012') putc ('\015',f);
putc (c,f);
}
msglen = ftell (f); /* size of message */
fflush (f); /* make sure all changes written out */
if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
/* single delivery */
else ret = deliver (f,msglen,argc ? *argv : myusername ());
fclose (f); /* all done with temporary file */
_exit (ret); /* normal exit */
return 0; /* stupid gcc */
}
/* Deliver message to recipient list
* Accepts: file description of message temporary file
* size of message temporary file in bytes
* recipient name
* Returns: NIL if success, else error code
*/
int deliver (FILE *f,unsigned long msglen,char *user)
{
MAILSTREAM *ds = NIL;
char *s,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
STRING st;
struct stat sbuf;
/* have a mailbox specifier? */
if (mailbox = strchr (user,'+')) {
*mailbox++ = '\0'; /* yes, tie off user name */
if (!*mailbox || !compare_cstring ((unsigned char *) mailbox,"INBOX"))
mailbox = NIL; /* user+ and user+INBOX same as user */
}
if (!*user) user = myusername ();
else if (strcmp (user,myusername ()))
return fail ("can't deliver to other user",EX_CANTCREAT);
sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
mm_dlog (tmp);
/* prepare stringstruct */
INIT (&st,file_string,(void *) f,msglen);
if (mailbox) { /* non-INBOX name */
switch (mailbox[0]) { /* make sure a valid name */
default: /* other names, try to deliver if not INBOX */
if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
!strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
!deliver_safely (NIL,&st,mailbox,path,tmp)) return NIL;
case '%': case '*': /* wildcards not valid */
case '/': /* absolute path names not valid */
case '~': /* user names not valid */
sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
mm_log (tmp,WARN);
break;
}
mm_dlog ("retrying delivery to INBOX");
SETPOS (&st,0); /* rewind stringstruct just in case */
}
/* no -I, resolve "INBOX" into path */
if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
/* clear box, get generic INBOX prototype */
if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
fatal ("no INBOX prototype");
/* standard system driver? */
if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
strcpy (path,sysinbox ());/* use system INBOX */
if (!lstat (path,&sbuf)) /* deliver to existing system INBOX */
return deliver_safely (ds,&st,mailbox,path,tmp);
}
else { /* other driver, try ~/INBOX */
if ((mailboxfile (path,"&&&&&") == path) &&
(s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
!lstat (path,&sbuf)){ /* deliver to existing ~/INBOX */
sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
return deliver_safely (ds,&st,cpystr (tmp),path,tmp);
}
}
/* not dummy, deliver to driver imputed path */
if (strcmp (ds->dtb->name,"dummy"))
return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
deliver_safely (ds,&st,mailbox,path,tmp) :
fail ("unable to resolve INBOX path",EX_CANTCREAT);
/* dummy, empty imputed append path exist? */
if (ibxpath (ds = default_proto (T),&mailbox,path) &&
!lstat (path,&sbuf) && !sbuf.st_size)
return deliver_safely (ds,&st,mailbox,path,tmp);
/* impute path that we will create */
if (!ibxpath (ds = default_proto (NIL),&mailbox,path))
return fail ("unable to resolve INBOX",EX_CANTCREAT);
}
/* black box, must create, get create proto */
else if (lstat (path,&sbuf)) ds = default_proto (NIL);
else { /* black box, existing file */
/* empty file, get append prototype */
if (!sbuf.st_size) ds = default_proto (T);
/* non-empty, get prototype from its data */
else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
fatal ("no INBOX prototype");
/* error if unknown format */
if (!strcmp (ds->dtb->name,"phile"))
return fail ("unknown format INBOX",EX_UNAVAILABLE);
/* otherwise can deliver to it */
return deliver_safely (ds,&st,mailbox,path,tmp);
}
sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
mm_dlog (tmp);
/* supplicate to the Evil One */
if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
sprintf (tmp,"created %.80s",path);
mm_dlog (tmp);
/* deliver the message */
return deliver_safely (ds,&st,mailbox,path,tmp);
}
/* Resolve INBOX from driver prototype into mailbox name and filesystem path
* Accepts: driver prototype
* pointer to mailbox name string pointer
* buffer to return mailbox path
* Returns: T if success, NIL if error
*/
long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
{
char *s,tmp[MAILTMPLEN];
long ret = T;
if (!ds) return NIL;
else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
strcpy (path,sysinbox ()); /* use system INBOX for unix and MMDF */
else if (!strcmp (ds->dtb->name,"tenex"))
ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
else if (!strcmp (ds->dtb->name,"mtx"))
ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
else if (!strcmp (ds->dtb->name,"mbox"))
ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
/* better not be a namespace driver */
else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
/* INBOX in home directory */
else ret = ((mailboxfile (path,"&&&&&") == path) &&
(s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
if (ret) { /* don't bother if lossage */
sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
*mailbox = cpystr (tmp); /* name of INBOX in this namespace */
}
return ret;
}
/* Deliver safely
* Accepts: prototype stream to force mailbox format
* stringstruct of message temporary file or NIL for check only
* mailbox name
* filesystem path name
* scratch buffer for messages
* Returns: NIL if success, else error code
*/
int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
char *tmp)
{
struct stat sbuf;
char *flags = NIL;
int i = delivery_unsafe (path,&sbuf,tmp);
if (i) return i; /* give up now if delivery unsafe */
/* directory, not file */
if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
if (sbuf.st_mode & 0001) { /* listable directories may be worrisome */
sprintf (tmp,"WARNING: directory %.80s is listable",path);
mm_log (tmp,WARN);
}
}
else { /* file, not directory */
if (sbuf.st_nlink != 1) { /* multiple links may be worrisome */
sprintf (tmp,"WARNING: multiple links to file %.80s",path);
mm_log (tmp,WARN);
}
if (sbuf.st_mode & 0111) { /* executable files may be worrisome */
sprintf (tmp,"WARNING: file %.80s is executable",path);
mm_log (tmp,WARN);
}
}
if (sbuf.st_mode & 0002) { /* public-write files may be worrisome */
sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
mm_log (tmp,WARN);
}
if (sbuf.st_mode & 0004) { /* public-write files may be worrisome */
sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
mm_log (tmp,WARN);
}
/* check site-written quota procedure */
if (!dmail_quota (st,path,tmp,sender,precedence))
return fail (tmp,EX_CANTCREAT);
/* so far, so good */
sprintf (tmp,"%s appending to %.80s (%s %.80s)",
prt ? prt->dtb->name : "default",mailbox,
((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
mm_dlog (tmp);
if (keywords) { /* any keywords requested? */
if (flagseen) sprintf (flags = tmp,"\\Seen %.1000s",keywords);
else flags = keywords;
}
else if (flagseen) flags = "\\Seen";
/* do the append now! */
if (!mail_append_full (prt,mailbox,flags,NIL,st)) {
sprintf (tmp,"message delivery failed to %.80s",path);
return fail (tmp,EX_CANTCREAT);
}
/* note success */
sprintf (tmp,"delivered to %.80s",path);
mm_log (tmp,NIL);
/* make sure nothing evil this way comes */
return delivery_unsafe (path,&sbuf,tmp);
}
/* Verify that delivery is safe
* Accepts: path name
* stat buffer
* scratch buffer for messages
* Returns: NIL if delivery is safe, error code if unsafe
*/
int delivery_unsafe (char *path,struct stat *sbuf,char *tmp)
{
u_short type;
sprintf (tmp,"Verifying safe delivery to %.80s",path);
mm_dlog (tmp);
/* prepare message just in case */
sprintf (tmp,"delivery to %.80s unsafe: ",path);
/* unsafe if can't get its status */
if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
/* check file type */
else switch (sbuf->st_mode & S_IFMT) {
case S_IFDIR: /* directory is always OK */
return NIL;
case S_IFREG: /* file is unsafe if setuid */
if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
/* or setgid */
else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
else return NIL; /* otherwise safe */
break;
case S_IFCHR: strcat (tmp,"character special"); break;
case S_IFBLK: strcat (tmp,"block special"); break;
case S_IFLNK: strcat (tmp,"symbolic link"); break;
case S_IFSOCK: strcat (tmp,"socket"); break;
default:
sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
}
return fail (tmp,EX_CANTCREAT);
}
/* Report an error
* Accepts: string to output
*/
int fail (char *string,int code)
{
mm_log (string,ERROR); /* pass up the string */
switch (code) {
#if T
case EX_USAGE:
case EX_OSERR:
case EX_SOFTWARE:
case EX_NOUSER:
case EX_CANTCREAT:
code = EX_TEMPFAIL; /* coerce these to TEMPFAIL */
break;
#endif
case -1: /* quota failure... */
code = EX_CANTCREAT; /* ...really returns this code */
break;
default:
break;
}
return code; /* error code to return */
}
/* Co-routines from MAIL library */
/* Message matches a search
* Accepts: MAIL stream
* message number
*/
void mm_searched (MAILSTREAM *stream,unsigned long msgno)
{
fatal ("mm_searched() call");
}
/* Message exists (i.e. there are that many messages in the mailbox)
* Accepts: MAIL stream
* message number
*/
void mm_exists (MAILSTREAM *stream,unsigned long number)
{
fatal ("mm_exists() call");
}
/* Message expunged
* Accepts: MAIL stream
* message number
*/
void mm_expunged (MAILSTREAM *stream,unsigned long number)
{
fatal ("mm_expunged() call");
}
/* Message flags update seen
* Accepts: MAIL stream
* message number
*/
void mm_flags (MAILSTREAM *stream,unsigned long number)
{
}
/* Mailbox found
* Accepts: MAIL stream
* delimiter
* mailbox name
* mailbox attributes
*/
void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
fatal ("mm_list() call");
}
/* Subscribed mailbox found
* Accepts: MAIL stream
* delimiter
* mailbox name
* mailbox attributes
*/
void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
fatal ("mm_lsub() call");
}
/* Mailbox status
* Accepts: MAIL stream
* mailbox name
* mailbox status
*/
void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
{
fatal ("mm_status() call");
}
/* Notification event
* Accepts: MAIL stream
* string to log
* error flag
*/
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
char tmp[MAILTMPLEN];
tmp[11] = '\0'; /* see if TRYCREATE */
if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
mm_log (string,errflg); /* just do mm_log action */
}
/* Log an event for the user to see
* Accepts: string to log
* error flag
*/
void mm_log (char *string,long errflg)
{
if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
else { /* ordinary logging */
fprintf (stderr,"%s\n",string);
switch (errflg) {
case NIL: /* no error */
syslog (LOG_INFO,"%s",string);
break;
case PARSE: /* parsing problem */
case WARN: /* warning */
syslog (LOG_WARNING,"%s",string);
break;
case ERROR: /* error */
default:
syslog (LOG_ERR,"%s",string);
break;
}
}
}
/* Log an event to debugging telemetry
* Accepts: string to log
*/
void mm_dlog (char *string)
{
if (debug) fprintf (stderr,"%s\n",string);
syslog (LOG_DEBUG,"%s",string);
}
/* Get user name and password for this host
* Accepts: parse of network mailbox name
* where to return user name
* where to return password
* trial count
*/
void mm_login (NETMBX *mb,char *username,char *password,long trial)
{
fatal ("mm_login() call");
}
/* About to enter critical code
* Accepts: stream
*/
void mm_critical (MAILSTREAM *stream)
{
critical = T; /* note in critical code */
}
/* About to exit critical code
* Accepts: stream
*/
void mm_nocritical (MAILSTREAM *stream)
{
critical = NIL; /* note not in critical code */
}
/* Disk error found
* Accepts: stream
* system error code
* flag indicating that mailbox may be clobbered
* Returns: T if user wants to abort
*/
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
{
return T;
}
/* Log a fatal error event
* Accepts: string to log
*/
void mm_fatal (char *string)
{
printf ("?%s\n",string); /* shouldn't happen normally */
}

44
src/dmail/dquota.c Normal file
View File

@@ -0,0 +1,44 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Procmail-Callable Mail Delivery Module Quota Hook
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 10 September 2007
* Last Edited: 10 September 2007
*/
#include "c-client.h"
/* Site-written routine to validate delivery per quota and policy
* Accepts: stringstruct of message temporary file
* filesystem path
* return path
* buffer to write error message
* precedence setting
* Returns: T if can deliver, or NIL if quota issue and must bounce
*/
long dmail_quota (STRING *msg,char *path,char *tmp,char *sender,
long precedence)
{
return LONGT; /* dummy success return */
}

32
src/dmail/dquota.h Normal file
View File

@@ -0,0 +1,32 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Procmail-Callable Mail Delivery Module Quota Hook
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 10 September 2007
* Last Edited: 10 September 2007
*/
/* Function prototypes */
long dmail_quota (STRING *msg,char *path,char *tmp,char *sender,
long precedence);

68
src/imapd/Makefile Normal file
View File

@@ -0,0 +1,68 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IMAPD Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 5 November 1990
# Last Edited: 30 August 2006
ALERT=/etc/imapd.alert
USERALERT=.imapalert
SHUTDOWN=/etc/nologin
ANO=/etc/anonymous.newsgroups
NNTP=/etc/imapd.nntp
SHELL= /bin/sh
# Un-comment this to get somewhat better interoperability with Netscape. It
# causes the "Manage Mail" menu item to open the given URL, e.g. to point to
# an alternative IMAP client (e.g. Pine) or perhaps to a homebrew mail
# account management page.
#NSBD= -DNETSCAPE_BRAIN_DAMAGE=\"http://www.washington.edu/pine\"
# Get local definitions from c-client directory
C = ../c-client
CCLIENTLIB = $C/c-client.a
CC = `cat $C/CCTYPE`
CFLAGS = -I$C `cat $C/CFLAGS` $(NSBD) $(ENBD) -DANOFILE=\"$(ANO)\" \
-DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" \
-DUSERALERTFILE=\"$(USERALERT)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
all: imapd
imapd: $(CCLIENTLIB) imapd.o
$(CC) $(CFLAGS) -o imapd imapd.o $(LDFLAGS)
imapd.o: $C/mail.h $C/misc.h $C/osdep.h
$(CCLIENTLIB):
cd $C;make
clean:
rm -f *.o imapd || true
# A monument to a hack of long ago and far away...
love:
@echo 'not war?'

48
src/imapd/imapd.8 Normal file
View File

@@ -0,0 +1,48 @@
.ig
* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
..
.TH IMAPD 8 "August 30, 2006"
.UC 5
.SH NAME
IMAPd \- Internet Message Access Protocol server
.SH SYNOPSIS
.B /usr/etc/imapd
.SH DESCRIPTION
.I imapd
is a server which supports the
.B IMAP4rev1
remote mail access protocol as documented in RFC-3501.
.I imapd
is invoked by the internet server (see
.IR inetd (8)),
normally for requests to connect to the
.B IMAP
port as indicated by the
.I /etc/services
file (see
.IR services (5)).
Normally, this is port 143 for plaintext IMAP and 993 for SSL IMAP.
.PP
This daemons contains CRAM-MD5 support. See the md5.txt documentation
file for additional information.
.PP
.I imapd
can also be accessed via
.IR rsh (1)
by many Unix-based clients. To do this, the
.I imapd
binary must have a link to
.I /etc/rimapd
since this is where this software expects it to be located.
.SH "SEE ALSO"
rsh(1) ipopd(8)

4608
src/imapd/imapd.c Normal file

File diff suppressed because it is too large Load Diff

55
src/imapd/makefile.nt Normal file
View File

@@ -0,0 +1,55 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IMAPD Makefile for Windows 9x and Windows NT
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 5 November 1990
# Last Edited: 30 August 2006
ALERT=\\imapd.alert
USERALERT=alert.txt
SHUTDOWN=\\nologin
ANO=\\anonymous.newsgroups
NNTP=\\imapd.nntp
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
imapd: $(CCLIENTLIB) imapd.obj
LINK /NOLOGO imapd.obj $(LIBS)
imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

58
src/imapd/makefile.ntk Normal file
View File

@@ -0,0 +1,58 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IMAPD Makefile for Windows 9x and Windows NT + Kerberos
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 5 November 1990
# Last Edited: 30 August 2006
ALERT=\\imapd.alert
USERALERT=alert.txt
SHUTDOWN=\\nologin
ANO=\\anonymous.newsgroups
NNTP=\\imapd.nntp
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
imapd: $(CCLIENTLIB) imapd.obj
LINK /NOLOGO imapd.obj $(LIBS)
imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

56
src/imapd/makefile.w2k Normal file
View File

@@ -0,0 +1,56 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IMAPD Makefile for Windows 2000/XP
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 5 November 1990
# Last Edited: 30 August 2006
ALERT=\\imapd.alert
USERALERT=alert.txt
SHUTDOWN=\\nologin
ANO=\\anonymous.newsgroups
NNTP=\\imapd.nntp
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
OSCOMPAT = /DWIN32
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
imapd: $(CCLIENTLIB) imapd.obj
LINK /NOLOGO imapd.obj $(LIBS)
imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

58
src/ipopd/Makefile Normal file
View File

@@ -0,0 +1,58 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IPOPD client Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 28 October 1990
# Last Edited: 30 August 2006
C = ../c-client
CCLIENTLIB = $C/c-client.a
SHELL = /bin/sh
# Get local definitions from c-client directory
CC = `cat $C/CCTYPE`
CFLAGS = -I$C `cat $C/CFLAGS`
LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
ipopd: ipop2d ipop3d
ipop2d: $(CCLIENTLIB) ipop2d.o
$(CC) $(CFLAGS) -o ipop2d ipop2d.o $(LDFLAGS)
ipop3d: $(CCLIENTLIB) ipop3d.o
$(CC) $(CFLAGS) -o ipop3d ipop3d.o $(LDFLAGS)
ipop2d.o: $C/mail.h $C/misc.h $C/osdep.h
ipop3d.o: $C/mail.h $C/misc.h $C/osdep.h
$(CCLIENTLIB):
cd $C;make
clean:
rm -f *.o ipop2d ipop3d || true
# A monument to a hack of long ago and far away...
love:
@echo 'not war?'

711
src/ipopd/ipop2d.c Normal file
View File

@@ -0,0 +1,711 @@
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: IPOP2D - IMAP to POP2 conversion server
*
* Author: Mark Crispin
* UW Technology
* University of Washington
* Seattle, WA 98195
* Internet: MRC@Washington.EDU
*
* Date: 28 October 1990
* Last Edited: 13 February 2008
*/
/* Parameter files */
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
extern int errno; /* just in case */
#include <signal.h>
#include <time.h>
#include "c-client.h"
/* Autologout timer */
#define KODTIMEOUT 60*5
#define LOGINTIMEOUT 60*3
#define TIMEOUT 60*30
/* Size of temporary buffers */
#define TMPLEN 1024
/* Server states */
#define LISN 0
#define AUTH 1
#define MBOX 2
#define ITEM 3
#define NEXT 4
#define DONE 5
/* Global storage */
char *version = "75"; /* edit number of this server */
short state = LISN; /* server state */
short critical = NIL; /* non-zero if in critical code */
MAILSTREAM *stream = NIL; /* mailbox stream */
time_t idletime = 0; /* time we went idle */
unsigned long nmsgs = 0; /* number of messages */
unsigned long current = 1; /* current message number */
unsigned long size = 0; /* size of current message */
char status[MAILTMPLEN]; /* space for status string */
char *user = ""; /* user name */
char *pass = ""; /* password */
unsigned long *msg = NIL; /* message translation vector */
char *logout = "Logout";
char *goodbye = "+ Sayonara\015\012";
/* Function prototypes */
int main (int argc,char *argv[]);
void sayonara (int status);
void clkint ();
void kodint ();
void hupint ();
void trmint ();
short c_helo (char *t,int argc,char *argv[]);
short c_fold (char *t);
short c_read (char *t);
short c_retr (char *t);
short c_acks (char *t);
short c_ackd (char *t);
short c_nack (char *t);
/* Main program */
int main (int argc,char *argv[])
{
char *s,*t;
char cmdbuf[TMPLEN];
char *pgmname = (argc && argv[0]) ?
(((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
s+1 : argv[0]) : "ipop2d";
/* set service name before linkage */
mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
#include "linkage.c"
if (mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) {
goodbye = "- POP2 server disabled on this system\015\012";
sayonara (1);
}
/* initialize server */
server_init (pgmname,"pop",NIL,clkint,kodint,hupint,trmint,NIL);
/* There are reports of POP2 clients which get upset if anything appears
* between the "+" and the "POP2" in the greeting.
*/
printf ("+ POP2 %s %s.%s server ready\015\012",tcp_serverhost (),
CCLIENTVERSION,version);
fflush (stdout); /* dump output buffer */
state = AUTH; /* initial server state */
while (state != DONE) { /* command processing loop */
idletime = time (0); /* get a command under timeout */
alarm ((state != AUTH) ? TIMEOUT : LOGINTIMEOUT);
clearerr (stdin); /* clear stdin errors */
while (!fgets (cmdbuf,TMPLEN-1,stdin)) {
if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
else {
char *e = ferror (stdin) ?
strerror (errno) : "Unexpected client disconnect";
alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
sprintf (logout = cmdbuf,"%.80s while reading line",e);
state = DONE;
stream = mail_close (stream);
goodbye = NIL;
sayonara (1);
}
}
alarm (0); /* make sure timeout disabled */
idletime = 0; /* no longer idle */
/* find end of line */
if (!strchr (cmdbuf,'\012')) {
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
logout = "- Command line too long\015\012";
state = DONE;
}
else if (!(s = strtok (cmdbuf," \015\012"))) {
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "- Missing or null command\015\012";
state = DONE;
}
else { /* dispatch based on command */
ucase (s); /* canonicalize case */
/* snarf argument */
t = strtok (NIL,"\015\012");
if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv);
else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD"))
state = c_fold (t);
else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ"))
state = c_read (t);
else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t);
else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t);
else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t);
else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t);
else if ((state == AUTH || state == MBOX || state == ITEM) &&
!strcmp (s,"QUIT")) {
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
state = DONE; /* done in either case */
if (t) goodbye = "- Bogus argument given to QUIT\015\012";
else { /* expunge the stream */
if (stream && nmsgs) stream = mail_close_full (stream,CL_EXPUNGE);
stream = NIL; /* don't repeat it */
}
}
else { /* some other or inappropriate command */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "- Bogus or out of sequence command\015\012";
state = DONE;
}
}
fflush (stdout); /* make sure output blatted */
}
/* clean up the stream */
if (stream) mail_close (stream);
sayonara (0);
return 0; /* stupid compilers */
}
/* Say goodbye
* Accepts: exit status
*
* Does not return
*/
void sayonara (int status)
{
logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
if (goodbye) { /* have a goodbye message? */
fputs (goodbye,stdout);
fflush (stdout); /* make sure blatted */
}
syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
user ? (char *) user : "???",tcp_clienthost ());
/* do logout hook if needed */
if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
_exit (status); /* all done */
}
/* Clock interrupt
*/
void clkint ()
{
alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "- Autologout; idle for too long\015\012";
logout = "Autologout";
state = DONE; /* mark state done in either case */
if (!critical) { /* badly host if in critical code */
if (stream && !stream->lock) mail_close (stream);
stream = NIL;
sayonara (1); /* die die die */
}
}
/* Kiss Of Death interrupt
*/
void kodint ()
{
/* only if in command wait */
if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "- Killed (lost mailbox lock)\015\012";
logout = "Killed (lost mailbox lock)";
state = DONE; /* mark state done in either case */
if (!critical) { /* badly host if in critical code */
if (stream && !stream->lock) mail_close (stream);
stream = NIL;
sayonara (1); /* die die die */
}
}
}
/* Hangup interrupt
*/
void hupint ()
{
alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = NIL;
logout = "Hangup";
state = DONE; /* mark state done in either case */
if (!critical) { /* badly host if in critical code */
if (stream && !stream->lock) mail_close (stream);
stream = NIL;
sayonara (1); /* die die die */
}
}
/* Termination interrupt
*/
void trmint ()
{
alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
goodbye = "- Killed (terminated)\015\012";
logout = "Killed (terminated)";
if (critical) state = DONE; /* mark state done in either case */
/* Make no attempt at graceful closure since a shutdown may be in
* progress, and we won't have any time to do mail_close() actions.
*/
else sayonara (1); /* die die die */
}
/* Parse HELO command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_helo (char *t,int argc,char *argv[])
{
char *s,*u,*p;
char tmp[TMPLEN];
if ((!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) ||
(strlen (p) >= TMPLEN)) { /* get user name and password */
fputs ("- Missing user or password\015\012",stdout);
return DONE;
}
/* copy password, handle quoting */
for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p;
*s = '\0'; /* tie off string */
pass = cpystr (tmp);
if (!(s = strchr (u,':'))) { /* want remote mailbox? */
/* no, delimit user from possible admin */
if (s = strchr (u,'*')) *s++ = '\0';
if (server_login (user = cpystr (u),pass,s,argc,argv)) {
syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s",s ? "Admin " : "",
user,tcp_clienthost ());
return c_fold ("INBOX"); /* local; select INBOX */
}
}
#ifndef DISABLE_POP_PROXY
/* can't do if can't log in as anonymous */
else if (anonymous_login (argc,argv)) {
*s++ = '\0'; /* separate host name from user name */
user = cpystr (s); /* note user name */
syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",u,user,
tcp_clienthost ());
/* initially remote INBOX */
sprintf (tmp,"{%.128s/user=%.128s}INBOX",u,user);
/* disable rimap just in case */
mail_parameters (NIL,SET_RSHTIMEOUT,0);
return c_fold (tmp);
}
#endif
fputs ("- Bad login\015\012",stdout);
return DONE;
}
/* Parse FOLD command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_fold (char *t)
{
unsigned long i,j,flags;
char *s = NIL,tmp[2*TMPLEN];
NETMBX mb;
if (!(t && *t)) { /* make sure there's an argument */
fputs ("- Missing mailbox name\015\012",stdout);
return DONE;
}
myusername_full (&flags); /* get user type flags */
/* expunge old stream */
if (stream && nmsgs) mail_expunge (stream);
nmsgs = 0; /* no more messages */
if (msg) fs_give ((void **) &msg);
#ifndef DISABLE_POP_PROXY
if (flags == MU_ANONYMOUS) { /* don't permit proxy to leave IMAP */
if (stream) { /* not first time */
if (!(stream->mailbox && (s = strchr (stream->mailbox,'}'))))
fatal ("bad previous mailbox name");
strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox));
if (i >= TMPLEN) fatal ("ridiculous network prefix");
strcpy (tmp+i,t); /* append mailbox to initial spec */
t = tmp;
}
/* must be net name first time */
else if (!mail_valid_net_parse (t,&mb)) fatal ("anonymous folder bogon");
}
#endif
/* open mailbox, note # of messages */
if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) {
sprintf (tmp,"1:%lu",j); /* fetch fast information for all messages */
mail_fetch_fast (stream,tmp,NIL);
msg = (unsigned long *) fs_get ((stream->nmsgs + 1) *
sizeof (unsigned long));
for (i = 1; i <= j; i++) /* find undeleted messages, add to vector */
if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i;
}
#ifndef DISABLE_POP_PROXY
if (!stream && (flags == MU_ANONYMOUS)) {
fputs ("- Bad login\015\012",stdout);
return DONE;
}
#endif
printf ("#%lu messages in %s\015\012",nmsgs,stream ? stream->mailbox :
"<none>");
return MBOX;
}
/* Parse READ command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_read (char *t)
{
MESSAGECACHE *elt = NIL;
if (t && *t) { /* have a message number argument? */
/* validity check message number */
if (((current = strtoul (t,NIL,10)) < 1) || (current > nmsgs)) {
fputs ("- Invalid message number given to READ\015\012",stdout);
return DONE;
}
}
else if (current > nmsgs) { /* at end of mailbox? */
fputs ("=0 No more messages\015\012",stdout);
return MBOX;
}
/* set size if message valid and exists */
size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0;
if (elt) sprintf (status,"Status: %s%s\015\012",
elt->seen ? "R" : " ",elt->recent ? " " : "O");
else status[0] = '\0'; /* no status */
size += strlen (status); /* update size to reflect status */
/* display results */
printf ("=%lu characters in message %lu\015\012",size + 2,current);
return ITEM;
}
/* Parse RETR command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_retr (char *t)
{
unsigned long i,j;
STRING *bs;
if (t) { /* disallow argument */
fputs ("- Bogus argument given to RETR\015\012",stdout);
return DONE;
}
if (size) { /* message size valid? */
t = mail_fetch_header (stream,msg[current],NIL,NIL,&i,FT_PEEK);
if (i > 2) { /* only if there is something */
i -= 2; /* lop off last two octets */
while (i) { /* blat the header */
if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
if (i -= j) t += j; /* advance to incomplete data */
}
}
fputs (status,stdout); /* yes, output message */
fputs ("\015\012",stdout); /* delimit header from text */
if (t = mail_fetch_text (stream,msg[current],NIL,&i,FT_RETURNSTRINGSTRUCT))
while (i) { /* blat the text */
if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
if (i -= j) t += j; /* advance to incomplete data */
}
else for (bs = &stream->private.string; i--; )
if (putc (SNX (bs),stdout) == EOF) return DONE;
fputs ("\015\012",stdout); /* trailer to coddle PCNFS' NFSMAIL */
}
else return DONE; /* otherwise go away */
return NEXT;
}
/* Parse ACKS command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_acks (char *t)
{
char tmp[TMPLEN];
if (t) { /* disallow argument */
fputs ("- Bogus argument given to ACKS\015\012",stdout);
return DONE;
}
/* mark message as seen */
sprintf (tmp,"%lu",msg[current++]);
mail_setflag (stream,tmp,"\\Seen");
return c_read (NIL); /* end message reading transaction */
}
/* Parse ACKD command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_ackd (char *t)
{
char tmp[TMPLEN];
if (t) { /* disallow argument */
fputs ("- Bogus argument given to ACKD\015\012",stdout);
return DONE;
}
/* mark message as seen and deleted */
sprintf (tmp,"%lu",msg[current]);
mail_setflag (stream,tmp,"\\Seen \\Deleted");
msg[current++] = 0; /* mark message as deleted */
return c_read (NIL); /* end message reading transaction */
}
/* Parse NACK command
* Accepts: pointer to command argument
* Returns: new state
*/
short c_nack (char *t)
{
if (t) { /* disallow argument */
fputs ("- Bogus argument given to NACK\015\012",stdout);
return DONE;
}
return c_read (NIL); /* end message reading transaction */
}
/* Co-routines from MAIL library */
/* Message matches a search
* Accepts: MAIL stream
* message number
*/
void mm_searched (MAILSTREAM *stream,unsigned long msgno)
{
/* Never called */
}
/* Message exists (i.e. there are that many messages in the mailbox)
* Accepts: MAIL stream
* message number
*/
void mm_exists (MAILSTREAM *stream,unsigned long number)
{
/* Can't use this mechanism. POP has no means of notifying the client of
new mail during the session. */
}
/* Message expunged
* Accepts: MAIL stream
* message number
*/
void mm_expunged (MAILSTREAM *stream,unsigned long number)
{
if (state != DONE) { /* ignore if closing */
/* someone else screwed us */
goodbye = "- Mailbox expunged from under me!\015\012";
if (stream && !stream->lock) mail_close (stream);
stream = NIL;
sayonara (1);
}
}
/* Message status changed
* Accepts: MAIL stream
* message number
*/
void mm_flags (MAILSTREAM *stream,unsigned long number)
{
/* This isn't used */
}
/* Mailbox found
* Accepts: MAIL stream
* hierarchy delimiter
* mailbox name
* mailbox attributes
*/
void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
/* This isn't used */
}
/* Subscribe mailbox found
* Accepts: MAIL stream
* hierarchy delimiter
* mailbox name
* mailbox attributes
*/
void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
/* This isn't used */
}
/* Mailbox status
* Accepts: MAIL stream
* mailbox name
* mailbox status
*/
void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
{
/* This isn't used */
}
/* Notification event
* Accepts: MAIL stream
* string to log
* error flag
*/
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
mm_log (string,errflg); /* just do mm_log action */
}
/* Log an event for the user to see
* Accepts: string to log
* error flag
*/
void mm_log (char *string,long errflg)
{
switch (errflg) {
case NIL: /* information message */
case PARSE: /* parse glitch */
break; /* too many of these to log */
case WARN: /* warning */
syslog (LOG_DEBUG,"%s",string);
break;
case BYE: /* driver broke connection */
if (state != DONE) {
char tmp[MAILTMPLEN];
alarm (0); /* disable all interrupts */
server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
sayonara (1);
}
break;
case ERROR: /* error that broke command */
default: /* default should never happen */
syslog (LOG_NOTICE,"%s",string);
break;
}
}
/* Log an event to debugging telemetry
* Accepts: string to log
*/
void mm_dlog (char *string)
{
/* Not doing anything here for now */
}
/* Get user name and password for this host
* Accepts: parse of network mailbox name
* where to return user name
* where to return password
* trial count
*/
void mm_login (NETMBX *mb,char *username,char *password,long trial)
{
/* set user name */
strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
strncpy (password,pass,255); /* and password */
username[NETMAXUSER] = password[255] = '\0';
}
/* About to enter critical code
* Accepts: stream
*/
void mm_critical (MAILSTREAM *stream)
{
++critical;
}
/* About to exit critical code
* Accepts: stream
*/
void mm_nocritical (MAILSTREAM *stream)
{
--critical;
}
/* Disk error found
* Accepts: stream
* system error code
* flag indicating that mailbox may be clobbered
* Returns: abort flag
*/
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
{
if (serious) { /* try your damnest if clobberage likely */
syslog (LOG_ALERT,
"Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
user,tcp_clienthost (),
(stream && stream->mailbox) ? stream->mailbox : "???",
strerror (errcode));
alarm (0); /* make damn sure timeout disabled */
sleep (60); /* give it some time to clear up */
return NIL;
}
syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
user,tcp_clienthost (),
(stream && stream->mailbox) ? stream->mailbox : "???",
strerror (errcode));
return T;
}
/* Log a fatal error event
* Accepts: string to log
*/
void mm_fatal (char *string)
{
mm_log (string,ERROR); /* shouldn't happen normally */
}

1082
src/ipopd/ipop3d.c Normal file

File diff suppressed because it is too large Load Diff

75
src/ipopd/ipopd.8 Normal file
View File

@@ -0,0 +1,75 @@
.ig
* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
..
.TH IPOPD 8 "August 30, 2006"
.UC 5
.SH NAME
IPOPd \- Post Office Protocol server
.SH SYNOPSIS
.B /usr/etc/ipop2d
.PP
.B /usr/etc/ipop3d
.SH DESCRIPTION
.I ipop2d
and
.I ipop3d
are servers which support the
.B POP2
and
.B POP3
remote mail access protocols respectively.
.I ipop2d
and
.I ipop3d
can also be used by
.B POP2
and
.B POP3
clients respecitively to access mailboxes on
.B IMAP
servers by specifying a login user name in the form <host>:<user>
e.g.,
.B SERVER.WASHINGTON.EDU:SMITH.
.PP
These daemons contain CRAM-MD5 and APOP support. See the md5.txt
documentation file for additional information.
.PP
.I ipop2d
and
.I ipop3d
are invoked by the internet server (see
.IR inetd (8)),
normally for requests to connect to the
.B POP
port as indicated by the
.I /etc/services
file (see
.IR services (5)).
.SH "SEE ALSO"
imapd(8)
.SH BUGS
The
.B POP2
and
.B POP3
protocols are intrinsically less flexible than
.B IMAP
and do not maintain `read' vs `unread' state on the server. As a result,
most
.B POP
based software transfers all the mail from the server to the client and
deletes it from the server. This necessarily locks the user into using only
a single client.
.PP
.B POP3
does not allow you to specify an alternate folder from the user's default.

57
src/ipopd/makefile.nt Normal file
View File

@@ -0,0 +1,57 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IPOPD Makefile for Windows 9x and Windows NT
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 28 October 1990
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
ipopd: ipop2d ipop3d
ipop2d: $(CCLIENTLIB) ipop2d.obj
LINK /NOLOGO ipop2d.obj $(LIBS)
ipop3d: $(CCLIENTLIB) ipop3d.obj
LINK /NOLOGO ipop3d.obj $(LIBS)
ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

58
src/ipopd/makefile.ntk Normal file
View File

@@ -0,0 +1,58 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IPOPD Makefile for Windows 9x and Windows NT + Kerberos
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 28 October 1990
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
ipopd: ipop2d ipop3d
ipop2d: $(CCLIENTLIB) ipop2d.obj
LINK /NOLOGO ipop2d.obj $(LIBS)
ipop3d: $(CCLIENTLIB) ipop3d.obj
LINK /NOLOGO ipop3d.obj $(LIBS)
ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

56
src/ipopd/makefile.w2k Normal file
View File

@@ -0,0 +1,56 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: IPOPD Makefile for Windows 2000/XP
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 28 October 1990
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
OSCOMPAT = /DWIN32
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
ipopd: ipop2d ipop3d
ipop2d: $(CCLIENTLIB) ipop2d.obj
LINK /NOLOGO ipop2d.obj $(LIBS)
ipop3d: $(CCLIENTLIB) ipop3d.obj
LINK /NOLOGO ipop3d.obj $(LIBS)
ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

51
src/mailutil/Makefile Normal file
View File

@@ -0,0 +1,51 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: mailutil Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 2 February 1993
# Last Edited: 30 August 2006
C = ../c-client
CCLIENTLIB = $C/c-client.a
SHELL = /bin/sh
# Get local definitions from c-client directory
CC = `cat $C/CCTYPE`
CFLAGS = -I$C `cat $C/CFLAGS`
LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
mailutil: $(CCLIENTLIB) mailutil.o
$(CC) $(CFLAGS) -o mailutil mailutil.o $(LDFLAGS)
mailutil.o: $C/mail.h $C/misc.h $C/osdep.h
$(CCLIENTLIB):
cd $C;make
clean:
rm -f *.o mailutil
# A monument to a hack of long ago and far away...
love:
@echo 'not war?'

264
src/mailutil/mailutil.1 Normal file
View File

@@ -0,0 +1,264 @@
.ig
* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
..
.TH mailutil 1 "March 3, 2008"
.SH NAME
mailutil - mail utility program
.nh
.SH SYNTAX
.B mailutil command [switches] [arguments]
.PP
All commands accept the -d, -v, and -u switches in addition to any
command-specific switches.
.PP
.B mailutil check [MAILBOX]
.PP
.B mailutil create MAILBOX
.PP
.B mailutil delete MAILBOX
.PP
.B mailutil rename SOURCE DESTINATION
.PP
.B mailutil copy [-rw] [-kw] [-ig] SOURCE DESTINATION
.PP
.B mailutil move [-rw] [-kw] [-ig] SOURCE DESTINATION
.PP
.B mailutil append [-rw] [-kw] [-ig] SOURCE DESTINATION
.PP
.B mailutil appenddelete [-rw] [-kw] [-ig] SOURCE DESTINATION
.PP
.B mailutil prune MAILBOX CRITERIA
.PP
.B mailutil transfer [-m mode] [-rw] [-kw] [-ig] SOURCE DESTINATION
.SH DESCRIPTION
.B mailutil
replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy,
mbxcreat, and mbxcvt programs.
.PP
.B mailutil check
determines whether new mail exists in the given mailbox (the default
is INBOX). The number of new messages is defined as the number of
messages that have "Recent" status set. If the mailbox contains no
new messages,
.B mailutil check
will indicate that no new mail is present;
otherwise, it will report the number of new messages. In either case,
it will also indicate the canonical form of the name of the mailbox.
.PP
.B mailutil create
creates a new
.I mailbox
with the given name. The mailbox name must not already exist. A mailbox
can be created in a particular format by prefixing the name with
.I #driver.
followed by the format name and a
.I /
character. For example, the command
.br
mailutil create #driver.mbx/junkmail
.br
will create a new mailbox named "junkmail" in mbx format.
.PP
.B mailutil delete
deletes an existing
.I mailbox
with the given name.
.PP
.B mailutil rename
renames an existing mailbox to a new name (which must not already exist).
This only works if the old and new names are in the same mail store. A
more general means to rename a mailbox is to do a
.B mailutil copy
of the old name to the new name, followed by a
.B mailutil delete
of the old name.
.PP
.B mailutil copy
creates a new mailbox and copies messages from the old mailbox to the
new mailbox. As in
.B mailutil create
a mailbox format can be specified with the new mailbox. For example, the
command
.br
mailutil copy INBOX #driver.mbx/INBOX
.br
will copy messages from your existing INBOX to an mbx-format INBOX.
.PP
.B mailutil move
is similar to
.B mailutil copy
but in addition will also remove (delete and expunge) the messages from the
old mailbox after copying them to the new mailbox.
.PP
.B mailutil append
and
.B mailutil appenddelete
are similar to
.B mailutil copy
and
.B mailutil move
respectively except that they do not create the destination mailbox.
.PP
.B mailutil prune
prunes the mailbox of messages which match certain criteria, which are
in the form of IMAP2 (RFC 1176) SEARCH arguments. For example, the
command.
.br
mailutil prune INBOX "before 1-jan-2004"
.br
will delete and expunge all messages written before January 1, 2004.
.PP
Note that mailutil implements pruning by deleting the matching messages,
and then expunging the mailbox. Consequently, mailutil will also expunge
any messages which were deleted at the time of the pruning.
.PP
.B mailutil transfer
copies an entire hierarchy of mailboxes from the named source to the
named destination. Mailboxes are created on the destination as
needed. Any error in copying messages will cause the transfer to stop.
.PP
Normally, any error in creation will cause the transfer to stop.
However, if
.B -m MODE
or
.B -merge MODE
is specified, a merging transfer is performed. The
.B MODE
argument indicats the type of merge:
.PP
.B -m[erge] prompt
indicates that the user should be asked for an alternative name to create.
If creating the new name fails, the user will be asked again.
.PP
.B -m[erge] append
indicates that it's alright to copy the messages into an existing mailbox
with that name. If the mailbox does not exist, the user will be prompted
for an alternative name.
.PP
.B -m[erge] suffix=XXXX
where XXXX is any string, indicates that an alternative name should be
built by appending the given suffix to the name. It that alternative name
can't be created, then the user will be prompted for an alternative name.
.PP
The source hierarchy consists of all mailboxes which start
with the given source name. With the exception of a remote system
specification (within "{}" braces), the source name is used as the
name of the destination. The destination hierarchy is a prefix
applied to any new names being created. For example,
.br
mailutil transfer foo bar
.br
will copy all mailboxes with names beginning with "foo" to names
beginning with "bar" (hence "foobar" will be copied to "barfoobar").
Similarly,
.br
mailutil transfer "{imap.foo.com}" "{imap.bar.com}old/"
.br
will copy all mailboxes from the imap.foo.com IMAP server to
equivalent names starting with "old/" on the imap.bar.com IMAP server.
.SH FLAGS
The
.B -d
or
.B -debug
flag prints full debugging telemetry including protocol operations.
.PP
The
.B -v
or
.B -verbose
flag prints verbose (non-error) telemetry.
.PP
The
.B -u USERID
or
.B -user USERID
switch attempts to become the indicated user. This is for the benefit of
system administrators who want to do mailutil operations on a userid that
does not normally have shell access.
.PP
The
.B -rw
or
.B -rwcopy
flag causes the source mailbox to be open in readwrite mode rather than
readonly mode. Normally, mailutil tries to use readonly mode to avoid
altering any flags in the source mailbox, but some mailbox types, e.g.
POP3, can't be open in readonly mode.
.PP
The
.B -kw
or
.B -kwcopy
flag causes the keywords of the source mailbox to be created in the
destination mailbox. Normally, mailutil does not create keywords in
the destination mailbox so only those keywords that are already defined
in the destination mailbox will be preserved. Note that some IMAP servers
may automatically create keywords, so this flag may not be necessary.
.PP
The
.B -ig
or
.B -ignore
flag causes the keywords of the source mailbox to be ignored completely
and no attempt is made to copy them to the destination mailbox.
.PP
The
.B -ig[nore]
and
.B -kw[copy]
flags are mutually exclusive.
.SH ARGUMENTS
The arguments are standard c-client mailbox names. A
variety of mailbox name formats and types of mailboxes are supported
by c-client; examples of the most common forms of names are:
.PP
.I
.IP Name 15
.I Meaning
.IP INBOX
primary incoming mail folder on the local system
.IP archive/tx-project
mail folder named "tx-project" in "archive" subdirectory of local
filesystem home directory
.IP {imapserver.foo.com}INBOX
primary incoming mail folder on IMAP server system
"imapserver.foo.com"
.IP {imapserver.foo.com}archive/tx-project
mail folder named "tx-project" in "archive" subdirectory on IMAP
server system "imapserver.foo.com"
.IP #news.comp.mail.misc
newsgroup "comp.mail.misc" on local filesystem
.IP {newserver.foo.com/nntp}comp.mail.misc
newsgroup "comp.mail.misc" on NNTP server system "newserver.foo.com"
.IP {popserver.foo.com/pop3}
mail folder on POP3 server system "popserver.foo.com"
.LP
See your system manager for more information about the types of
mailboxes which are available on your system.
.SH RESTRICTIONS
You must surround a
.I {host}mailbox
argument with quotation marks if you run
.B mailutil
from
.IR csh (1)
or another shell for which braces have special meaning.
.PP
You must surround a
.I #driver.format/mailbox
argument with quotation marks if you run
.B mailutil
from a shell in which "#" is the comment character.
.SH AUTHOR
Mark Crispin, MRC@Washington.EDU

942
src/mailutil/mailutil.c Normal file
View File

@@ -0,0 +1,942 @@
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Mail utility
*
* Author: Mark Crispin
* UW Technology
* University of Washington
* Seattle, WA 98195
* Internet: MRC@Washington.EDU
*
* Date: 2 February 1994
* Last Edited: 19 February 2008
*/
#include <stdio.h>
#include <errno.h>
extern int errno; /* just in case */
#include "c-client.h"
#ifdef SYSCONFIG /* defined in env_unix.h */
#include <pwd.h>
#endif
/* Globals */
char *version = "13"; /* edit number */
int debugp = NIL; /* flag saying debug */
int verbosep = NIL; /* flag saying verbose */
int rwcopyp = NIL; /* flag saying readwrite copy (for POP) */
int kwcopyp = NIL; /* flag saying keyword copy */
int ignorep = NIL; /* flag saying ignore keywords */
int critical = NIL; /* flag saying in critical code */
int trycreate = NIL; /* [TRYCREATE] seen */
char *suffix = NIL; /* suffer merge mode suffix text */
int ddelim = -1; /* destination delimiter */
FILE *f = NIL;
/* Usage strings */
char *usage2 = "usage: %s %s\n\n%s\n";
char *usage3 = "usage: %s %s %s\n\n%s\n";
char *usgchk = "check [MAILBOX]";
char *usgcre = "create MAILBOX";
char *usgdel = "delete MAILBOX";
char *usgren = "rename SOURCE DESTINATION";
char *usgcpymov = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";
char *usgappdel = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";
char *usgprn = "prune mailbox SEARCH_CRITERIA";
char *usgxfr = "transfer [-rw[copy]] [-kw[copy]] [-ig[nore]] [-m[erge] m] SOURCE DEST";
#ifdef SYSCONFIG
char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]] [-u[ser] userid] [--]";
#else
char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]]";
#endif
/* Merge modes */
#define mPROMPT 1
#define mAPPEND 2
#define mSUFFIX 3
/* Function prototypes */
void ms_init (STRING *s,void *data,unsigned long size);
char ms_next (STRING *s);
void ms_setpos (STRING *s,unsigned long i);
int main (int argc,char *argv[]);
SEARCHPGM *prune_criteria (char *criteria);
int prune_criteria_number (unsigned long *number,char **r);
int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
int mode);
long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date,
STRING **message);
/* Append package */
typedef struct append_package {
MAILSTREAM *stream; /* source stream */
unsigned long msgno; /* current message number */
unsigned long msgmax; /* maximum message number */
char *flags; /* current flags */
char *date; /* message internal date */
STRING *message; /* stringstruct of message */
} APPENDPACKAGE;
/* Message string driver for message stringstructs */
STRINGDRIVER mstring = {
ms_init, /* initialize string structure */
ms_next, /* get next byte in string structure */
ms_setpos /* set position in string structure */
};
/* Initialize file string structure for file stringstruct
* Accepts: string structure
* pointer to message data structure
* size of string
*/
void ms_init (STRING *s,void *data,unsigned long size)
{
APPENDPACKAGE *md = (APPENDPACKAGE *) data;
s->data = data; /* note stream/msgno and header length */
mail_fetch_header (md->stream,md->msgno,NIL,NIL,&s->data1,
FT_PREFETCHTEXT|FT_PEEK);
#if 0
s->size = size; /* message size */
#else /* This kludge is necessary because of broken IMAP servers (sigh!) */
mail_fetch_text (md->stream,md->msgno,NIL,&s->size,FT_PEEK);
s->size += s->data1; /* header + body size */
#endif
SETPOS (s,0);
}
/* Get next character from file stringstruct
* Accepts: string structure
* Returns: character, string structure chunk refreshed
*/
char ms_next (STRING *s)
{
char c = *s->curpos++; /* get next byte */
SETPOS (s,GETPOS (s)); /* move to next chunk */
return c; /* return the byte */
}
/* Set string pointer position for file stringstruct
* Accepts: string structure
* new position
*/
void ms_setpos (STRING *s,unsigned long i)
{
APPENDPACKAGE *md = (APPENDPACKAGE *) s->data;
if (i < s->data1) { /* want header? */
s->chunk = mail_fetch_header (md->stream,md->msgno,NIL,NIL,NIL,FT_PEEK);
s->chunksize = s->data1; /* header length */
s->offset = 0; /* offset is start of message */
}
else if (i < s->size) { /* want body */
s->chunk = mail_fetch_text (md->stream,md->msgno,NIL,NIL,FT_PEEK);
s->chunksize = s->size - s->data1;
s->offset = s->data1; /* offset is end of header */
}
else { /* off end of message */
s->chunk = NIL; /* make sure that we crack on this then */
s->chunksize = 1; /* make sure SNX cracks the right way... */
s->offset = i;
}
/* initial position and size */
s->curpos = s->chunk + (i -= s->offset);
s->cursize = s->chunksize - i;
}
/* Main program */
int main (int argc,char *argv[])
{
MAILSTREAM *source = NIL;
MAILSTREAM *dest = NIL;
SEARCHPGM *criteria;
char c,*s,*dp,*t,*t1,tmp[MAILTMPLEN],mbx[MAILTMPLEN];
unsigned long m,len,curlen,start,last;
int i;
int merge = NIL;
int retcode = 1;
int moreswitchp = T;
char *cmd = NIL;
char *src = NIL;
char *dst = NIL;
char *pgm = argc ? argv[0] : "mailutil";
#include "linkage.c"
for (i = 1; i < argc; i++) {
s = argv[i]; /* pick up argument */
/* parse switches */
if (moreswitchp && (*s == '-')) {
if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T;
else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T;
else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T;
else if (!strcmp (s,"-kwcopy") || !strcmp (s,"-kw")) kwcopyp = T;
else if (!strcmp (s,"-ignore") || !strcmp (s,"-ig")) ignorep = T;
else if ((!strcmp (s,"-merge") || !strcmp (s,"-m")) && (++i < argc)) {
if (!strcmp (s = argv[i],"prompt")) merge = mPROMPT;
else if (!strcmp (s,"append")) merge = mAPPEND;
else if (!strncmp (s,"suffix=",7) && s[7]) {
merge = mSUFFIX;
suffix = cpystr (s+7);
}
else {
printf ("unknown merge option: %s\n",s);
exit (retcode);
}
}
#ifdef SYSCONFIG
else if ((!strcmp (s,"-user") || !strcmp (s,"-u")) && (++i < argc)) {
struct passwd *pw = getpwnam (s = argv[i]);
if (!pw) {
printf ("unknown user id: %s\n",argv[i]);
exit (retcode);
}
else if (setuid (pw->pw_uid)) {
perror ("unable to change user id");
exit (retcode);
}
}
#endif
/* -- means no more switches, so mailbox
name can start with "-" */
else if ((s[1] == '-') && !s[2]) moreswitchp = NIL;
else {
printf ("unknown switch: %s\n",s);
exit (retcode);
}
}
else if (!cmd) cmd = s; /* first non-switch is command */
else if (!src) src = s; /* second non-switch is source */
else if (!dst) dst = s; /* third non-switch is destination */
else {
printf ("unknown argument: %s\n",s);
exit (retcode);
}
}
if (kwcopyp && ignorep) {
puts ("-kwcopy and -ignore are mutually exclusive");
exit (retcode);
}
if (!cmd) cmd = ""; /* prevent SEGV */
if (!strcmp (cmd,"check")) { /* check for new messages */
if (!src) src = "INBOX";
if (dst || merge || rwcopyp || kwcopyp || ignorep)
printf (usage2,pgm,usgchk,stdsw);
else if (mail_status (source = (*src == '{') ?
mail_open (NIL,src,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL)) : NIL,
src,SA_MESSAGES | SA_RECENT | SA_UNSEEN))
retcode = 0;
}
else if (!strcmp (cmd,"create")) {
if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
printf (usage2,pgm,usgcre,stdsw);
else if (mail_create (source = (*src == '{') ?
mail_open (NIL,src,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL)) : NIL,src))
retcode = 0;
}
else if (!strcmp (cmd,"delete")) {
if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
printf (usage2,pgm,usgdel,stdsw);
else if (mail_delete (source = (*src == '{') ?
mail_open (NIL,src,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL)) : NIL,src))
retcode = 0;
}
else if (!strcmp (cmd,"rename")) {
if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep)
printf (usage2,pgm,usgren,stdsw);
else if (mail_rename (source = (*src == '{') ?
mail_open (NIL,src,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL)) : NIL,src,dst))
retcode = 0;
}
else if ((i = !strcmp (cmd,"move")) || !strcmp (cmd,"copy")) {
if (!src || !dst || merge) printf (usage3,pgm,cmd,usgcpymov,stdsw);
else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
(debugp ? OP_DEBUG : NIL))) {
dest = NIL; /* open destination stream if network */
if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL)))) {
if (mbxcopy (source,dest,dst,T,i,merge)) retcode = 0;
}
}
}
else if ((i = !strcmp (cmd,"appenddelete")) || !strcmp (cmd,"append")) {
if (!src || !dst || merge) printf (usage3,pgm,cmd,usgappdel,stdsw);
else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
(debugp ? OP_DEBUG : NIL))) {
dest = NIL; /* open destination stream if network */
if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL)))) {
if (mbxcopy (source,dest,dst,NIL,i,merge)) retcode = 0;
}
}
}
else if (!strcmp (cmd,"prune")) {
if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep ||
!(criteria = prune_criteria (dst))) printf (usage2,pgm,usgprn,stdsw);
else if ((source = mail_open (NIL,src,(debugp ? OP_DEBUG : NIL))) &&
mail_search_full (source,NIL,criteria,SE_FREE)) {
for (m = 1, s = t = NIL, len = start = last = 0; m <= source->nmsgs; m++)
if (mail_elt (source,m)->searched) {
if (s) { /* continuing a range? */
if (m == last + 1) last = m;
else { /* no, end of previous range? */
if (last != start) sprintf (t,":%lu,%lu",last,m);
/* no, just this message */
else sprintf (t,",%lu",m);
start = last = m; /* either way, start new range */
/* running out of space? */
if ((len - (curlen = (t += strlen (t)) - s)) < 20) {
fs_resize ((void **) &s,len += MAILTMPLEN);
t = s + curlen; /* relocate current pointer */
}
}
}
else { /* first time, start new buffer */
s = (char *) fs_get (len = MAILTMPLEN);
sprintf (s,"%lu",start = last = m);
t = s + strlen (s); /* end of buffer */
}
}
/* finish last range if necessary */
if (last != start) sprintf (t,":%lu",last);
if (s) { /* delete/expunge any matching messages */
mail_flag (source,s,"\\Deleted",ST_SET);
m = source->nmsgs; /* get number of messages before purge */
mail_expunge (source);
printf ("%lu message(s) purged\n",m - source->nmsgs);
fs_give ((void **) &s); /* flush buffer */
}
else puts ("No matching messages, so nothing purged");
source = mail_close (source);
}
}
else if (!strcmp (cmd,"transfer")) {
if (!src || !dst) printf (usage2,pgm,usgxfr,stdsw);
else if ((*src == '{') && /* open source mailbox */
!(source = mail_open (NIL,src,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL))));
else if ((*dst == '{') && /* open destination server */
!(dest = mail_open (NIL,dst,OP_HALFOPEN |
(debugp ? OP_DEBUG : NIL))));
else if (!(f = tmpfile ())) puts ("can't open temporary file");
else {
if (verbosep) puts ("Listing mailboxes...");
if (dest) strcpy (strchr (strcpy (tmp,dest->mailbox),'}') + 1,
dp = strchr (dst,'}') + 1);
else {
dp = dst;
tmp[0] = '\0';
}
mail_list (dest,tmp,"");
rewind (f); /* list all mailboxes matching prefix */
if (ddelim < 0) { /* if server failed to give delimiter */
puts ("warning: unable to get destination hierarchy delimiter!");
ddelim = 0; /* default to none */
}
if (source) strcpy (strchr (strcpy (tmp,source->mailbox),'}') + 1,
strchr (src,'}') + 1);
else strcpy (tmp,src);
mail_list (source,tmp,"*");
rewind (f);
/* read back mailbox names */
for (retcode = 0; !retcode && (fgets (tmp,MAILTMPLEN-1,f)); ) {
if (t = strchr (tmp+1,'\n')) *t = '\0';
for (t = mbx,t1 = dest ? dest->mailbox : "",c = NIL; (c != '}') && *t1;
*t++ = c= *t1++);
for (t1 = dp; *t1; *t++ = *t1++);
/* point to name without delim or netspec */
t1 = source ? (strchr (tmp+1,'}') + 1) : tmp + 1;
/* src and mbx have different delimiters? */
if (ddelim && (ddelim != tmp[0]))
while (c = *t1++) { /* swap delimiters then */
if (c == ddelim) c = tmp[0] ? tmp[0] : 'x';
else if (c == tmp[0]) c = ddelim;
*t++ = c;
}
/* easy case */
else while (*t1) *t++ = *t1++;
*t++ = '\0';
if (verbosep) {
printf ("Copying %s\n => %s\n",tmp+1,mbx);
fflush (stdout);
}
if (source = mail_open (source,tmp+1,(debugp ? OP_DEBUG : NIL) |
(rwcopyp ? NIL : OP_READONLY))) {
if (!mbxcopy (source,dest,mbx,T,NIL,merge)) retcode = 1;
if (source->dtb->flags & DR_LOCAL) source = mail_close (source);
}
else printf ("can't open source mailbox %s\n",tmp+1);
}
}
}
else {
printf ("%s version %s.%s\n\n",pgm,CCLIENTVERSION,version);
printf (usage2,pgm,"command [switches] arguments",stdsw);
printf ("\nCommands:\n %s\n",usgchk);
puts (" ;; report number of messages and new messages");
printf (" %s\n",usgcre);
puts (" ;; create new mailbox");
printf (" %s\n",usgdel);
puts (" ;; delete existing mailbox");
printf (" %s\n",usgren);
puts (" ;; rename mailbox to a new name");
printf (" copy %s\n",usgcpymov);
printf (" move %s\n",usgcpymov);
puts (" ;; create new mailbox and copy/move messages");
printf (" append %s\n",usgappdel);
printf (" appenddelete %s\n",usgappdel);
puts (" ;; copy/move messages to existing mailbox");
printf (" %s\n",usgprn);
puts (" ;; prune mailbox of messages matching criteria");
printf (" %s\n",usgxfr);
puts (" ;; copy source hierarchy to destination");
puts (" ;; -merge modes are prompt, append, or suffix=xxxx");
}
/* close streams */
if (source) mail_close (source);
if (dest) mail_close (dest);
exit (retcode);
return retcode; /* stupid compilers */
}
/* Pruning criteria, somewhat extended from mail_criteria()
* Accepts: criteria
* Returns: search program if parse successful, else NIL
*/
SEARCHPGM *prune_criteria (char *criteria)
{
SEARCHPGM *pgm = NIL;
char *criterion,*r,tmp[MAILTMPLEN];
int f;
if (criteria) { /* only if criteria defined */
/* make writeable copy of criteria */
criteria = cpystr (criteria);
/* for each criterion */
for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r);
criterion; (criterion = strtok_r (NIL," ",&r))) {
f = NIL; /* init then scan the criterion */
switch (*ucase (criterion)) {
case 'A': /* possible ALL, ANSWERED */
if (!strcmp (criterion+1,"LL")) f = T;
else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T;
break;
case 'B': /* possible BCC, BEFORE, BODY */
if (!strcmp (criterion+1,"CC"))
f = mail_criteria_string (&pgm->bcc,&r);
else if (!strcmp (criterion+1,"EFORE"))
f = mail_criteria_date (&pgm->before,&r);
else if (!strcmp (criterion+1,"ODY"))
f = mail_criteria_string (&pgm->body,&r);
break;
case 'C': /* possible CC */
if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r);
break;
case 'D': /* possible DELETED, DRAFT */
if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T;
else if (!strcmp (criterion+1,"RAFT")) f = pgm->draft = T;
break;
case 'F': /* possible FLAGGED, FROM */
if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T;
else if (!strcmp (criterion+1,"ROM"))
f = mail_criteria_string (&pgm->from,&r);
break;
case 'K': /* possible KEYWORD */
if (!strcmp (criterion+1,"EYWORD"))
f = mail_criteria_string (&pgm->keyword,&r);
break;
case 'L': /* possible LARGER */
if (!strcmp (criterion+1,"ARGER"))
f = prune_criteria_number (&pgm->larger,&r);
case 'N': /* possible NEW */
if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T;
break;
case 'O': /* possible OLD, ON */
if (!strcmp (criterion+1,"LD")) f = pgm->old = T;
else if (!strcmp (criterion+1,"N"))
f = mail_criteria_date (&pgm->on,&r);
break;
case 'R': /* possible RECENT */
if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T;
break;
case 'S': /* possible SEEN, SENT*, SINCE, SMALLER,
SUBJECT */
if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T;
else if (!strncmp (criterion+1,"ENT",3)) {
if (!strcmp (criterion+4,"BEFORE"))
f = mail_criteria_date (&pgm->sentbefore,&r);
else if (!strcmp (criterion+4,"ON"))
f = mail_criteria_date (&pgm->senton,&r);
else if (!strcmp (criterion+4,"SINCE"))
f = mail_criteria_date (&pgm->sentsince,&r);
}
else if (!strcmp (criterion+1,"INCE"))
f = mail_criteria_date (&pgm->since,&r);
else if (!strcmp (criterion+1,"MALLER"))
f = prune_criteria_number (&pgm->smaller,&r);
else if (!strcmp (criterion+1,"UBJECT"))
f = mail_criteria_string (&pgm->subject,&r);
break;
case 'T': /* possible TEXT, TO */
if (!strcmp (criterion+1,"EXT"))
f = mail_criteria_string (&pgm->text,&r);
else if (!strcmp (criterion+1,"O"))
f = mail_criteria_string (&pgm->to,&r);
break;
case 'U': /* possible UN* */
if (criterion[1] == 'N') {
if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T;
else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T;
else if (!strcmp (criterion+2,"DRAFT")) f = pgm->undraft = T;
else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T;
else if (!strcmp (criterion+2,"KEYWORD"))
f = mail_criteria_string (&pgm->unkeyword,&r);
else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T;
}
break;
default: /* we will barf below */
break;
}
if (!f) { /* if can't identify criterion */
sprintf (tmp,"Unknown search criterion: %.30s",criterion);
MM_LOG (tmp,ERROR);
mail_free_searchpgm (&pgm);
break;
}
}
/* no longer need copy of criteria */
fs_give ((void **) &criteria);
}
return pgm;
}
/* Parse a number
* Accepts: pointer to integer to return
* pointer to strtok state
* Returns: T if successful, else NIL
*/
int prune_criteria_number (unsigned long *number,char **r)
{
char *t;
STRINGLIST *s = NIL;
/* parse the date and return fn if OK */
int ret = (mail_criteria_string (&s,r) &&
(*number = strtoul ((char *) s->text.data,&t,10)) && !*t) ?
T : NIL;
if (s) mail_free_stringlist (&s);
return ret;
}
/* Copy mailbox
* Accepts: stream open on source
* halfopen stream for destination or NIL
* destination mailbox name
* non-zero to create destination mailbox
* non-zero to delete messages from source after copying
* merge mode
* Returns: T if success, NIL if error
*/
int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
int mode)
{
char *s,tmp[MAILTMPLEN];
APPENDPACKAGE ap;
STRING st;
char *ndst = NIL;
int ret = NIL;
trycreate = NIL; /* no TRYCREATE yet */
if (create) while (!mail_create (dest,dst) && (mode != mAPPEND)) {
switch (mode) {
case mPROMPT: /* prompt user for new name */
tmp[0] = '\0';
while (!tmp[0]) { /* read name */
fputs ("alternative name: ",stdout);
fflush (stdout);
fgets (tmp,MAILTMPLEN-1,stdin);
if (s = strchr (tmp,'\n')) *s = '\0';
}
if (ndst) fs_give ((void **) &ndst);
ndst = cpystr (tmp);
break;
case mSUFFIX: /* try again with new suffix */
if (ndst) fs_give ((void **) &ndst);
sprintf (ndst = (char *) fs_get (strlen (dst) + strlen (suffix) + 1),
"%s%s",dst,suffix);
printf ("retry to create %s\n",ndst);
mode = mPROMPT; /* switch to prompt mode if name fails */
break;
case NIL: /* not merging */
return NIL;
}
if (ndst) dst = ndst; /* if alternative name given, use it */
}
if (kwcopyp) {
int i;
size_t len;
char *dummymsg = "Date: Thu, 18 May 2006 00:00 -0700\r\nFrom: dummy@example.com\r\nSubject: dummy\r\n\r\ndummy\r\n";
for (i = 0,len = 0; i < NUSERFLAGS; ++i)
if (source->user_flags[i]) len += strlen (source->user_flags[i]) + 1;
if (len) { /* easy if no user flags to copy... */
char *t;
char *tail = "\\Deleted)";
char *flags = (char *) fs_get (1 + len + strlen (tail) + 1);
s = flags; *s++ = '(';
for (i = 0; i < NUSERFLAGS; ++i) if (t = source->user_flags[i]) {
while (*t) *s++ = *t++;
*s++ = ' ';
}
strcpy (s,tail); /* terminate flags list */
if ((dst[0] == '#') && ((dst[1] == 'D') || (dst[1] == 'd')) &&
((dst[2] == 'R') || (dst[2] == 'r')) &&
((dst[3] == 'I') || (dst[3] == 'i')) &&
((dst[4] == 'V') || (dst[4] == 'v')) &&
((dst[5] == 'E') || (dst[5] == 'e')) &&
((dst[6] == 'R') || (dst[6] == 'r')) && (dst[7] == '.') &&
(t = strchr (dst+8,'/'))) ++t;
else t = dst;
INIT (&st,mail_string,dummymsg,strlen (dummymsg));
if (!(mail_append (dest,dst,&st) &&
(dest = mail_open (dest,t,debugp ? OP_DEBUG : NIL)))) {
fs_give ((void **) &flags);
return NIL;
}
mail_setflag (dest,"*",flags);
mail_expunge (dest);
fs_give ((void **) &flags);
}
}
if (source->nmsgs) { /* non-empty source */
if (verbosep) printf ("%s [%lu message(s)] => %s\n",
source->mailbox,source->nmsgs,dst);
ap.stream = source; /* prepare append package */
ap.msgno = 0;
ap.msgmax = source->nmsgs;
ap.flags = ap.date = NIL;
ap.message = &st;
/* make sure we have all messages */
sprintf (tmp,"1:%lu",ap.msgmax);
mail_fetchfast (source,tmp);
if (mail_append_multiple (dest,dst,mm_append,(void *) &ap)) {
--ap.msgno; /* make sure user knows it won */
if (verbosep) printf ("[Ok %lu messages(s)]\n",ap.msgno);
if (del && ap.msgno) { /* delete source messages */
sprintf (tmp,"1:%lu",ap.msgno);
mail_flag (source,tmp,"\\Deleted",ST_SET);
/* flush moved messages */
mail_expunge (source);
}
ret = T;
}
else if ((mode == mAPPEND) && trycreate)
ret = mbxcopy (source,dest,dst,create,del,mPROMPT);
else if (verbosep) puts ("[Failed]");
}
else { /* empty source */
if (verbosep) printf ("%s [empty] => %s\n",source->mailbox,dst);
ret = T;
}
if (ndst) fs_give ((void **) &ndst);
return ret;
}
/* Append callback
* Accepts: mail stream
* append package
* pointer to return flags
* pointer to return date
* pointer to return message stringstruct
* Returns: T on success
*/
long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date,
STRING **message)
{
char *t,*t1,tmp[MAILTMPLEN];
unsigned long u;
MESSAGECACHE *elt;
APPENDPACKAGE *ap = (APPENDPACKAGE *) data;
*flags = *date = NIL; /* assume no flags or date */
if (ap->flags) fs_give ((void **) &ap->flags);
if (ap->date) fs_give ((void **) &ap->date);
mail_gc (ap->stream,GC_TEXTS);
if (++ap->msgno <= ap->msgmax) {
/* initialize flag string */
memset (t = tmp,0,MAILTMPLEN);
/* output system flags */
if ((elt = mail_elt (ap->stream,ap->msgno))->seen) strcat (t," \\Seen");
if (elt->deleted) strcat (t," \\Deleted");
if (elt->flagged) strcat (t," \\Flagged");
if (elt->answered) strcat (t," \\Answered");
if (elt->draft) strcat (t," \\Draft");
/* any user flags? */
if (!ignorep && (u = elt->user_flags)) do
if ((t1 = ap->stream->user_flags[find_rightmost_bit (&u)]) &&
(MAILTMPLEN - ((t += strlen (t)) - tmp)) > (long) (2 + strlen (t1))){
*t++ = ' '; /* space delimiter */
strcpy (t,t1); /* copy the user flag */
}
while (u); /* until no more user flags */
*flags = ap->flags = cpystr (tmp + 1);
*date = ap->date = cpystr (mail_date (tmp,elt));
*message = ap->message; /* message stringstruct */
INIT (ap->message,mstring,(void *) ap,elt->rfc822_size);
}
else *message = NIL; /* all done */
return LONGT;
}
/* Co-routines from MAIL library */
/* Message matches a search
* Accepts: MAIL stream
* message number
*/
void mm_searched (MAILSTREAM *stream,unsigned long msgno)
{
/* dummy routine */
}
/* Message exists (i.e. there are that many messages in the mailbox)
* Accepts: MAIL stream
* message number
*/
void mm_exists (MAILSTREAM *stream,unsigned long number)
{
/* dummy routine */
}
/* Message expunged
* Accepts: MAIL stream
* message number
*/
void mm_expunged (MAILSTREAM *stream,unsigned long number)
{
/* dummy routine */
}
/* Message flags update seen
* Accepts: MAIL stream
* message number
*/
void mm_flags (MAILSTREAM *stream,unsigned long number)
{
/* dummy routine */
}
/* Mailbox found
* Accepts: MAIL stream
* hierarchy delimiter
* mailbox name
* mailbox attributes
*/
void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
/* note destination delimiter */
if (ddelim < 0) ddelim = delimiter;
/* if got a selectable name */
else if (!(attributes & LATT_NOSELECT) && *name)
fprintf (f,"%c%s\n",delimiter,name);
}
/* Subscribe mailbox found
* Accepts: MAIL stream
* hierarchy delimiter
* mailbox name
* mailbox attributes
*/
void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
/* dummy routine */
}
/* Mailbox status
* Accepts: MAIL stream
* mailbox name
* mailbox status
*/
void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
{
if (status->recent || status->unseen)
printf ("%lu new message(s) (%lu unseen),",status->recent,status->unseen);
else fputs ("No new messages,",stdout);
printf (" %lu total in %s\n",status->messages,mailbox);
}
/* Notification event
* Accepts: MAIL stream
* string to log
* error flag
*/
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
if (!errflg && (string[0] == '[') &&
((string[1] == 'T') || (string[1] == 't')) &&
((string[2] == 'R') || (string[2] == 'r')) &&
((string[3] == 'Y') || (string[3] == 'y')) &&
((string[4] == 'C') || (string[4] == 'c')) &&
((string[5] == 'R') || (string[5] == 'r')) &&
((string[6] == 'E') || (string[6] == 'e')) &&
((string[7] == 'A') || (string[7] == 'a')) &&
((string[8] == 'T') || (string[8] == 't')) &&
((string[9] == 'E') || (string[9] == 'e')) &&
(string[10] == ']'))
trycreate = T;
mm_log (string,errflg); /* just do mm_log action */
}
/* Log an event for the user to see
* Accepts: string to log
* error flag
*/
void mm_log (char *string,long errflg)
{
switch (errflg) {
case BYE:
case NIL: /* no error */
if (verbosep) fprintf (stderr,"[%s]\n",string);
break;
case PARSE: /* parsing problem */
case WARN: /* warning */
fprintf (stderr,"warning: %s\n",string);
break;
case ERROR: /* error */
default:
fprintf (stderr,"%s\n",string);
break;
}
}
/* Log an event to debugging telemetry
* Accepts: string to log
*/
void mm_dlog (char *string)
{
fprintf (stderr,"%s\n",string);
}
/* Get user name and password for this host
* Accepts: parse of network mailbox name
* where to return user name
* where to return password
* trial count
*/
void mm_login (NETMBX *mb,char *username,char *password,long trial)
{
char *s,tmp[MAILTMPLEN];
sprintf (s = tmp,"{%s/%s",mb->host,mb->service);
if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",
strcpy (username,mb->user));
if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser);
if (*mb->user) strcat (s = tmp,"} password:");
else {
printf ("%s} username: ",tmp);
fgets (username,NETMAXUSER-1,stdin);
username[NETMAXUSER-1] = '\0';
if (s = strchr (username,'\n')) *s = '\0';
s = "password: ";
}
strcpy (password,getpass (s));
}
/* About to enter critical code
* Accepts: stream
*/
void mm_critical (MAILSTREAM *stream)
{
critical = T; /* note in critical code */
}
/* About to exit critical code
* Accepts: stream
*/
void mm_nocritical (MAILSTREAM *stream)
{
critical = NIL; /* note not in critical code */
}
/* Disk error found
* Accepts: stream
* system error code
* flag indicating that mailbox may be clobbered
* Returns: T if user wants to abort
*/
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
{
return T;
}
/* Log a fatal error event
* Accepts: string to log
*/
void mm_fatal (char *string)
{
fprintf (stderr,"FATAL: %s\n",string);
}

50
src/mailutil/makefile.nt Normal file
View File

@@ -0,0 +1,50 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MAILUTIL Makefile for Windows 9x and Windows NT
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
CFLAGS= -I$C /MT /W3 /DWIN32 /D_WIN32_WINNT=0x0400 -nologo $(EXTRACFLAGS)
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
mailutil: $(CCLIENTLIB) mailutil.obj
LINK /NOLOGO mailutil.obj $(LIBS)
mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

51
src/mailutil/makefile.ntk Normal file
View File

@@ -0,0 +1,51 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MAILUTIL Makefile for Windows 9x and Windows NT + Kerberos
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
mailutil: $(CCLIENTLIB) mailutil.obj
LINK /NOLOGO mailutil.obj $(LIBS)
mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

49
src/mailutil/makefile.w2k Normal file
View File

@@ -0,0 +1,49 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MAILUTIL Makefile for Windows 2000/XP
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
OSCOMPAT = /DWIN32
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
mailutil: $(CCLIENTLIB) mailutil.obj
LINK /NOLOGO mailutil.obj $(LIBS)
mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

51
src/mlock/Makefile Normal file
View File

@@ -0,0 +1,51 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MLOCK Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 8 February 1999
# Last Edited: 30 August 2006
C = ../c-client
SHELL = /bin/sh
# Get local definitions from c-client directory
CC = `cat $C/CCTYPE`
CFLAGS = `cat $C/CFLAGS`
all: mlock
mlock: mlock.o
$(CC) $(CFLAGS) -o mlock mlock.o
install: mlock
chgrp mail mlock
chmod 3711 mlock
cp -p mlock /etc/mlock
clean:
rm -f *.o mlock || true
# A monument to a hack of long ago and far away...
love:
@echo 'not war?'

175
src/mlock/mlock.c Normal file
View File

@@ -0,0 +1,175 @@
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Standalone Mailbox Lock program
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 8 February 1999
* Last Edited: 3 March 2008
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sysexits.h>
#include <syslog.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>
#include <netdb.h>
#include <ctype.h>
#include <string.h>
#define LOCKTIMEOUT 5 /* lock timeout in minutes */
#define LOCKPROTECTION 0664
#ifndef MAXHOSTNAMELEN /* Solaris still sucks */
#define MAXHOSTNAMELEN 256
#endif
/* Fatal error
* Accepts: Message string
* exit code
* Returns: code
*/
int die (char *msg,int code)
{
syslog (LOG_NOTICE,"(%u) %s",code,msg);
write (1,"?",1); /* indicate "impossible" failure */
return code;
}
int main (int argc,char *argv[])
{
int ld,i;
int tries = LOCKTIMEOUT * 60 - 1;
char *s,*dir,*file,*lock,*hitch,tmp[1024];
size_t dlen,len;
struct stat sb,fsb;
struct group *grp = getgrnam ("mail");
/* get syslog */
openlog (argv[0],LOG_PID,LOG_MAIL);
if (!grp || (grp->gr_gid != getegid ()))
return die ("not setgid mail",EX_USAGE);
if (argc != 3) return die ("invalid arguments",EX_USAGE);
for (s = argv[1]; *s; s++)
if (!isdigit (*s)) return die ("invalid fd",EX_USAGE);
/* find directory */
if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1])
return die ("invalid path",EX_USAGE);
/* calculate lengths of directory and file */
if (!(dlen = file - argv[2])) dlen = 1;
len = strlen (++file);
/* make buffers */
dir = (char *) malloc (dlen + 1);
lock = (char *) malloc (len + 6);
hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN);
if (!dir || !lock || !hitch) return die ("malloc failure",errno);
strncpy (dir,argv[2],dlen); /* connect to desired directory */
dir[dlen] = '\0';
printf ("dir=%s, file=%s\n",dir,file);
chdir (dir);
/* get device/inode of file descriptor */
if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno);
/* better be a regular file */
if ((fsb.st_mode & S_IFMT) != S_IFREG)
return die ("fd not regular file",EX_USAGE);
/* now get device/inode of file */
if (lstat (file,&sb)) return die ("lstat failure",errno);
/* does it match? */
if ((sb.st_mode & S_IFMT) != S_IFREG)
return die ("name not regular file",EX_USAGE);
if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino))
return die ("fd and name different",EX_USAGE);
/* build lock filename */
sprintf (lock,"%s.lock",file);
if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG))
return die ("existing lock not regular file",EX_NOPERM);
do { /* until OK or out of tries */
if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60)))
unlink (lock); /* time out lock if enough time has passed */
/* SUN-OS had an NFS
* As kludgy as an albatross;
* And everywhere that it was installed,
* It was a total loss.
* -- MRC 9/25/91
*/
/* build hitching post file name */
sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0),
(unsigned long) getpid ());
len = strlen (hitch); /* append local host name */
gethostname (hitch + len,MAXHOSTNAMELEN);
/* try to get hitching-post file */
if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
/* make sure others can break the lock */
chmod (hitch,LOCKPROTECTION);
/* get device/inode of hitch file */
if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno);
close (ld); /* close the hitching-post */
/* Note: link() may return an error even if it actually succeeded. So we
* always check for success via the link count, and ignore the error if
* the link count is right.
*/
/* tie hitching-post to lock */
i = link (hitch,lock) ? errno : 0;
/* success if link count now 2 */
if (stat (hitch,&sb) || (sb.st_nlink != 2) ||
(fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) {
ld = -1; /* failed to hitch */
if (i == EPERM) { /* was it because links not allowed? */
/* Probably a FAT filesystem on Linux. It can't be NFS, so try
* creating the lock file directly.
*/
if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
/* get device/inode of lock file */
if (fstat (ld,&fsb)) return die ("lock fstat failure",errno);
close (ld); /* close the file */
}
/* give up immediately if protection failure */
else if (errno != EEXIST) tries = 0;
}
}
unlink (hitch); /* flush hitching post */
}
/* give up immediately if protection failure */
else if (errno == EACCES) tries = 0;
if (ld < 0) { /* lock failed */
if (tries--) sleep (1); /* sleep 1 second and try again */
else {
write (1,"-",1); /* hard failure */
return EX_CANTCREAT;
}
}
} while (ld < 0);
write (1,"+",1); /* indicate that all is well */
read (0,tmp,1); /* read continue signal from parent */
/* flush the lock file */
if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) &&
(fsb.st_ino == sb.st_ino)) unlink (lock);
else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock);
return EX_OK;
}

53
src/mtest/Makefile Normal file
View File

@@ -0,0 +1,53 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MTEST Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ../c-client
CCLIENTLIB = $C/c-client.a
SHELL = /bin/sh
# Get local definitions from c-client directory
CC = `cat $C/CCTYPE`
CFLAGS = -I$C `cat $C/CFLAGS`
LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
all: mtest
mtest: $(CCLIENTLIB) mtest.o
$(CC) $(CFLAGS) -o mtest mtest.o $(LDFLAGS)
mtest.o: $C/mail.h $C/misc.h $C/osdep.h $C/rfc822.h $C/smtp.h $C/nntp.h
$(CCLIENTLIB):
cd $C;make
clean:
rm -f *.o mtest || true
# A monument to a hack of long ago and far away...
love:
@echo 'not war?'

49
src/mtest/makefile.nt Normal file
View File

@@ -0,0 +1,49 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MTEST Makefile for Windows 9x and Windows NT
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
mtest: $(CCLIENTLIB) mtest.obj
LINK /NOLOGO mtest.obj $(LIBS)
mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

51
src/mtest/makefile.ntk Normal file
View File

@@ -0,0 +1,51 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MTEST Makefile for Windows 9x and Windows NT + Kerberos
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
mtest: $(CCLIENTLIB) mtest.obj
LINK /NOLOGO mtest.obj $(LIBS)
mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

53
src/mtest/makefile.os2 Normal file
View File

@@ -0,0 +1,53 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MTEST Makefile
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
# Thanks to Nicholas Paul Sheppard who contributed the original version
CC = gcc
CFLAGS = -O2 -Zomf
LD = gcc
LDFLAGS = -s -Zomf -Zcrtdll
C = ..\c-client
CCLIENTLIB = $C\\c-client.lib
LIBS = $(CCLIENTLIB) -l socket
mtest.exe: $(CCLIENTLIB) mtest.obj
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(CCLIENTLIB):
@echo Make c-client first
false
mtest.obj: mtest.c $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h
$(CC) $(CFLAGS) -I$C -o $@ -c $<
clean:
if exist *.obj del *.obj
# A monument to a hack of long ago and far away...
love:
@echo not war?

49
src/mtest/makefile.w2k Normal file
View File

@@ -0,0 +1,49 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: MTEST Makefile for Windows 2000/XP
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 25 February 1996
# Last Edited: 30 August 2006
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
OSCOMPAT = /DWIN32
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
mtest: $(CCLIENTLIB) mtest.obj
LINK /NOLOGO mtest.obj $(LIBS)
mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
$(CCLIENTLIB):
@echo Make c-client first
false
clean:
del *.obj *.exe *.lib *.exp || rem
# A monument to a hack of long ago and far away...
love:
@echo not war?

813
src/mtest/mtest.c Normal file
View File

@@ -0,0 +1,813 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Mail library test program
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 8 July 1988
* Last Edited: 5 November 2007
*
* This original version of this file is
* Copyright 1988 Stanford University
* and was developed in the Symbolic Systems Resources Group of the Knowledge
* Systems Laboratory at Stanford University in 1987-88, and was funded by the
* Biomedical Research Technology Program of the NationalInstitutes of Health
* under grant number RR-00785.
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include "c-client.h"
#include "imap4r1.h"
/* Excellent reasons to hate ifdefs, and why my real code never uses them */
#ifndef unix
# define unix 0
#endif
#if unix
# define UNIXLIKE 1
# define MACOS 0
# include <pwd.h>
#else
# define UNIXLIKE 0
# ifdef noErr
# define MACOS 1
# include <Memory.h>
# else
# define MACOS 0
# endif
#endif
char *curhst = NIL; /* currently connected host */
char *curusr = NIL; /* current login user */
char personalname[MAILTMPLEN]; /* user's personal name */
static char *hostlist[] = { /* SMTP server host list */
"mailhost",
"localhost",
NIL
};
static char *newslist[] = { /* Netnews server host list */
"news",
NIL
};
int main (void);
void mm (MAILSTREAM *stream,long debug);
void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
unsigned long msgno);
void header (MAILSTREAM *stream,long msgno);
void display_body (BODY *body,char *pfx,long i);
void status (MAILSTREAM *stream);
void prompt (char *msg,char *txt);
void smtptest (long debug);
/* Main program - initialization */
int main ()
{
MAILSTREAM *stream = NIL;
void *sdb = NIL;
char *s,tmp[MAILTMPLEN];
long debug;
#include "linkage.c"
#if MACOS
{
size_t *base = (size_t *) 0x000908;
/* increase stack size on a Mac */
SetApplLimit ((Ptr) (*base - (size_t) 65535L));
}
#endif
curusr = cpystr (((s = myusername ()) && *s) ? s : "somebody");
#if UNIXLIKE
{
char *suffix;
struct passwd *pwd = getpwnam (curusr);
if (pwd) {
strcpy (tmp,pwd->pw_gecos);
/* dyke out the office and phone poop */
if (suffix = strchr (tmp,',')) suffix[0] = '\0';
strcpy (personalname,tmp);/* make a permanent copy of it */
}
else personalname[0] = '\0';
}
#else
personalname[0] = '\0';
#endif
curhst = cpystr (mylocalhost ());
puts ("MTest -- C client test program");
if (!*personalname) prompt ("Personal name: ",personalname);
/* user wants protocol telemetry? */
prompt ("Debug protocol (y/n)?",tmp);
ucase (tmp);
debug = (tmp[0] == 'Y') ? T : NIL;
do {
prompt ("Mailbox ('?' for help): ",tmp);
if (!strcmp (tmp,"?")) {
puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox");
puts ("Known local mailboxes:");
mail_list (NIL,NIL,"%");
if (s = sm_read (&sdb)) {
puts ("Local subscribed mailboxes:");
do (mm_lsub (NIL,NIL,s,NIL));
while (s = sm_read (&sdb));
}
puts ("or just hit return to quit");
}
else if (tmp[0]) stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
} while (!stream && tmp[0]);
mm (stream,debug); /* run user interface if opened */
#if MACOS
/* clean up resolver */
if (resolveropen) CloseResolver ();
#endif
return NIL;
}
/* MM command loop
* Accepts: MAIL stream
*/
void mm (MAILSTREAM *stream,long debug)
{
void *sdb = NIL;
char cmd[MAILTMPLEN];
char *s,*arg;
unsigned long i;
unsigned long last = 0;
BODY *body;
status (stream); /* first report message status */
while (stream) {
prompt ("MTest>",cmd); /* prompt user, get command */
/* get argument */
if (arg = strchr (cmd,' ')) *arg++ = '\0';
switch (*ucase (cmd)) { /* dispatch based on command */
case 'B': /* Body command */
if (arg) last = atoi (arg);
else if (!last) {
puts ("?Missing message number");
break;
}
if (last && (last <= stream->nmsgs)) {
mail_fetchstructure (stream,last,&body);
if (body) display_body (body,NIL,(long) 0);
else puts ("%No body information available");
}
else puts ("?Bad message number");
break;
case 'C': /* Check command */
mail_check (stream);
status (stream);
break;
case 'D': /* Delete command */
if (arg) last = atoi (arg);
else {
if (last == 0) {
puts ("?Missing message number");
break;
}
arg = cmd;
sprintf (arg,"%lu",last);
}
if (last && (last <= stream->nmsgs))
mail_setflag (stream,arg,"\\DELETED");
else puts ("?Bad message number");
break;
case 'E': /* Expunge command */
mail_expunge (stream);
last = 0;
break;
case 'F': /* Find command */
if (!arg) {
arg = "%";
if (s = sm_read (&sdb)) {
puts ("Local network subscribed mailboxes:");
do if (*s == '{') (mm_lsub (NIL,NIL,s,NIL));
while (s = sm_read (&sdb));
}
}
puts ("Subscribed mailboxes:");
mail_lsub (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
NIL,arg);
puts ("Known mailboxes:");
mail_list (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
NIL,arg);
break;
case 'G':
mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT);
break;
case 'H': /* Headers command */
if (arg) {
if (!(last = atoi (arg))) {
mail_search (stream,arg);
for (i = 1; i <= stream->nmsgs; ++i)
if (mail_elt (stream,i)->searched) header (stream,i);
break;
}
}
else if (last == 0) {
puts ("?Missing message number");
break;
}
if (last && (last <= stream->nmsgs)) header (stream,last);
else puts ("?Bad message number");
break;
case 'L': /* Literal command */
if (arg) last = atoi (arg);
else if (!last) {
puts ("?Missing message number");
break;
}
if (last && (last <= stream->nmsgs))
puts (mail_fetch_message (stream,last,NIL,NIL));
else puts ("?Bad message number");
break;
case 'M':
mail_status (NIL,arg ? arg : stream->mailbox,
SA_MESSAGES|SA_RECENT|SA_UNSEEN|SA_UIDNEXT|SA_UIDVALIDITY);
break;
case 'N': /* New mailbox command */
if (!arg) {
puts ("?Missing mailbox");
break;
}
/* get the new mailbox */
while (!(stream = mail_open (stream,arg,debug))) {
prompt ("Mailbox: ",arg);
if (!arg[0]) break;
}
last = 0;
status (stream);
break;
case 'O': /* Overview command */
if (!arg) {
puts ("?Missing UID");
break;
}
mail_fetch_overview (stream,arg,overview_header);
break;
case 'P': /* Ping command */
mail_ping (stream);
status (stream);
break;
case 'Q': /* Quit command */
mail_close (stream);
stream = NIL;
break;
case 'S': /* Send command */
smtptest (debug);
break;
case '\0': /* null command (type next message) */
if (!last || (last++ >= stream->nmsgs)) {
puts ("%No next message");
break;
}
case 'T': /* Type command */
if (arg) last = atoi (arg);
else if (!last) {
puts ("?Missing message number");
break;
}
if (last && (last <= stream->nmsgs)) {
STRINGLIST *lines = mail_newstringlist ();
STRINGLIST *cur = lines;
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr ("Date")));
cur = cur->next = mail_newstringlist ();
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr ("From")));
cur = cur->next = mail_newstringlist ();
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr (">From")));
cur = cur->next = mail_newstringlist ();
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr ("Subject")));
cur = cur->next = mail_newstringlist ();
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr ("To")));
cur = cur->next = mail_newstringlist ();
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr ("cc")));
cur = cur->next = mail_newstringlist ();
cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
cpystr ("Newsgroups")));
printf ("%s",mail_fetchheader_full (stream,last,lines,NIL,NIL));
puts (mail_fetchtext (stream,last));
mail_free_stringlist (&lines);
}
else puts ("?Bad message number");
break;
case 'U': /* Undelete command */
if (arg) last = atoi (arg);
else {
if (!last) {
puts ("?Missing message number");
break;
}
arg = cmd;
sprintf (arg,"%lu",last);
}
if (last > 0 && last <= stream->nmsgs)
mail_clearflag (stream,arg,"\\DELETED");
else puts ("?Bad message number");
break;
case 'X': /* Xit command */
mail_expunge (stream);
mail_close (stream);
stream = NIL;
break;
case '+':
mail_debug (stream); debug = T;
break;
case '-':
mail_nodebug (stream); debug = NIL;
break;
case '?': /* ? command */
puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Literal,");
puts (" MailboxStatus, New Mailbox, Overview, Ping, Quit, Send, Type,");
puts ("Undelete, Xit, +, -, or <RETURN> for next message");
break;
default: /* bogus command */
printf ("?Unrecognized command: %s\n",cmd);
break;
}
}
}
/* MM display header
* Accepts: IMAP2 stream
* message number
*/
void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
unsigned long msgno)
{
if (ov) {
unsigned long i;
char *t,tmp[MAILTMPLEN];
ADDRESS *adr;
MESSAGECACHE *elt = mail_elt (stream,msgno);
MESSAGECACHE selt;
tmp[0] = elt->recent ? (elt->seen ? 'R': 'N') : ' ';
tmp[1] = (elt->recent | elt->seen) ? ' ' : 'U';
tmp[2] = elt->flagged ? 'F' : ' ';
tmp[3] = elt->answered ? 'A' : ' ';
tmp[4] = elt->deleted ? 'D' : ' ';
mail_parse_date (&selt,ov->date);
sprintf (tmp+5,"%4lu) ",elt->msgno);
mail_date (tmp+11,&selt);
tmp[17] = ' ';
tmp[18] = '\0';
memset (tmp+18,' ',(size_t) 20);
tmp[38] = '\0'; /* tie off with null */
/* get first from address from envelope */
for (adr = ov->from; adr && !adr->host; adr = adr->next);
if (adr) { /* if a personal name exists use it */
if (!(t = adr->personal))
sprintf (t = tmp+400,"%s@%s",adr->mailbox,adr->host);
memcpy (tmp+18,t,(size_t) min (20,(long) strlen (t)));
}
strcat (tmp," ");
if (i = elt->user_flags) {
strcat (tmp,"{");
while (i) {
strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
if (i) strcat (tmp," ");
}
strcat (tmp,"} ");
}
sprintf (tmp + strlen (tmp),"%.25s (%lu chars)",
ov->subject ? ov->subject : " ",ov->optional.octets);
puts (tmp);
}
else printf ("%%No overview for UID %lu\n",uid);
}
/* MM display header
* Accepts: IMAP2 stream
* message number
*/
void header (MAILSTREAM *stream,long msgno)
{
unsigned long i;
char tmp[MAILTMPLEN];
char *t;
MESSAGECACHE *cache = mail_elt (stream,msgno);
mail_fetchstructure (stream,msgno,NIL);
tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
tmp[2] = cache->flagged ? 'F' : ' ';
tmp[3] = cache->answered ? 'A' : ' ';
tmp[4] = cache->deleted ? 'D' : ' ';
sprintf (tmp+5,"%4lu) ",cache->msgno);
mail_date (tmp+11,cache);
tmp[17] = ' ';
tmp[18] = '\0';
mail_fetchfrom (tmp+18,stream,msgno,(long) 20);
strcat (tmp," ");
if (i = cache->user_flags) {
strcat (tmp,"{");
while (i) {
strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
if (i) strcat (tmp," ");
}
strcat (tmp,"} ");
}
mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25);
sprintf (t += strlen (t)," (%lu chars)",cache->rfc822_size);
puts (tmp);
}
/* MM display body
* Accepts: BODY structure pointer
* prefix string
* index
*/
void display_body (BODY *body,char *pfx,long i)
{
char tmp[MAILTMPLEN];
char *s = tmp;
PARAMETER *par;
PART *part; /* multipart doesn't have a row to itself */
if (body->type == TYPEMULTIPART) {
/* if not first time, extend prefix */
if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
else tmp[0] = '\0';
for (i = 0,part = body->nested.part; part; part = part->next)
display_body (&part->body,tmp,i++);
}
else { /* non-multipart, output oneline descriptor */
if (!pfx) pfx = ""; /* dummy prefix if top level */
sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype);
if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
if (par = body->parameter) do
sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
while (par = par->next);
if (body->id) sprintf (s += strlen (s),", id = %s",body->id);
switch (body->type) { /* bytes or lines depending upon body type */
case TYPEMESSAGE: /* encapsulated message */
case TYPETEXT: /* plain text */
sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
break;
default:
sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
break;
}
puts (tmp); /* output this line */
/* encapsulated message? */
if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822") &&
(body = body->nested.msg->body)) {
if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1);
else { /* build encapsulation prefix */
sprintf (tmp,"%s%ld.",pfx,i);
display_body (body,tmp,(long) 0);
}
}
}
}
/* MM status report
* Accepts: MAIL stream
*/
void status (MAILSTREAM *stream)
{
unsigned long i;
char *s,date[MAILTMPLEN];
THREADER *thr;
AUTHENTICATOR *auth;
rfc822_date (date);
puts (date);
if (stream) {
if (stream->mailbox)
printf (" %s mailbox: %s, %lu messages, %lu recent\n",
stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
else puts ("%No mailbox is open on this stream");
if (stream->user_flags[0]) {
printf ("Keywords: %s",stream->user_flags[0]);
for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
printf (", %s",stream->user_flags[i]);
puts ("");
}
if (!strcmp (stream->dtb->name,"imap")) {
if (LEVELIMAP4rev1 (stream)) s = "IMAP4rev1 (RFC 3501)";
else if (LEVEL1730 (stream)) s = "IMAP4 (RFC 1730)";
else if (LEVELIMAP2bis (stream)) s = "IMAP2bis";
else if (LEVEL1176 (stream)) s = "IMAP2 (RFC 1176)";
else s = "IMAP2 (RFC 1064)";
printf ("%s server %s\n",s,imap_host (stream));
if (LEVELIMAP4 (stream)) {
if (i = imap_cap (stream)->auth) {
s = "";
printf ("Mutually-supported SASL mechanisms:");
while (auth = mail_lookup_auth (find_rightmost_bit (&i) + 1)) {
printf (" %s",auth->name);
if (!strcmp (auth->name,"PLAIN"))
s = "\n [LOGIN will not be listed here if PLAIN is supported]";
}
puts (s);
}
printf ("Supported standard extensions:\n");
if (LEVELACL (stream)) puts (" Access Control lists (RFC 2086)");
if (LEVELQUOTA (stream)) puts (" Quotas (RFC 2087)");
if (LEVELLITERALPLUS (stream))
puts (" Non-synchronizing literals (RFC 2088)");
if (LEVELIDLE (stream)) puts (" IDLE unsolicited update (RFC 2177)");
if (LEVELMBX_REF (stream)) puts (" Mailbox referrals (RFC 2193)");
if (LEVELLOG_REF (stream)) puts (" Login referrals (RFC 2221)");
if (LEVELANONYMOUS (stream)) puts (" Anonymous access (RFC 2245)");
if (LEVELNAMESPACE (stream)) puts (" Multiple namespaces (RFC 2342)");
if (LEVELUIDPLUS (stream)) puts (" Extended UID behavior (RFC 2359)");
if (LEVELSTARTTLS (stream))
puts (" Transport Layer Security (RFC 2595)");
if (LEVELLOGINDISABLED (stream))
puts (" LOGIN command disabled (RFC 2595)");
if (LEVELID (stream))
puts (" Implementation identity negotiation (RFC 2971)");
if (LEVELCHILDREN (stream))
puts (" LIST children announcement (RFC 3348)");
if (LEVELMULTIAPPEND (stream))
puts (" Atomic multiple APPEND (RFC 3502)");
if (LEVELBINARY (stream))
puts (" Binary body content (RFC 3516)");
if (LEVELUNSELECT (stream)) puts (" Mailbox unselect (RFC 3691)");
if (LEVELURLAUTH (stream))
puts (" URL authenticated fetch (RFC 4467)");
if (LEVELCATENATE (stream)) puts (" Catenation (RFC 4469)");
if (LEVELCONDSTORE (stream)) puts (" Conditional STORE (RFC 4551)");
if (LEVELESEARCH (stream)) puts (" Extended SEARCH (RFC 4731)");
puts ("Supported draft extensions:");
if (LEVELSASLIR (stream)) puts (" SASL initial client response");
if (LEVELSORT (stream)) puts (" Server-based sorting");
if (LEVELTHREAD (stream)) {
printf (" Server-based threading:");
for (thr = imap_cap (stream)->threader; thr; thr = thr->next)
printf (" %s",thr->name);
putchar ('\n');
}
if (LEVELSCAN (stream)) puts (" Mailbox text scan");
if (i = imap_cap (stream)->extlevel) {
printf ("Supported BODYSTRUCTURE extensions:");
switch (i) {
case BODYEXTLOC: printf (" location");
case BODYEXTLANG: printf (" language");
case BODYEXTDSP: printf (" disposition");
case BODYEXTMD5: printf (" MD5\n");
}
}
}
else putchar ('\n');
}
}
}
/* Prompt user for input
* Accepts: pointer to prompt message
* pointer to input buffer
*/
void prompt (char *msg,char *txt)
{
printf ("%s",msg);
gets (txt);
}
/* Interfaces to C-client */
void mm_searched (MAILSTREAM *stream,unsigned long number)
{
}
void mm_exists (MAILSTREAM *stream,unsigned long number)
{
}
void mm_expunged (MAILSTREAM *stream,unsigned long number)
{
}
void mm_flags (MAILSTREAM *stream,unsigned long number)
{
}
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
mm_log (string,errflg);
}
void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
{
putchar (' ');
if (delimiter) putchar (delimiter);
else fputs ("NIL",stdout);
putchar (' ');
fputs (mailbox,stdout);
if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
if (attributes & LATT_MARKED) fputs (", marked",stdout);
if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
putchar ('\n');
}
void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
{
putchar (' ');
if (delimiter) putchar (delimiter);
else fputs ("NIL",stdout);
putchar (' ');
fputs (mailbox,stdout);
if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
if (attributes & LATT_MARKED) fputs (", marked",stdout);
if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
putchar ('\n');
}
void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
{
printf (" Mailbox %s",mailbox);
if (status->flags & SA_MESSAGES) printf (", %lu messages",status->messages);
if (status->flags & SA_RECENT) printf (", %lu recent",status->recent);
if (status->flags & SA_UNSEEN) printf (", %lu unseen",status->unseen);
if (status->flags & SA_UIDVALIDITY) printf (", %lu UID validity",
status->uidvalidity);
if (status->flags & SA_UIDNEXT) printf (", %lu next UID",status->uidnext);
printf ("\n");
}
void mm_log (char *string,long errflg)
{
switch ((short) errflg) {
case NIL:
printf ("[%s]\n",string);
break;
case PARSE:
case WARN:
printf ("%%%s\n",string);
break;
case ERROR:
printf ("?%s\n",string);
break;
}
}
void mm_dlog (char *string)
{
puts (string);
}
void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
{
char *s,tmp[MAILTMPLEN];
if (curhst) fs_give ((void **) &curhst);
curhst = (char *) fs_get (1+strlen (mb->host));
strcpy (curhst,mb->host);
sprintf (s = tmp,"{%s/%s",mb->host,mb->service);
if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",strcpy (user,mb->user));
if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser);
if (*mb->user) strcat (s = tmp,"} password:");
else {
printf ("%s} username: ",tmp);
fgets (user,NETMAXUSER-1,stdin);
user[NETMAXUSER-1] = '\0';
if (s = strchr (user,'\n')) *s = '\0';
s = "password: ";
}
if (curusr) fs_give ((void **) &curusr);
curusr = cpystr (user);
strcpy (pwd,getpass (s));
}
void mm_critical (MAILSTREAM *stream)
{
}
void mm_nocritical (MAILSTREAM *stream)
{
}
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
{
#if UNIXLIKE
kill (getpid (),SIGSTOP);
#else
abort ();
#endif
return NIL;
}
void mm_fatal (char *string)
{
printf ("?%s\n",string);
}
/* SMTP tester */
void smtptest (long debug)
{
SENDSTREAM *stream = NIL;
char line[MAILTMPLEN];
char *text = (char *) fs_get (8*MAILTMPLEN);
ENVELOPE *msg = mail_newenvelope ();
BODY *body = mail_newbody ();
msg->from = mail_newaddr ();
msg->from->personal = cpystr (personalname);
msg->from->mailbox = cpystr (curusr);
msg->from->host = cpystr (curhst);
msg->return_path = mail_newaddr ();
msg->return_path->mailbox = cpystr (curusr);
msg->return_path->host = cpystr (curhst);
prompt ("To: ",line);
rfc822_parse_adrlist (&msg->to,line,curhst);
if (msg->to) {
prompt ("cc: ",line);
rfc822_parse_adrlist (&msg->cc,line,curhst);
}
else {
prompt ("Newsgroups: ",line);
if (*line) msg->newsgroups = cpystr (line);
else {
mail_free_body (&body);
mail_free_envelope (&msg);
fs_give ((void **) &text);
return;
}
}
prompt ("Subject: ",line);
msg->subject = cpystr (line);
puts (" Msg (end with a line with only a '.'):");
body->type = TYPETEXT;
*text = '\0';
while (gets (line)) {
if (line[0] == '.') {
if (line[1] == '\0') break;
else strcat (text,".");
}
strcat (text,line);
strcat (text,"\015\012");
}
body->contents.text.data = (unsigned char *) text;
body->contents.text.size = strlen (text);
rfc822_date (line);
msg->date = (char *) fs_get (1+strlen (line));
strcpy (msg->date,line);
if (msg->to) {
puts ("Sending...");
if (stream = smtp_open (hostlist,debug)) {
if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]");
else printf ("[Failed - %s]\n",stream->reply);
}
}
else {
puts ("Posting...");
if (stream = nntp_open (newslist,debug)) {
if (nntp_mail (stream,msg,body)) puts ("[Ok]");
else printf ("[Failed - %s]\n",stream->reply);
}
}
if (stream) smtp_close (stream);
else puts ("[Can't open connection to any server]");
mail_free_envelope (&msg);
mail_free_body (&body);
}

231
src/osdep/amiga/Makefile Normal file
View File

@@ -0,0 +1,231 @@
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: C client makefile for Amiga
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 11 May 1989
# Last Edited: 5 November 2006
# Command line build parameters
EXTRAAUTHENTICATORS=
EXTRADRIVERS=mbox
PASSWDTYPE=std
# Build parameters normally set by the individual port
AMICFLAGS=-O -DNO_INLINE_STDARG -Dunix
AMILDFLAGS=/pine/libc.a -lamiga -lauto
CHECKPW=std
LOGINPW=std
ACTIVEFILE=/UULib/News/Active
SPOOLDIR=/usr/spool
MAILSPOOL=/AmiTCP/Mail
NEWSSPOOL=/UUNews
MD5PWD="/etc/cram-md5.pwd"
# Default formats for creating new mailboxes and for empty mailboxes in the
# default namespace; must be set to the associated driver's prototype.
#
# The CREATEPROTO is the default format for new mailbox creation.
# The EMPTYPROTO is the default format for handling zero-byte files.
#
# Normally, this is set by the individual port.
#
# NOTE: namespace formats (e.g. mh and news) can not be set as a default format
# since they do not exist in the default namespace. Also, it is meaningless to
# set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since
# these formats can never be empty files.
CREATEPROTO=unixproto
EMPTYPROTO=unixproto
# Commands possibly overriden by the individual port
ARRC=ar rc
CC=cc
LN=cp
RANLIB=ranlib
RM=rm -f
# Standard distribution build parameters
DEFAULTAUTHENTICATORS=ext md5 pla log
DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
CHUNKSIZE=65536
# Normally no need to change any of these
ARCHIVE=c-client.a
BINARIES=mail.o misc.o newsrc.o smanager.o osdep.o utf8.o utf8aux.o \
dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
CFLAGS=$(BASECFLAGS) $(EXTRACFLAGS)
MAKE=make
MV=mv
SHELL=/bin/sh
# Primary build command
BUILDOPTIONS= EXTRACFLAGS=$(EXTRACFLAGS) EXTRALDFLAGS=$(EXTRALDFLAGS)\
EXTRADRIVERS=$(EXTRADRIVERS) EXTRAAUTHENTICATORS=$(EXTRAAUTHENTICATORS)\
PASSWDTYPE=$(PASSWDTYPE)
BUILD=$(MAKE) build $(BUILDOPTIONS) $(SPECIALS)
# Here if no make argument established
missing: osdep.h
$(MAKE) $(ARCHIVE) CC=`cat CCTYPE` CFLAGS="`cat CFLAGS`"
osdep.h:
@echo You must specify what type of system
@false
# Current ports
ami: # AmigaDOS
$(BUILD) OS=$@ \
BASECFLAGS="-DOLD $(AMICFLAGS)" \
BASELDFLAGS="$(AMILDFLAGS) -lamitcp000" \
CC=gcc
am2: # AmigaDOS with a 68020+
$(BUILD) OS=ami \
BASECFLAGS="-DOLD -m68020 $(AMICFLAGS)" \
BASELDFLAGS="$(AMILDFLAGS) -lamitcp" \
CC=gcc
amn: # AmigaDOS with a 680x0 using "new" socket library
$(BUILD) OS=ami \
BASELDFLAGS="$(AMILDFLAGS) -lnewamitcp000" \
CC=gcc
ama: # AmigaDOS using AS225R2
$(BUILD) OS=ami \
MAILSPOOL=/INet/Mail \
BASECFLAGS="-m68020 $(AMICFLAGS)" \
BASELDFLAGS="$(AMILDFLAGS) -las225r2" \
CC=gcc
# Build it!
build: clean once ckp$(PASSWDTYPE) $(EXTRAAUTHENTICATORS) $(ARCHIVE)
$(ARCHIVE): $(BINARIES)
$(RM) $(ARCHIVE) || true
$(ARRC) $(ARCHIVE) $(BINARIES)
$(RANLIB) $(ARCHIVE)
# Cleanup
clean:
$(RM) *.o linkage.[ch] auths.c $(ARCHIVE) osdep.* *TYPE *FLAGS || true
# Dependencies
dummy.o: mail.h misc.h osdep.h dummy.h
fdstring.o: mail.h misc.h osdep.h fdstring.h
flstring.o: mail.h misc.h osdep.h flstring.h
imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h
mail.o: mail.h misc.h osdep.h rfc822.h linkage.h
mbx.o: mail.h misc.h osdep.h dummy.h
mh.o: mail.h misc.h osdep.h mh.h dummy.h
mix.o: mail.h misc.h osdep.h dummy.h
mx.o: mail.h misc.h osdep.h mx.h dummy.h
misc.o: mail.h misc.h osdep.h
mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h
mtx.o: mail.h misc.h osdep.h dummy.h
netmsg.o: mail.h misc.h osdep.h netmsg.h
news.o: mail.h misc.h osdep.h
newsrc.o: mail.h misc.h osdep.h newsrc.h
nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h
phile.o: mail.h misc.h osdep.h rfc822.h dummy.h
pseudo.o: pseudo.h
pop3.o: mail.h misc.h osdep.h pop3.h rfc822.h
smanager.o: mail.h misc.h osdep.h
smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h
rfc822.o: mail.h misc.h osdep.h rfc822.h
tenex.o: mail.h misc.h osdep.h dummy.h
unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
utf8.o: mail.h misc.h osdep.h utf8.h
utf8aux.o: mail.h misc.h osdep.h utf8.h
# OS-dependent
osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \
osdep.h env_ami.h tcp_ami.h \
osdep.c env_ami.c fs_ami.c ftl_ami.c nl_ami.c tcp_ami.c \
auths.c gethstid.c \
gr_waitp.c \
auth_log.c auth_md5.c auth_pla.c \
pmatch.c scandir.c \
tz_bsd.c \
write.c \
strerror.c strpbrk.c strstr.c strtok.c strtoul.c \
OSCFLAGS
$(CC) $(CFLAGS) `cat OSCFLAGS` -c osdep.c
osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c
$(RM) osdep.c || true
cat osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c
# Once-only environment setup
once:
@echo Once-only environment setup...
./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy
./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
echo $(CC) > CCTYPE
echo $(CFLAGS) -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS
echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \
-DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \
-DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \
-DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" > OSCFLAGS
echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS
$(LN) os_$(OS).h osdep.h
$(LN) os_$(OS).c osdepbas.c
$(LN) log_$(LOGINPW).c osdeplog.c
$(LN) ssl_none.c osdepssl.c
# Password checkers
ckpstd: # Port standard
$(LN) ckp_$(CHECKPW).c osdepckp.c
# A monument to a hack of long ago and far away...
love:
@echo not war?

42
src/osdep/amiga/ckp_std.c Normal file
View File

@@ -0,0 +1,42 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Standard check password
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 30 August 2006
*/
/* Check password
* Accepts: login passwd struct
* password string
* argument count
* argument vector
* Returns: passwd struct if password validated, NIL otherwise
*/
struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
{
return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
!strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ?
pw : NIL;
}

36
src/osdep/amiga/drivers Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/sh
# ========================================================================
# Copyright 1988-2006 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# ========================================================================
# Program: Driver Linkage Generator
#
# Author: Mark Crispin
# Networks and Distributed Computing
# Computing & Communications
# University of Washington
# Administration Building, AG-44
# Seattle, WA 98195
# Internet: MRC@CAC.Washington.EDU
#
# Date: 11 October 1989
# Last Edited: 30 August 2006
# Erase old driver linkage
rm -f linkage.[ch]
# Now define the new list
for driver
do
echo "extern DRIVER "$driver"driver;" >> linkage.h
echo " mail_link (&"$driver"driver); /* link in the $driver driver */" | cat >> linkage.c
done

809
src/osdep/amiga/dummy.c Normal file
View File

@@ -0,0 +1,809 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Dummy routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 9 May 1991
* Last Edited: 1 June 2007
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
extern int errno; /* just in case */
#include "mail.h"
#include "osdep.h"
#include <pwd.h>
#include <sys/stat.h>
#include "dummy.h"
#include "misc.h"
/* Function prototypes */
DRIVER *dummy_valid (char *name);
void *dummy_parameters (long function,void *value);
void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
long level);
long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
long attributes,char *contents);
long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
MAILSTREAM *dummy_open (MAILSTREAM *stream);
void dummy_close (MAILSTREAM *stream,long options);
long dummy_ping (MAILSTREAM *stream);
void dummy_check (MAILSTREAM *stream);
long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
/* Dummy routines */
/* Driver dispatch used by MAIL */
DRIVER dummydriver = {
"dummy", /* driver name */
DR_LOCAL|DR_MAIL, /* driver flags */
(DRIVER *) NIL, /* next driver */
dummy_valid, /* mailbox is valid for us */
dummy_parameters, /* manipulate parameters */
dummy_scan, /* scan mailboxes */
dummy_list, /* list mailboxes */
dummy_lsub, /* list subscribed mailboxes */
dummy_subscribe, /* subscribe to mailbox */
NIL, /* unsubscribe from mailbox */
dummy_create, /* create mailbox */
dummy_delete, /* delete mailbox */
dummy_rename, /* rename mailbox */
mail_status_default, /* status of mailbox */
dummy_open, /* open mailbox */
dummy_close, /* close mailbox */
NIL, /* fetch message "fast" attributes */
NIL, /* fetch message flags */
NIL, /* fetch overview */
NIL, /* fetch message structure */
NIL, /* fetch header */
NIL, /* fetch text */
NIL, /* fetch message data */
NIL, /* unique identifier */
NIL, /* message number from UID */
NIL, /* modify flags */
NIL, /* per-message modify flags */
NIL, /* search for message based on criteria */
NIL, /* sort messages */
NIL, /* thread messages */
dummy_ping, /* ping mailbox to see if still alive */
dummy_check, /* check for new messages */
dummy_expunge, /* expunge deleted messages */
dummy_copy, /* copy messages to another mailbox */
dummy_append, /* append string message to mailbox */
NIL /* garbage collect stream */
};
/* prototype stream */
MAILSTREAM dummyproto = {&dummydriver};
/* Dummy validate mailbox
* Accepts: mailbox name
* Returns: our driver if name is valid, NIL otherwise
*/
DRIVER *dummy_valid (char *name)
{
char *s,tmp[MAILTMPLEN];
struct stat sbuf;
/* must be valid local mailbox */
if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
/* indeterminate clearbox INBOX */
if (!*s) return &dummydriver;
else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
case S_IFREG:
case S_IFDIR:
return &dummydriver;
}
/* blackbox INBOX does not exist yet */
else if (!compare_cstring (name,"INBOX")) return &dummydriver;
}
return NIL;
}
/* Dummy manipulate driver parameters
* Accepts: function code
* function-dependent value
* Returns: function-dependent return value
*/
void *dummy_parameters (long function,void *value)
{
void *ret = NIL;
switch ((int) function) {
case GET_INBOXPATH:
if (value) ret = dummy_file ((char *) value,"INBOX");
break;
}
return ret;
}
/* Dummy scan mailboxes
* Accepts: mail stream
* reference
* pattern to search
* string to scan
*/
void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
{
DRIVER *drivers;
char *s,test[MAILTMPLEN],file[MAILTMPLEN];
long i;
if (!pat || !*pat) { /* empty pattern? */
if (dummy_canonicalize (test,ref,"*")) {
/* tie off name at root */
if (s = strchr (test,'/')) *++s = '\0';
else test[0] = '\0';
dummy_listed (stream,'/',test,LATT_NOSELECT,NIL);
}
}
/* get canonical form of name */
else if (dummy_canonicalize (test,ref,pat)) {
/* found any wildcards? */
if (s = strpbrk (test,"%*")) {
/* yes, copy name up to that point */
strncpy (file,test,i = s - test);
file[i] = '\0'; /* tie off */
}
else strcpy (file,test); /* use just that name then */
if (s = strrchr (file,'/')){/* find directory name */
*++s = '\0'; /* found, tie off at that point */
s = file;
}
/* silly case */
else if ((file[0] == '~') || (file[0] == '#')) s = file;
/* do the work */
dummy_list_work (stream,s,test,contents,0);
/* always an INBOX */
if (pmatch ("INBOX",ucase (test))) {
/* done if have a dirfmt INBOX */
for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
drivers && !(!(drivers->flags & DR_DISABLE) &&
(drivers->flags & DR_DIRFMT) &&
(*drivers->valid) ("INBOX")); drivers = drivers->next);
/* list INBOX appropriately */
dummy_listed (stream,drivers ? '/' : NIL,"INBOX",
drivers ? NIL : LATT_NOINFERIORS,contents);
}
}
}
/* Dummy list mailboxes
* Accepts: mail stream
* reference
* pattern to search
*/
void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
{
dummy_scan (stream,ref,pat,NIL);
}
/* Dummy list subscribed mailboxes
* Accepts: mail stream
* reference
* pattern to search
*/
void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
{
void *sdb = NIL;
char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN];
int showuppers = pat[strlen (pat) - 1] == '%';
/* get canonical form of name */
if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
if (*s != '{') {
if (!compare_cstring (s,"INBOX") &&
pmatch ("INBOX",ucase (strcpy (tmp,test))))
mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
else while (showuppers && (t = strrchr (s,'/'))) {
*t = '\0'; /* tie off the name */
if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT);
}
}
while (s = sm_read (&sdb)); /* until no more subscriptions */
}
/* Dummy subscribe to mailbox
* Accepts: mail stream
* mailbox to add to subscription list
* Returns: T on success, NIL on failure
*/
long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
{
char *s,tmp[MAILTMPLEN];
struct stat sbuf;
/* must be valid local mailbox */
if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf))
switch (sbuf.st_mode & S_IFMT) {
case S_IFDIR: /* allow but snarl */
sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s",
mailbox);
MM_NOTIFY (stream,tmp,WARN);
case S_IFREG:
return sm_subscribe (mailbox);
}
sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
MM_LOG (tmp,ERROR);
return NIL;
}
/* Dummy list mailboxes worker routine
* Accepts: mail stream
* directory name to search
* search pattern
* string to scan
* search level
*/
void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
long level)
{
DRIVER *drivers;
dirfmttest_t dt;
DIR *dp;
struct direct *d;
struct stat sbuf;
char tmp[MAILTMPLEN],path[MAILTMPLEN];
size_t len = 0;
/* punt if bogus name */
if (!mailboxdir (tmp,dir,NIL)) return;
if (dp = opendir (tmp)) { /* do nothing if can't open directory */
/* see if a non-namespace directory format */
for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
dir && !dt && drivers; drivers = drivers->next)
if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) &&
(*drivers->valid) (dir))
dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL);
/* list it if at top-level */
if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX"))
dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents);
/* scan directory, ignore . and .. */
if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp))
if ((!(dt && (*dt) (d->d_name))) &&
((d->d_name[0] != '.') ||
(((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
(d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) &&
((len + strlen (d->d_name)) <= NETMAXMBX)) {
/* see if name is useful */
if (dir) sprintf (tmp,"%s%s",dir,d->d_name);
else strcpy (tmp,d->d_name);
/* make sure useful and can get info */
if ((pmatch_full (strcpy (path,tmp),pat,'/') ||
pmatch_full (strcat (path,"/"),pat,'/') ||
dmatch (path,pat,'/')) &&
mailboxdir (path,dir,"x") && (len = strlen (path)) &&
strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) {
/* only interested in file type */
switch (sbuf.st_mode & S_IFMT) {
case S_IFDIR: /* directory? */
/* form with trailing / */
sprintf (path,"%s/",tmp);
/* skip listing if INBOX */
if (!pmatch (tmp,"INBOX")) {
if (pmatch_full (tmp,pat,'/')) {
if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents))
break;
}
/* try again with trailing / */
else if (pmatch_full (path,pat,'/') &&
!dummy_listed (stream,'/',path,LATT_NOSELECT,contents))
break;
}
if (dmatch (path,pat,'/') &&
(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
dummy_list_work (stream,path,pat,contents,level+1);
break;
case S_IFREG: /* ordinary name */
/* Must use ctime for systems that don't update mtime properly */
if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX"))
dummy_listed (stream,'/',tmp,LATT_NOINFERIORS +
((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))?
LATT_MARKED : LATT_UNMARKED),contents);
break;
}
}
}
closedir (dp); /* all done, flush directory */
}
}
/* Scan file for contents
* Accepts: driver to use
* file name
* desired contents
* length of contents
* size of file
* Returns: NIL if contents not found, T if found
*/
long scan_contents (DRIVER *dtb,char *name,char *contents,
unsigned long csiz,unsigned long fsiz)
{
scancontents_t sc = dtb ?
(scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL;
return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz);
}
/* Scan file for contents
* Accepts: file name
* desired contents
* length of contents
* size of file
* Returns: NIL if contents not found, T if found
*/
#define BUFSIZE 4*MAILTMPLEN
long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
unsigned long fsiz)
{
int fd;
unsigned long ssiz,bsiz;
char *buf;
/* forget it if can't select or open */
if ((fd = open (name,O_RDONLY,NIL)) >= 0) {
/* get buffer including slop */
buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
memset (buf,'\0',ssiz); /* no slop area the first time */
while (fsiz) { /* until end of file */
read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE));
if (search ((unsigned char *) buf,bsiz+ssiz,
(unsigned char *) contents,csiz)) break;
memcpy (buf,buf+BUFSIZE,ssiz);
fsiz -= bsiz; /* note that we read that much */
}
fs_give ((void **) &buf); /* flush buffer */
close (fd); /* finished with file */
if (fsiz) return T; /* found */
}
return NIL; /* not found */
}
/* Mailbox found
* Accepts: MAIL stream
* hierarchy delimiter
* mailbox name
* attributes
* contents to search before calling mm_list()
* Returns: NIL if should abort hierarchy search, else T (currently always)
*/
long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
long attributes,char *contents)
{
DRIVER *d;
DIR *dp;
struct direct *dr;
dirfmttest_t dt;
unsigned long csiz;
struct stat sbuf;
int nochild;
char *s,tmp[MAILTMPLEN];
if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
(dp = opendir (tmp))) { /* if not \NoInferiors */
/* locate dirfmttest if any */
for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
!dt && d; d = d->next)
if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) &&
(*d->valid) (name))
dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL);
/* scan directory for children */
for (nochild = T; nochild && (dr = readdir (dp)); )
if ((!(dt && (*dt) (dr->d_name))) &&
((dr->d_name[0] != '.') ||
(((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
(dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2])))))
nochild = NIL;
attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
closedir (dp); /* all done, flush directory */
}
d = NIL; /* don't \NoSelect dir if it has a driver */
if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
(d != &dummydriver)) attributes &= ~LATT_NOSELECT;
if (!contents || /* notify main program */
(!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
(s = mailboxfile (tmp,name)) &&
(*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) &&
!stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) &&
SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size)))
mm_list (stream,delimiter,name,attributes);
return T;
}
/* Dummy create mailbox
* Accepts: mail stream
* mailbox name to create
* Returns: T on success, NIL on failure
*/
long dummy_create (MAILSTREAM *stream,char *mailbox)
{
char *s,tmp[MAILTMPLEN];
long ret = NIL;
/* validate name */
if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
MM_LOG (tmp,ERROR);
}
/* create the name, done if made directory */
else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&&
(s = strrchr (s,'/')) && !s[1]) return T;
return ret ? set_mbx_protections (mailbox,tmp) : NIL;
}
/* Dummy create path
* Accepts: mail stream
* path name to create
* directory mode
* Returns: T on success, NIL on failure
*/
long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
{
struct stat sbuf;
char c,*s,tmp[MAILTMPLEN];
int fd;
long ret = NIL;
char *t = strrchr (path,'/');
int wantdir = t && !t[1];
int mask = umask (0);
if (wantdir) *t = '\0'; /* flush trailing delimiter for directory */
if (s = strrchr (path,'/')) { /* found superior to this name? */
c = *++s; /* remember first character of inferior */
*s = '\0'; /* tie off to get just superior */
/* name doesn't exist, create it */
if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
!dummy_create_path (stream,path,dirmode)) {
umask (mask); /* restore mask */
return NIL;
}
*s = c; /* restore full name */
}
if (wantdir) { /* want to create directory? */
ret = !mkdir (path,(int) dirmode);
*t = '/'; /* restore directory delimiter */
}
/* create file */
else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,
(long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0)
ret = !close (fd);
if (!ret) { /* error? */
sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno));
MM_LOG (tmp,ERROR);
}
umask (mask); /* restore mask */
return ret; /* return status */
}
/* Dummy delete mailbox
* Accepts: mail stream
* mailbox name to delete
* Returns: T on success, NIL on failure
*/
long dummy_delete (MAILSTREAM *stream,char *mailbox)
{
struct stat sbuf;
char *s,tmp[MAILTMPLEN];
if (!(s = dummy_file (tmp,mailbox))) {
sprintf (tmp,"Can't delete - invalid name: %.80s",s);
MM_LOG (tmp,ERROR);
}
/* no trailing / (workaround BSD kernel bug) */
if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0';
if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
rmdir (tmp) : unlink (tmp)) {
sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
MM_LOG (tmp,ERROR);
return NIL;
}
return T; /* return success */
}
/* Mail rename mailbox
* Accepts: mail stream
* old mailbox name
* new mailbox name
* Returns: T on success, NIL on failure
*/
long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
{
struct stat sbuf;
char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
/* no trailing / allowed */
if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
MM_LOG (mbx,ERROR);
return NIL;
}
if (s) { /* found a directory delimiter? */
if (!s[1]) *s = '\0'; /* ignore trailing delimiter */
else { /* found superior to destination name? */
c = *++s; /* remember first character of inferior */
*s = '\0'; /* tie off to get just superior */
/* name doesn't exist, create it */
if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
!dummy_create (stream,mbx)) return NIL;
*s = c; /* restore full name */
}
}
/* rename of non-ex INBOX creates dest */
if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
return dummy_create (NIL,mbx);
if (rename (oldname,mbx)) {
sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
strerror (errno));
MM_LOG (tmp,ERROR);
return NIL;
}
return T; /* return success */
}
/* Dummy open
* Accepts: stream to open
* Returns: stream on success, NIL on failure
*/
MAILSTREAM *dummy_open (MAILSTREAM *stream)
{
int fd;
char err[MAILTMPLEN],tmp[MAILTMPLEN];
struct stat sbuf;
/* OP_PROTOTYPE call */
if (!stream) return &dummyproto;
err[0] = '\0'; /* no error message yet */
/* can we open the file? */
if (!dummy_file (tmp,stream->mailbox))
sprintf (err,"Can't open this name: %.80s",stream->mailbox);
else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
/* no, error unless INBOX */
if (compare_cstring (stream->mailbox,"INBOX"))
sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
}
else { /* file had better be empty then */
fstat (fd,&sbuf); /* sniff at its size */
close (fd);
if ((sbuf.st_mode & S_IFMT) != S_IFREG)
sprintf (err,"Can't open %.80s: not a selectable mailbox",
stream->mailbox);
else if (sbuf.st_size) /* bogus format if non-empty */
sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format",
stream->mailbox,tmp);
}
if (err[0]) { /* if an error happened */
MM_LOG (err,stream->silent ? WARN : ERROR);
return NIL;
}
else if (!stream->silent) { /* only if silence not requested */
mail_exists (stream,0); /* say there are 0 messages */
mail_recent (stream,0); /* and certainly no recent ones! */
stream->uid_validity = time (0);
}
stream->inbox = T; /* note that it's an INBOX */
return stream; /* return success */
}
/* Dummy close
* Accepts: MAIL stream
* options
*/
void dummy_close (MAILSTREAM *stream,long options)
{
/* return silently */
}
/* Dummy ping mailbox
* Accepts: MAIL stream
* Returns: T if stream alive, else NIL
*/
long dummy_ping (MAILSTREAM *stream)
{
MAILSTREAM *test;
if (time (0) >= /* time to do another test? */
((time_t) (stream->gensym +
(long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
/* has mailbox format changed? */
if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
(test->dtb != stream->dtb) &&
(test = mail_open (NIL,stream->mailbox,NIL))) {
/* preserve some resources */
test->original_mailbox = stream->original_mailbox;
stream->original_mailbox = NIL;
test->sparep = stream->sparep;
stream->sparep = NIL;
test->sequence = stream->sequence;
mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
memcpy (fs_get (sizeof (MAILSTREAM)),stream,
sizeof (MAILSTREAM)));
/* swap the streams */
memcpy (stream,test,sizeof (MAILSTREAM));
fs_give ((void **) &test);/* flush test now that copied */
/* make sure application knows */
mail_exists (stream,stream->recent = stream->nmsgs);
}
/* still hasn't changed */
else stream->gensym = time (0);
}
return T;
}
/* Dummy check mailbox
* Accepts: MAIL stream
* No-op for readonly files, since read/writer can expunge it from under us!
*/
void dummy_check (MAILSTREAM *stream)
{
dummy_ping (stream); /* invoke ping */
}
/* Dummy expunge mailbox
* Accepts: MAIL stream
* sequence to expunge if non-NIL
* expunge options
* Returns: T, always
*/
long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
{
return LONGT;
}
/* Dummy copy message(s)
* Accepts: MAIL stream
* sequence
* destination mailbox
* options
* Returns: T if copy successful, else NIL
*/
long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
{
if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
return NIL;
}
/* Dummy append message string
* Accepts: mail stream
* destination mailbox
* append callback function
* data for callback
* Returns: T on success, NIL on failure
*/
long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
{
struct stat sbuf;
int fd = -1;
int e;
char tmp[MAILTMPLEN];
MAILSTREAM *ts = default_proto (T);
/* append to INBOX? */
if (!compare_cstring (mailbox,"INBOX")) {
/* yes, if no empty proto try creating */
if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX"))
ts = NIL;
}
else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
if ((e = errno) == ENOENT) /* failed, was it no such file? */
MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
MM_LOG (tmp,ERROR); /* pass up error */
return NIL; /* always fails */
}
else if (fd >= 0) { /* found file? */
fstat (fd,&sbuf); /* get its size */
close (fd); /* toss out the fd */
if (sbuf.st_size) ts = NIL; /* non-empty file? */
}
if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
MM_LOG (tmp,ERROR);
return NIL;
}
/* Dummy mail generate file string
* Accepts: temporary buffer to write into
* mailbox name string
* Returns: local file string or NIL if failure
*/
char *dummy_file (char *dst,char *name)
{
char *s = mailboxfile (dst,name);
/* return our standard inbox */
return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
}
/* Dummy canonicalize name
* Accepts: buffer to write name
* reference
* pattern
* Returns: T if success, NIL if failure
*/
long dummy_canonicalize (char *tmp,char *ref,char *pat)
{
unsigned long i;
char *s;
if (ref) { /* preliminary reference check */
if (*ref == '{') return NIL;/* remote reference not allowed */
else if (!*ref) ref = NIL; /* treat empty reference as no reference */
}
switch (*pat) {
case '#': /* namespace name */
if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
else return NIL; /* unknown namespace */
break;
case '{': /* remote names not allowed */
return NIL;
case '/': /* rooted name */
case '~': /* home directory name */
if (!ref || (*ref != '#')) {/* non-namespace reference? */
strcpy (tmp,pat); /* yes, ignore */
break;
}
/* fall through */
default: /* apply reference for all other names */
if (!ref) strcpy (tmp,pat); /* just copy if no namespace */
else if ((*ref != '#') || mailboxfile (tmp,ref)) {
/* wants root of name? */
if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat);
/* otherwise just append */
else sprintf (tmp,"%s%s",ref,pat);
}
else return NIL; /* unknown namespace */
}
/* count wildcards */
for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
if (i > MAXWILDCARDS) { /* ridiculous wildcarding? */
MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
return NIL;
}
return T;
}

43
src/osdep/amiga/dummy.h Normal file
View File

@@ -0,0 +1,43 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: Dummy routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 9 May 1991
* Last Edited: 30 August 2006
*/
/* Exported function prototypes */
void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
long scan_contents (DRIVER *dtb,char *name,char *contents,
unsigned long csiz,unsigned long fsiz);
long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
unsigned long fsiz);
long dummy_create (MAILSTREAM *stream,char *mailbox);
long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
long dummy_delete (MAILSTREAM *stream,char *mailbox);
long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
char *dummy_file (char *dst,char *name);
long dummy_canonicalize (char *tmp,char *ref,char *pat);

1282
src/osdep/amiga/env_ami.c Normal file

File diff suppressed because it is too large Load Diff

95
src/osdep/amiga/env_ami.h Normal file
View File

@@ -0,0 +1,95 @@
/* ========================================================================
* Copyright 1988-2006 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: UNIX environment routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 30 August 2006
*/
typedef struct dotlock_base {
char lock[MAILTMPLEN];
int pipei;
int pipeo;
} DOTLOCK;
/* Bits that can be set in restrictBox */
#define RESTRICTROOT 0x1 /* restricted box doesn't allow root */
#define RESTRICTOTHERUSER 0x2 /* restricted box doesn't allow other user */
/* Subscription definitions for UNIX */
#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ())
#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ())
/* dorc() options */
#define SYSCONFIG "/etc/c-client.cf"
/* Special users */
#define ANONYMOUSUSER "nobody" /* anonymous user */
#define UNLOGGEDUSER "root" /* unlogged-in user */
#define ADMINGROUP "mailadm" /* mail administrator group */
/* Function prototypes */
#include "env.h"
void rfc822_fixed_date (char *date);
long env_init (char *user,char *home);
char *myusername_full (unsigned long *flags);
#define MU_LOGGEDIN 0
#define MU_NOTLOGGEDIN 1
#define MU_ANONYMOUS 2
#define myusername() \
myusername_full (NIL)
char *sysinbox ();
char *mailboxdir (char *dst,char *dir,char *name);
long dotlock_lock (char *file,DOTLOCK *base,int fd);
long dotlock_unlock (DOTLOCK *base);
int lockname (char *lock,char *fname,int op,long *pid);
int lockfd (int fd,char *lock,int op);
int lock_work (char *lock,void *sbuf,int op,long *pid);
long chk_notsymlink (char *name,void *sbuf);
void unlockfd (int fd,char *lock);
long set_mbx_protections (char *mailbox,char *path);
long get_dir_protection (char *mailbox);
MAILSTREAM *user_flags (MAILSTREAM *stream);
char *default_user_flag (unsigned long i);
void dorc (char *file,long flag);
long path_create (MAILSTREAM *stream,char *mailbox);
void grim_pid_reap_status (int pid,int killreq,void *status);
#define grim_pid_reap(pid,killreq) \
grim_pid_reap_status (pid,killreq,NIL)
long safe_write (int fd,char *buf,long nbytes);
void *arm_signal (int sig,void *action);
struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]);
long loginpw (struct passwd *pw,int argc,char *argv[]);
long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
char *argv[]);
void *mm_blocknotify (int reason,void *data);

View File

@@ -0,0 +1,99 @@
/* ========================================================================
* Copyright 1988-2007 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: File descriptor string routines
*
* Author: Mark Crispin
* Networks and Distributed Computing
* Computing & Communications
* University of Washington
* Administration Building, AG-44
* Seattle, WA 98195
* Internet: MRC@CAC.Washington.EDU
*
* Date: 15 April 1997
* Last Edited: 4 April 2007
*/
#include "mail.h"
#include "osdep.h"
#include "misc.h"
#include "fdstring.h"
/* String driver for fd stringstructs */
static void fd_string_init (STRING *s,void *data,unsigned long size);
static char fd_string_next (STRING *s);
static void fd_string_setpos (STRING *s,unsigned long i);
STRINGDRIVER fd_string = {
fd_string_init, /* initialize string structure */
fd_string_next, /* get next byte in string structure */
fd_string_setpos /* set position in string structure */
};
/* Initialize string structure for fd stringstruct
* Accepts: string structure
* pointer to string
* size of string
*/
static void fd_string_init (STRING *s,void *data,unsigned long size)
{
FDDATA *d = (FDDATA *) data;
/* note fd */
s->data = (void *) (unsigned long) d->fd;
s->data1 = d->pos; /* note file offset */
s->size = size; /* note size */
s->curpos = s->chunk = d->chunk;
s->chunksize = (unsigned long) d->chunksize;
s->offset = 0; /* initial position */
/* and size of data */
s->cursize = min (s->chunksize,size);
/* move to that position in the file */
lseek (d->fd,d->pos,L_SET);
read (d->fd,s->chunk,(size_t) s->cursize);
}
/* Get next character from fd stringstruct
* Accepts: string structure
* Returns: character, string structure chunk refreshed
*/
static char fd_string_next (STRING *s)
{
char c = *s->curpos++; /* get next byte */
SETPOS (s,GETPOS (s)); /* move to next chunk */
return c; /* return the byte */
}
/* Set string pointer position for fd stringstruct
* Accepts: string structure
* new position
*/
static void fd_string_setpos (STRING *s,unsigned long i)
{
if (i > s->size) i = s->size; /* don't permit setting beyond EOF */
s->offset = i; /* set new offset */
s->curpos = s->chunk; /* reset position */
/* set size of data */
if (s->cursize = min (s->chunksize,SIZE (s))) {
/* move to that position in the file */
lseek ((long) s->data,s->data1 + s->offset,L_SET);
read ((long) s->data,s->curpos,(size_t) s->cursize);
}
}

Some files were not shown because too many files have changed in this diff Show More