/*
* 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[>]",
** "<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 '<addr> [(]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 <addr>'? 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 <address> 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 */
syntax highlighted by Code2HTML, v. 0.9.1