/* * xmail - X window system interface to the mail program * * Copyright 1990,1991,1992 by National Semiconductor Corporation * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of National Semiconductor Corporation not * be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" * WITHOUT EXPRESS OR IMPLIED WARRANTY. NATIONAL SEMICONDUCTOR CORPORATION * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Michael C. Wagnitz - National Semiconductor Corporation * */ #include "global.h" extern char *mailrcFile(void); String list = NULL; /* list of aliases */ int list_length; /* size of alias list */ alias_compare(AliasRec **a1, AliasRec **a2) { return(strcmp((*a1)->name, (*a2)->name)); } /* ** @(#)addtobuf() - add text to recipient or file and folder names buffer ** drop any leading backslash from a recipient name */ void addtobuf(char *text, char *buffer, char *otherBuffer) { int current_line_length; char *last_line; if (strchr("./+|", *text) != NULL) { if (*otherBuffer) (void) strcat(otherBuffer, ","); (void) strcat(otherBuffer, text); } else { if (*buffer) (void) strcat(buffer, ", "); if (last_line = strrchr(buffer, '\t')) last_line++; else last_line = buffer; current_line_length = strlen(last_line); if (current_line_length && current_line_length + (int)strlen(text) > 71) { (void) strcat(buffer, "\n\t"); /* make it a continuation of header */ } (void) strcat(buffer, (*text == '\\') ? &text[1] : text); } } /* addtobuf */ /* ** @(#) de_alias() - move (possibly) comma separated aliases into buffers */ void de_alias(char *text, char *buffer, char *otherBuffer) { char *cp, *next_alias, buf[BUFSIZ]; if (strchr(text, ',') == NULL) addtobuf(text, buffer, otherBuffer); else { (void) strncpy(buf, text, BUFSIZ); for (next_alias = buf; *next_alias; next_alias = cp) { if (cp = strchr(next_alias, ',')) *cp++ = '\0'; else cp = next_alias + strlen(next_alias); addtobuf(next_alias, buffer, otherBuffer); } } } /* de_alias */ /* ** @(#)alias() - return alias value(s) from mail, or name if no alias found */ char * alias(char *name) { int i, n, testing_for_compound_address; char tmp[BUFSIZ], buf[BUFSIZ]; String ep, s, p, value; tmp[0] = '\0'; if (name) (void) strncpy(tmp, name, BUFSIZ); /* ** If not already done, extract the mail alias list and build the alias table. ** Provide support for the possibility of multiple names for an alias with or ** without comma separations. */ if (! aliases) { if (mailpid) list = XtNewString(QueryMail("alias")); else if (! (list = XtNewString(GetMailrc("alias")))) { list = (String) XtMalloc((unsigned) 2); list[0] = '\0'; } /* ** count up the number of aliases in the list and allocate the list size */ ep = &list[strlen(list)]; for (i = 1, p = list; p < ep; p++) if (*p == '\n') i++; aliases = (AliasRec **) XtMalloc((unsigned) (i + 1) * sizeof(AliasRec *)); /* ** Copy the pointers for the alias names and values into an array, marking ** the ends of each with a null and separating any multiple values with a ** comma. Ensure there is no trailing comma in the value list. */ for (n = 0, p = list; n < i && p < ep; n++, p++) { aliases[n] = (AliasRec *) XtMalloc((unsigned) sizeof(AliasRec)); for (; *p && (*p == ' ' || *p == '\t'); p++); for (aliases[n]->name = p; *p && *p != ' ' && *p != '\t'; p++); for (*p++ = '\0'; *p && strchr(" \t\"\'", *p); p++); testing_for_compound_address = True; for (aliases[n]->alias = p; *p && *p != '\n'; p++) { /* ** If it contains a chevron, parenthesis, or pipe symbol, then just treat ** the whole line as one alias entry. */ if (*p == '|') { if (s = strchr(p, '\n')) p = s; else p += strlen(p); break; } if (testing_for_compound_address) { if ((s = strchr(p, '<')) || (s = strchr(p, '('))) { if (value = strchr(p, '\n')) { /* could be more than one */ if (s < value) { /* if its within this alias */ p = value; /* point to end of this alias */ if (*(p - 1) == '"' || /* could be true (no mailpid) */ *(p - 1) == '\'') *(p - 1) = '\0'; break; } else { if (*s == '<' && (s = strchr(p, '(')) && s < value) { p = value; /* point to end of this alias */ if (*(p - 1) == '"' || /* possibly not in mail */ *(p - 1) == '\'') *(p - 1) = '\0'; break; } else testing_for_compound_address = False; } } else { /* last entry of this record */ p += strlen(p); /* point to the end of line */ break; } } else testing_for_compound_address = False; } /* end - if testing_for_compound_address */ if ((*p == ' ' || *p == '\t') && *(p+1) && *(p+1) != '\n' && *(p-1) != *p && *(p-1) != ',') *p = ','; } for (s = p - 1; strchr(", \t", *s); s--); if (strchr(", \t", *++s)) *s = '\0'; if (*p) *p = '\0'; } aliases[n] = NULL; if (n) qsort((char *)aliases, n, sizeof(char *), alias_compare); } /* end - if no alias list */ /* ** In deference to those who didn't install the app-defaults file, accept a ** newline character as a word separator as well as the comma normally found. ** If input is made up of more than one word, check each word for aliasing. ** If it contains a chevron or parenthesis, it is a 'compound' address type. ** If line length approaches 80 characters, add a newline-tab and continue. */ if (*(value = tmp)) { buf[0] = '\0'; for (p = value; *p;) { /* 'value' points to current 'word' */ for (s = p; *s && strchr(", \t\n", *s) == NULL; s++); if (*s) { /* ** First, check for case of possible compound address. ** Could be a form of either: "(user[ ]name) [<]addr[>]", ** " [(]user name[)]", ** or "[<]addr[>] (user name)". ** If any of these, skip to end of that address/name. */ if (strchr(" \t", *s)) { if (*value == '(') { s = strchr(value, ')'); if (*s) { /* if form is '(user) addr', skip to */ for (s++; *s && strchr(" \t", *s); s++); /* start of addr */ for (; *s && ! strchr(", \t\n", *s); s++); /* then to end */ } } else if (*value == '<') { s = strchr(value, '>'); if (*s) { /* ** if form is ' [(]user[)]', skip to end of user str */ for (s++; *s && strchr(" \t", *s); s++); for (; *s && ! strchr(",\t\n", *s); s++); } } else { /* 'addr (usr)|usr '? find end */ for (; *s && strchr(" \t", *s); s++); if (! strchr("(<", *s)) s--; /* NOT one of these, back up */ else { if (*s == '<') s = strchr(s, '>'); /* find end of
or */ else s = strchr(s, ')'); /* find end of (user name) */ if (s && *s) s++; } } } if (s) *s++ = '\0'; p = s; } else p = &value[strlen(value)]; for (n = 0; aliases[n]; n++) { if (strcmp(value, aliases[n]->name) == 0) { de_alias(aliases[n]->alias, buf, otherBuf); break; } } if (! aliases[n]) /* If not an alias, use the name supplied. */ de_alias(value, buf, otherBuf); for (; *p && strchr(", \t\n", *p); p++); value = p; } value = buf; } return ((char *)value); } /* alias */ /* ** @(#)GetMailEnv() - Get environment value from mail or shell ** Accommodate the case of trailing blanks on the item. ** Expand environment variables. */ char * GetMailEnv(String item) { int length; String ep, mailenv, s, c, value, getenv(const char *); char buf[BUFSIZ]; value = NULL; (void) strcpy(buf, item); for (length = 0; buf[length] && buf[length] != ' '; length++); buf[length] = '\0'; if (! mailpid) { if (! (value = GetMailrc(buf))) { if ((s = getenv(buf)) != NULL) value = XtNewString(s); } } else { mailenv = QueryMail("set"); ep = &mailenv[strlen(mailenv)]; for (s = mailenv; s < ep && strncmp(s, buf, length) != 0; s++) for (; s < ep && *s != '\n'; s++); if (! *s) { if (s = getenv(buf)) value = XtNewString(s); } else { /* ** Try to accomodate Berkeley mail (versus SunOS) whose ``set'' ** command returns a sorted list with no equal sign between the ** item and its value. */ if (c = strchr(s, '\n')) *c = '\0'; c = &s[strlen(buf)]; /* point just past the item */ if (*c != '=') { /* We're NOT running Sunmail */ for (;(*c == ' ' || *c == '\t'); c++); if (! *c) value = XtNewString("True"); /* use boolean if no value */ else { if (! (ep = strchr(c+1, '"')) && ! (ep = strchr(c+1, "'"[0]))) value = XtNewString(c); /* most things will be okay */ else { /* if value is fully quoted */ c++; *ep = '\0'; value = XtNewString(c); } } } else { /* We're are running Sunmail */ if (! (c = strchr(s, '"'))) c = strchr(s, "'"[0]); s = c; if (! s) /* variable is flag only, no value */ value = XtNewString("True"); /* use boolean if no value */ else { for (c = ++s; *c && *c != *(s - 1); c++); length = c - s; value = (String) XtMalloc((unsigned) length + 1); (void) strncpy(value, s, length); value[length] = '\0'; } } } } /* * Expand shell variables in value */ if (value) { String v, e, nvalue; while (s = strchr(value, '$')) { for (c = s + 1; *c && !strchr(" \t\n$/\"\'", *c); c++); length = c - s - 1; (void) strncpy(buf, s + 1, length); buf[length] = '\0'; if (*buf == '{') { /* if variable is braced... */ for (v = buf, e = buf + 1; *e && *e != '}';) *v++ = *e++; *v = '\0'; } if (!(e = getenv(buf))) e = ""; if (nvalue = (String) XtMalloc((unsigned) strlen(value) - length + strlen(e) + 2)) { for (c = nvalue, v = value; v != s;) *c++ = *v++; for (s = e; *s;) *c++ = *s++; for (v += length + 1; *v;) *c++ = *v++; *c = '\0'; XtFree((String) value); value = nvalue; } } } return(value); } /* GetMailEnv */ /* ** @(#)mailrcFile() - Return a path to environment or default .mailrc file */ char * mailrcFile(void) { char *s, *getenv(const char *); static char buf[BUFSIZ]; if (s = getenv("MAILRC")) (void) strcpy(buf, s); else (void) sprintf(buf, "%s/.mailrc", HOME); return((char *)buf); } /* mailrcFile */ /* ** @(#)add_to_list - save buffer of aliases in the global alias list */ void add_to_list(String s) { if (! list) { list_length = BUFSIZ; list = (String) XtMalloc((unsigned) list_length); list[0] = '\0'; } for (; *s == ' ' || *s == '\t'; s++); /* skip leading whitespace */ if ((int)strlen(list) + (int)strlen(s) + 1 >= list_length) { list_length += BUFSIZ; list = (String) XtRealloc(list, list_length); } (void) strcat(list, s); /* append the entire line */ } /* end - add_to_list */ /* ** @(#)get_mailrc - item and return it's value ** Handle continuation lines, source of additional files, more ** than one occurance of the item, and aliases/groups. */ int get_mailrc(char *item, char **value, char *filename) { int unset, n, status = 0; int negated = strncmp(item, "no", 2) == 0 ? 1 : 0; int size = strlen(item) - 2 * negated; int we_want_aliases = (strcmp(item, "alias") == 0); String c, d, getenv(const char *), s = NULL; char e[1], tmp[BUFSIZ], buf[BUFSIZ]; FILE *fp = NULL; if ((fp = fopen(filename, "r")) != NULL) { s = fgets(buf, BUFSIZ, fp); while (s) { if (strncmp(buf, "source", 6) == 0) { bcopy(buf + 7, buf, strlen(buf) - 6); LASTCH(buf) = '\0'; /* drop the newline character */ if (buf[0] == '$' || (buf[0] == '~' && buf[1] == '/')) { for (unset = 0, n = 1; buf[n] && buf[n] != '/'; n++) if (! strchr("{()}", buf[n])) tmp[unset++] = buf[n]; tmp[unset] = '\0'; if (tmp[0]) d = getenv(tmp); else d = HOME; (void) sprintf(tmp, "%s%s", d, &buf[n]); (void) strcpy(buf, tmp); } if ((status = get_mailrc(item, &s, buf))) { if (we_want_aliases) *value = list; else { XtFree((String) *value); *value = s; } } /* end - if something was found in another source */ } else { if (we_want_aliases) { if (strncmp(buf,"alias",5) == 0 || strncmp(buf,"group",5) == 0) { status = 1; /* we have found at least one alias */ add_to_list(&buf[5]); if (buf[strlen(buf) - 2] == '\\') { /* alias is continued */ list[strlen(list) - 2] = '\0'; /* drop the "\\n" */ while (s = fgets(buf, BUFSIZ, fp)) { if ((int)strlen(s) > 1 && s[(int)strlen(s) - 2] == '\\') { (void) strcpy(&buf[strlen(buf) - 2], " "); /* drop "\\n" */ add_to_list(s); /* add continuations */ } else break; } if (s) add_to_list(s); /* don't forget the last line */ } /* end - if this is a continued alias definition line */ } /* end - if we found a match */ *value = list; } else { /* I'm looking for 'set' or 'unset' records */ if (! (strncmp(buf, "set", 3) && strncmp(buf, "unset", 5))) { unset = (buf[0] == 'u')? 1:0; /* find out which one matched */ s = &buf[(unset?5:3)]; /* starting just beyond 'set' */ while (*s) { /* could be multiple assigns */ for (; *s && strchr(" \t\\\n", *s); s++); /* next word */ if (*s) { if ((strncmp(s, item, size) != 0) && (!unset || !negated || strncmp(s, &item[2], size) != 0)) for (;*s&&!strchr(" \t\\\n",*s);s++); /* skip item */ else { status = 1; /* we have at least one match */ s = s + size; /* look for a value to it */ if (*s++ != '=') { /* variable only, no value */ XtFree((String) *value); *value = (unset && ! negated)? NULL: XtNewString("True"); } else { if (*s == '"' || *s == "'"[0]) /* if quoted */ for (c = s + 1; *c && *c != *s; c++); else for (c = s--; *c && !strchr(" \t\\\n", *c); c++); e[0] = *c; /* save the current character */ *c = '\0'; /* mark the end of the value */ d = c + 1; /* save point after value */ c = s + 1; /* point to start of value */ XtFree((String) *value); /* toss any previous */ *value = XtNewString(c); /* keep latest value */ s = d--; /* look for any more matches */ *d = e[0]; /* restore saved character */ } /* end - if boolean variable or valued item */ } /* end - we have a match */ } /* end - if some word(s) still exist on the line */ if (! *s && buf[strlen(buf) - 2] == '\\') /* if continued */ s = fgets(buf, BUFSIZ, fp); /* then keep looking */ } /* end - while examining this set|unset record */ } /* end - if we have a set|unset record */ } /* end - looking for alias or set/unset records */ } /* end - if not a ``source'' record */ s = fgets(buf, BUFSIZ, fp); /* now read the next line of the file */ } /* end - while something to read in the mailrc file */ (void) fclose(fp); } return(status); } /* end - get_mailrc */ /* ** @(#)GetMailrc() - Get mail environment variable value from the mailrc file ** Added support for source'd files within the .mailrc file */ char * GetMailrc(char *item) { char *s = NULL; (void) get_mailrc(item, &s, mailrcFile()); return((char *)s); } /* GetMailrc */