home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
- *
- * Pack sender's name into something sensible, return in packed:
- * pack_name(packed, name, length)
- *
- */
-
- #include "config.h"
-
- /* #define NAME_TEST /* Never define this ! */
-
- #define SEP_DOT 0 /* . */
- #define SEP_PERCENT 1 /* % */
- #define SEP_SCORE 2 /* _ */
- #define SEP_AMPERSAND 3 /* @ */
- #define SEP_BANG 4 /* ! */
- #define SEP_MAXIMUM 5
-
-
- #define CL_OK 0x0100 /* letter or digit */
- #define CL_SPACE 0x0200 /* cvt to space */
- #define CL_IGNORE 0x0400 /* ignore */
- #define CL_RANGE(c) 0x0800+c /* space range, end with c */
- #define CL_HYPHEN 0x1000 /* convert to - */
- #define CL_STOP 0x2000 /* discard rest of name */
- #define CL_SEP | 0x4000 + /* address separator */
-
- #define IS_OK(c) (Class[c] & CL_OK)
- #define IS_SPACE(c) (Class[c] & CL_SPACE)
- #define IGNORE(c) (c & 0x80 || Class[c] & CL_IGNORE)
- #define BEGIN_RANGE(c) (Class[c] & CL_RANGE(0))
- #define END_RANGE(c) (Class[c] & 0xff)
- #define IS_HYPHEN(c) (Class[c] & CL_HYPHEN)
- #define IS_STOP(c) (Class[c] & CL_STOP)
- #define IS_SEPARATOR(c) (Class[c] & (0 CL_SEP 0))
-
- static short Class[128] = {
- /* NUL */ CL_STOP ,
- /* SOH */ CL_IGNORE ,
- /* STX */ CL_IGNORE ,
- /* ETX */ CL_IGNORE ,
- /* EOT */ CL_IGNORE ,
- /* ENQ */ CL_IGNORE ,
- /* ACK */ CL_IGNORE ,
- /* BEL */ CL_IGNORE ,
- /* BS */ CL_IGNORE ,
- /* TAB */ CL_SPACE ,
- /* NL */ CL_IGNORE ,
- /* VT */ CL_IGNORE ,
- /* FF */ CL_IGNORE ,
- /* CR */ CL_IGNORE ,
- /* SO */ CL_IGNORE ,
- /* SI */ CL_IGNORE ,
- /* DLE */ CL_IGNORE ,
- /* DC1 */ CL_IGNORE ,
- /* DC2 */ CL_IGNORE ,
- /* DC3 */ CL_IGNORE ,
- /* DC4 */ CL_IGNORE ,
- /* NAK */ CL_IGNORE ,
- /* SYN */ CL_IGNORE ,
- /* ETB */ CL_IGNORE ,
- /* CAN */ CL_IGNORE ,
- /* EM */ CL_IGNORE ,
- /* SUB */ CL_IGNORE ,
- /* ESC */ CL_IGNORE ,
- /* FS */ CL_IGNORE ,
- /* GS */ CL_IGNORE ,
- /* RS */ CL_IGNORE ,
- /* US */ CL_IGNORE ,
-
- /* space */ CL_SPACE ,
- /* ! */ CL_SPACE CL_SEP SEP_BANG,
- /* " */ CL_RANGE( '"' ) ,
- /* # */ CL_OK ,
- /* $ */ CL_OK ,
- /* % */ CL_OK CL_SEP SEP_PERCENT,
- /* & */ CL_OK ,
- /* ' */ CL_OK ,
- /* ( */ CL_RANGE( ')' ) ,
- /* ) */ CL_IGNORE ,
- /* * */ CL_HYPHEN ,
- /* + */ CL_HYPHEN ,
- /* , */ CL_STOP ,
- /* - */ CL_HYPHEN ,
- /* . */ CL_SPACE CL_SEP SEP_DOT,
- /* / */ CL_OK ,
- /* 0 */ CL_OK ,
- /* 1 */ CL_OK ,
- /* 2 */ CL_OK ,
- /* 3 */ CL_OK ,
- /* 4 */ CL_OK ,
- /* 5 */ CL_OK ,
- /* 6 */ CL_OK ,
- /* 7 */ CL_OK ,
- /* 8 */ CL_OK ,
- /* 9 */ CL_OK ,
- /* : */ CL_IGNORE ,
- /* ; */ CL_STOP ,
- /* < */ CL_IGNORE ,
- /* = */ CL_HYPHEN ,
- /* > */ CL_IGNORE ,
- /* ? */ CL_IGNORE ,
- /* @ */ CL_OK CL_SEP SEP_AMPERSAND,
- /* A */ CL_OK ,
- /* B */ CL_OK ,
- /* C */ CL_OK ,
- /* D */ CL_OK ,
- /* E */ CL_OK ,
- /* F */ CL_OK ,
- /* G */ CL_OK ,
- /* H */ CL_OK ,
- /* I */ CL_OK ,
- /* J */ CL_OK ,
- /* K */ CL_OK ,
- /* L */ CL_OK ,
- /* M */ CL_OK ,
- /* N */ CL_OK ,
- /* O */ CL_OK ,
- /* P */ CL_OK ,
- /* Q */ CL_OK ,
- /* R */ CL_OK ,
- /* S */ CL_OK ,
- /* T */ CL_OK ,
- /* U */ CL_OK ,
- /* V */ CL_OK ,
- /* W */ CL_OK ,
- /* X */ CL_OK ,
- /* Y */ CL_OK ,
- /* Z */ CL_OK ,
- /* [ */ CL_OK ,
- /* \ */ CL_OK ,
- /* ] */ CL_OK ,
- /* ^ */ CL_IGNORE ,
- /* _ */ CL_SPACE CL_SEP SEP_SCORE,
- /* ` */ CL_IGNORE ,
- /* a */ CL_OK ,
- /* b */ CL_OK ,
- /* c */ CL_OK ,
- /* d */ CL_OK ,
- /* e */ CL_OK ,
- /* f */ CL_OK ,
- /* g */ CL_OK ,
- /* h */ CL_OK ,
- /* i */ CL_OK ,
- /* j */ CL_OK ,
- /* k */ CL_OK ,
- /* l */ CL_OK ,
- /* m */ CL_OK ,
- /* n */ CL_OK ,
- /* o */ CL_OK ,
- /* p */ CL_OK ,
- /* q */ CL_OK ,
- /* r */ CL_OK ,
- /* s */ CL_OK ,
- /* t */ CL_OK ,
- /* u */ CL_OK ,
- /* v */ CL_OK ,
- /* w */ CL_OK ,
- /* x */ CL_OK ,
- /* y */ CL_OK ,
- /* z */ CL_OK ,
- /* { */ CL_OK ,
- /* | */ CL_OK ,
- /* } */ CL_OK ,
- /* ~ */ CL_HYPHEN ,
- /* DEL */ CL_IGNORE
- } ;
-
-
- pack_name(dest, source, length)
- char *dest, *source;
- int length;
- {
- register char *p, *q, *r, c;
- register int n;
- char namebuf[129], *name;
- char *maxq;
- int lname, lfirst, lmiddle, llast, sep, i;
- int drop_space, prev_space;
- char *separator[SEP_MAXIMUM];
-
- dest[0] = NUL;
-
- if (source == NULL || source[0] == NUL)
- return 0;
-
- p = source, q = namebuf, n = 0;
- maxq = namebuf + sizeof namebuf - 1;
-
- new_partition:
- for (i = SEP_MAXIMUM; --i >= 0; separator[i] = NULL);
-
- while ( c = *p++ ) {
- if (c == '<') {
- while (q > namebuf && q[-1] == SP) q--;
- if (q == namebuf) continue;
- break;
- }
- if (IGNORE(c)) continue;
- if (q == namebuf && IS_SPACE(c)) continue;
- if (c == '(') {
- if (*p == ')') {
- p++;
- continue;
- }
- if (n++ == 0) {
- q = namebuf;
- goto new_partition;
- }
- continue;
- }
- if (c == ')') {
- if (--n == 0) break;
- continue;
- }
- if (n > 1) continue;
- if (q >= maxq) break;
- *q++ = c;
- if (IS_SEPARATOR(c)) {
- switch (sep = (Class[c] & 0xff)) {
-
- case SEP_DOT:
- if (separator[SEP_AMPERSAND] && q - namebuf <= length)
- break;
- continue;
-
- case SEP_BANG:
- if (separator[SEP_AMPERSAND]) continue;
- break;
-
- default:
- if (separator[sep]) continue;
- break;
- }
-
- separator[sep] = q - 1;
- }
- }
-
- *q = NUL;
-
- if (namebuf[0] == NUL) return 0;
-
- name = namebuf;
-
- if (name[0] == '"') {
- name++;
- if (q[-1] == '"') *--q = NUL;
- }
-
- if (q - name <= length) goto name_ok;
-
- /* sorry for the many goto's -- the 3B2 C compiler does not */
- /* make correct code for complicated logical expressions!! */
- /* not even without -O */
-
- /* We must pack the name to make it fit */
-
- /* Name_of_person%... -> Name_of_person */
-
- if (r = separator[SEP_PERCENT]) {
- if (!(q = separator[SEP_SCORE]) || q > r )
- goto no_percent;
- if ((q = separator[SEP_AMPERSAND]) && q < r)
- goto no_percent;
- if ((q = separator[SEP_BANG]) && q < r)
- goto no_percent;
- *r = NUL;
- goto parse_name;
- }
-
- no_percent:
-
- /* name@site.domain -> name@site */
-
- if (r = separator[SEP_AMPERSAND]) {
-
- if ((q = separator[SEP_PERCENT]) && q < r) {
- *r = NUL;
- if (r - name <= length) goto name_ok;
-
- *q = NUL;
-
- if (((p = separator[SEP_BANG]) && p < q)
- || ((p = strrchr(name, '!')) && p < q)) {
- name = p + 1;
- }
-
- if (strchr(name, '.'))
- goto parse_name;
-
- goto name_ok;
- }
-
- if (q = separator[SEP_DOT]) {
- *q = NUL;
- goto name_ok;
- }
-
- *r = NUL;
- if (r - name <= length) goto name_ok;
-
- if ((q = separator[SEP_BANG]) && q < r) {
- name = q + 1;
- goto name_ok;
- }
-
- #ifdef NOTDEF
- if (strchr(name, '!') == NULL)
- goto parse_name; /* take the chance ... */
- #endif
- goto name_ok; /* can't do it any better */
- }
-
-
- /* Phase 1: Normalization (remove superfluous characters) */
-
- parse_name:
-
- for (p = name, lname = 0, prev_space = 0; c = *p; p++) {
-
- /*
- if (IGNORE(c)) {
- *p = TAB;
- if (p == name) name++;
- continue;
- }
- */
-
- if (IS_OK(c)) {
- lname++;
- prev_space = 0;
- continue;
- }
-
- if (IS_HYPHEN(c)) {
- if (p == name) {
- name++;
- continue;
- }
- if (prev_space)
- *p = TAB;
- else {
- *p = '-';
- lname++;
- }
- continue;
- }
-
- if (BEGIN_RANGE(c)) {
-
- if (p == name) {
- name++;
- continue;
- }
-
- c = END_RANGE(c);
- for (q = p+1; *q && *q != c; q++);
- if (*q) {
- if (p[-1] != ' ') lname++;
- while (p <= q) *p++ = ' ';
- p--;
- prev_space++;
- continue;
- }
- c = ' ';
- }
-
- if (IS_SPACE(c)) {
- *p = ' ';
- if (p == name)
- name++;
- else
- if (!prev_space) {
- lname++;
- prev_space++;
- }
- continue;
- }
-
- if (IS_STOP(c)) {
- *p = NUL;
- break;
- }
- }
- drop_last_name:
- while (p > name && (*--p == ' ' || *p == TAB)) *p = NUL;
-
- if (lname < length) goto name_ok;
-
-
- /* Phase 2: Reduce middle names */
-
- for (r = p, llast = 0; r > name && *r != ' '; r--)
- if (*r != TAB) llast++;
-
- /* r points to space before last name */
-
- if (strncmp(r, " Jr", 3) == 0 || strncmp(r, " II", 3) == 0) {
- p = r+1;
- lname -= llast;
- goto drop_last_name;
- }
-
- if (r == name) goto phase6; /* only last name */
-
- for (q = name, lfirst = 0; *q && *q != ' '; q++)
- if (*q != TAB) lfirst++;
-
- /* q points at space after first name */
-
- for (p = q, lmiddle = 0; p < r; ) {
- /* find next middle name */
- while (p < r && (*p == ' ' || *p == TAB)) p++;
-
- if (p >= r) break; /* found last name */
-
- p++; /* skip first char of middle name */
- for (;*p != ' '; p++) { /* remove rest */
- if (*p == TAB) continue;
- *p = TAB;
- lname--;
- }
- lmiddle += 2; /* initial + space */
- }
-
- if (lname < length) goto name_ok;
-
- /* If removing middle names is not enough, but reducing first name instead is, do it that way */
-
- if (lname - lmiddle >= length && lname - lfirst + 1 < length) goto phase4;
-
-
- /* Phase 3: Remove middle names */
-
- for (p = q; p < r; p++) {
- if (*p == TAB) continue;
- if (*p == ' ') continue;
- *p = TAB;
- lname -= 2;
- }
-
- if (lname < length) goto name_ok;
-
-
- /* Phase 4: Reduce first name */
-
- phase4:
- for (p = name+1; p < q; p++) {
- if (*p == TAB) continue;
- if (*p == ' ') continue;
- if (*p == '-' && (p + 1) < q) {
- p++;
- continue;
- }
- *p = TAB;
- lname--;
- }
-
- if (lname < length) goto name_ok;
-
- /* Phase 5: Remove first name */
-
- name = r+1;
- lname--;
-
- if (lname < length) goto name_ok;
-
- /* Phase 6: Cut last name */
- phase6:
- goto name_ok;
-
- name_ok:
-
- q = dest;
- maxq = q + length;
-
- drop_space = 1;
-
- for (p = name; *p && q < maxq ; p++) {
- if (*p == TAB) continue;
-
- if ( *p == ' ' ) {
- if (!drop_space) {
- drop_space = 1;
- *q++ = ' ';
- }
- continue;
- }
- drop_space = 0;
- *q++ = *p;
- }
-
- *q = NUL;
-
- return strlen(dest);
- }
-
- #ifdef NAME_TEST
-
- main() {
- char in[512], out[512];
-
- while (gets(in)) {
- printf("'%s' -> (%d) ", in, pack_name(out,in,NAME_LENGTH));
- puts(out);
- }
- exit(0);
- }
-
- #endif
-