Logo Search packages:      
Sourcecode: nagios-plugin-check-multi version File versions  Download package

head.c

/*
 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
 *
 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
 */
/*
 * Copyright (c) 1980, 1993
 *    The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the University of
 *    California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
#ifdef      DOSCCS
static char sccsid[] = "@(#)head.c  2.17 (gritter) 3/4/06";
#endif
#endif /* not lint */

#include "rcv.h"
#include "extern.h"
#include <time.h>

/*
 * Mail -- a mail program
 *
 * Routines for processing and detecting headlines.
 */

static char *copyin(char *src, char **space);
static char *nextword(char *wp, char *wbuf);
static int gethfield(FILE *f, char **linebuf, size_t *linesize, int rem,
            char **colon);
static int msgidnextc(const char **cp, int *status);
static int charcount(char *str, int c);

/*
 * See if the passed line buffer is a mail header.
 * Return true if yes.  POSIX.2 leaves the content
 * following 'From ' unspecified, so don't care about
 * it.
 */
/*ARGSUSED 2*/
int
is_head(char *linebuf, size_t linelen)
{
      char *cp;

      cp = linebuf;
      if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' ||
          *cp++ != ' ')
            return (0);
      return(1);
}

/*
 * Split a headline into its useful components.
 * Copy the line into dynamic string space, then set
 * pointers into the copied line in the passed headline
 * structure.  Actually, it scans.
 */
void
parse(char *line, size_t linelen, struct headline *hl, char *pbuf)
{
      char *cp;
      char *sp;
      char *word;

      hl->l_from = NULL;
      hl->l_tty = NULL;
      hl->l_date = NULL;
      cp = line;
      sp = pbuf;
      word = ac_alloc(linelen + 1);
      /*
       * Skip over "From" first.
       */
      cp = nextword(cp, word);
      cp = nextword(cp, word);
      if (*word)
            hl->l_from = copyin(word, &sp);
      if (cp != NULL && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') {
            cp = nextword(cp, word);
            hl->l_tty = copyin(word, &sp);
      }
      if (cp != NULL)
            hl->l_date = copyin(cp, &sp);
      else
            hl->l_date = catgets(catd, CATSET, 213, "<Unknown date>");
      ac_free(word);
}

/*
 * Copy the string on the left into the string on the right
 * and bump the right (reference) string pointer by the length.
 * Thus, dynamically allocate space in the right string, copying
 * the left string into it.
 */
static char *
copyin(char *src, char **space)
{
      char *cp;
      char *top;

      top = cp = *space;
      while ((*cp++ = *src++) != '\0')
            ;
      *space = cp;
      return (top);
}

#ifdef      notdef
static int  cmatch(char *, char *);
/*
 * Test to see if the passed string is a ctime(3) generated
 * date string as documented in the manual.  The template
 * below is used as the criterion of correctness.
 * Also, we check for a possible trailing time zone using
 * the tmztype template.
 */

/*
 * 'A'      An upper case char
 * 'a'      A lower case char
 * ' '      A space
 * '0'      A digit
 * 'O'      An optional digit or space
 * ':'      A colon
 * '+'      A sign
 * 'N'      A new line
 */
static char  *tmztype[] = {
      "Aaa Aaa O0 00:00:00 0000",
      "Aaa Aaa O0 00:00 0000",
      "Aaa Aaa O0 00:00:00 AAA 0000",
      "Aaa Aaa O0 00:00 AAA 0000",
      /*
       * Sommer time, e.g. MET DST
       */
      "Aaa Aaa O0 00:00:00 AAA AAA 0000",
      "Aaa Aaa O0 00:00 AAA AAA 0000",
      /*
       * time zone offset, e.g.
       * +0200 or +0200 MET or +0200 MET DST
       */
      "Aaa Aaa O0 00:00:00 +0000 0000",
      "Aaa Aaa O0 00:00 +0000 0000",
      "Aaa Aaa O0 00:00:00 +0000 AAA 0000",
      "Aaa Aaa O0 00:00 +0000 AAA 0000",
      "Aaa Aaa O0 00:00:00 +0000 AAA AAA 0000",
      "Aaa Aaa O0 00:00 +0000 AAA AAA 0000",
      /*
       * time zone offset without time zone specification (pine)
       */
      "Aaa Aaa O0 00:00:00 0000 +0000",
      NULL,
};

static int 
is_date(char *date)
{
      int ret = 0, form = 0;

      while (tmztype[form]) {
            if ( (ret = cmatch(date, tmztype[form])) == 1 )
                  break;
            form++;
      }

      return ret;
}

/*
 * Match the given string (cp) against the given template (tp).
 * Return 1 if they match, 0 if they don't
 */
static int 
cmatch(char *cp, char *tp)
{
      int c;

      while (*cp && *tp)
            switch (*tp++) {
            case 'a':
                  if (c = *cp++, !lowerchar(c))
                        return 0;
                  break;
            case 'A':
                  if (c = *cp++, !upperchar(c))
                        return 0;
                  break;
            case ' ':
                  if (*cp++ != ' ')
                        return 0;
                  break;
            case '0':
                  if (c = *cp++, !digitchar(c))
                        return 0;
                  break;
            case 'O':
                  if (c = *cp, c != ' ' && !digitchar(c))
                        return 0;
                  cp++;
                  break;
            case ':':
                  if (*cp++ != ':')
                        return 0;
                  break;
            case '+':
                  if (*cp != '+' && *cp != '-')
                        return 0;
                  cp++;
                  break;
            case 'N':
                  if (*cp++ != '\n')
                        return 0;
                  break;
            }
      if (*cp || *tp)
            return 0;
      return (1);
}
#endif      /* notdef */

/*
 * Collect a liberal (space, tab delimited) word into the word buffer
 * passed.  Also, return a pointer to the next word following that,
 * or NULL if none follow.
 */
static char *
nextword(char *wp, char *wbuf)
{
      int c;

      if (wp == NULL) {
            *wbuf = 0;
            return (NULL);
      }
      while ((c = *wp++) != '\0' && !blankchar(c)) {
            *wbuf++ = c;
            if (c == '"') {
                  while ((c = *wp++) != '\0' && c != '"')
                        *wbuf++ = c;
                  if (c == '"')
                        *wbuf++ = c;
                  else
                        wp--;
            }
      }
      *wbuf = '\0';
      for (; blankchar(c); c = *wp++)
            ;
      if (c == 0)
            return (NULL);
      return (wp - 1);
}

void
extract_header(FILE *fp, struct header *hp)
{
      char *linebuf = NULL;
      size_t linesize = 0;
      int seenfields = 0;
      char *colon, *cp, *value;
      struct header nh;
      struct header *hq = &nh;
      int lc, c;

      memset(hq, 0, sizeof *hq);
      for (lc = 0; readline(fp, &linebuf, &linesize) > 0; lc++);
      rewind(fp);
      while ((lc = gethfield(fp, &linebuf, &linesize, lc, &colon)) >= 0) {
            if ((value = thisfield(linebuf, "to")) != NULL) {
                  seenfields++;
                  hq->h_to = checkaddrs(cat(hq->h_to,
                              sextract(value, GTO|GFULL)));
            } else if ((value = thisfield(linebuf, "cc")) != NULL) {
                  seenfields++;
                  hq->h_cc = checkaddrs(cat(hq->h_cc,
                              sextract(value, GCC|GFULL)));
            } else if ((value = thisfield(linebuf, "bcc")) != NULL) {
                  seenfields++;
                  hq->h_bcc = checkaddrs(cat(hq->h_bcc,
                              sextract(value, GBCC|GFULL)));
            } else if ((value = thisfield(linebuf, "from")) != NULL) {
                  seenfields++;
                  hq->h_from = checkaddrs(cat(hq->h_from,
                              sextract(value, GEXTRA|GFULL)));
            } else if ((value = thisfield(linebuf, "reply-to")) != NULL) {
                  seenfields++;
                  hq->h_replyto = checkaddrs(cat(hq->h_replyto,
                              sextract(value, GEXTRA|GFULL)));
            } else if ((value = thisfield(linebuf, "sender")) != NULL) {
                  seenfields++;
                  hq->h_sender = checkaddrs(cat(hq->h_sender,
                              sextract(value, GEXTRA|GFULL)));
            } else if ((value = thisfield(linebuf,
                                    "organization")) != NULL) {
                  seenfields++;
                  for (cp = value; blankchar(*cp & 0377); cp++);
                  hq->h_organization = hq->h_organization ?
                        save2str(hq->h_organization, cp) :
                        savestr(cp);
            } else if ((value = thisfield(linebuf, "subject")) != NULL ||
                        (value = thisfield(linebuf, "subj")) != NULL) {
                  seenfields++;
                  for (cp = value; blankchar(*cp & 0377); cp++);
                  hq->h_subject = hq->h_subject ?
                        save2str(hq->h_subject, cp) :
                        savestr(cp);
            } else
                  fprintf(stderr, catgets(catd, CATSET, 266,
                              "Ignoring header field \"%s\"\n"),
                              linebuf);
      }
      /*
       * In case the blank line after the header has been edited out.
       * Otherwise, fetch the header separator.
       */
      if (linebuf) {
            if (linebuf[0] != '\0') {
                  for (cp = linebuf; *(++cp) != '\0'; );
                  fseek(fp, (long)-(1 + cp - linebuf), SEEK_CUR);
            } else {
                  if ((c = getc(fp)) != '\n' && c != EOF)
                        ungetc(c, fp);
            }
      }
      if (seenfields) {
            hp->h_to = hq->h_to;
            hp->h_cc = hq->h_cc;
            hp->h_bcc = hq->h_bcc;
            hp->h_from = hq->h_from;
            hp->h_replyto = hq->h_replyto;
            hp->h_sender = hq->h_sender;
            hp->h_organization = hq->h_organization;
            hp->h_subject = hq->h_subject;
      } else
            fprintf(stderr, catgets(catd, CATSET, 267,
                        "Restoring deleted header lines\n"));
      if (linebuf)
            free(linebuf);
}

/*
 * Return the desired header line from the passed message
 * pointer (or NULL if the desired header field is not available).
 * If mult is zero, return the content of the first matching header
 * field only, the content of all matching header fields else.
 */
char *
hfield_mult(char *field, struct message *mp, int mult)
{
      FILE *ibuf;
      char *linebuf = NULL;
      size_t linesize = 0;
      int lc;
      char *hfield;
      char *colon, *oldhfield = NULL;

      if ((ibuf = setinput(&mb, mp, NEED_HEADER)) == NULL)
            return NULL;
      if ((lc = mp->m_lines - 1) < 0)
            return NULL;
      if ((mp->m_flag & MNOFROM) == 0) {
            if (readline(ibuf, &linebuf, &linesize) < 0) {
                  if (linebuf)
                        free(linebuf);
                  return NULL;
            }
      }
      while (lc > 0) {
            if ((lc = gethfield(ibuf, &linebuf, &linesize, lc, &colon))
                        < 0) {
                  if (linebuf)
                        free(linebuf);
                  return oldhfield;
            }
            if ((hfield = thisfield(linebuf, field)) != NULL) {
                  oldhfield = save2str(hfield, oldhfield);
                  if (mult == 0)
                        break;
            }
      }
      if (linebuf)
            free(linebuf);
      return oldhfield;
}

/*
 * Return the next header field found in the given message.
 * Return >= 0 if something found, < 0 elsewise.
 * "colon" is set to point to the colon in the header.
 * Must deal with \ continuations & other such fraud.
 */
static int
gethfield(FILE *f, char **linebuf, size_t *linesize, int rem, char **colon)
{
      char *line2 = NULL;
      size_t line2size = 0;
      char *cp, *cp2;
      int c, isenc;

      if (*linebuf == NULL)
            *linebuf = srealloc(*linebuf, *linesize = 1);
      **linebuf = '\0';
      for (;;) {
            if (--rem < 0)
                  return -1;
            if ((c = readline(f, linebuf, linesize)) <= 0)
                  return -1;
            for (cp = *linebuf; fieldnamechar(*cp & 0377); cp++);
            if (cp > *linebuf)
                  while (blankchar(*cp & 0377))
                        cp++;
            if (*cp != ':' || cp == *linebuf)
                  continue;
            /*
             * I guess we got a headline.
             * Handle wraparounding
             */
            *colon = cp;
            cp = *linebuf + c;
            for (;;) {
                  isenc = 0;
                  while (--cp >= *linebuf && blankchar(*cp & 0377));
                  cp++;
                  if (rem <= 0)
                        break;
                  if (cp-8 >= *linebuf && cp[-1] == '=' && cp[-2] == '?')
                        isenc |= 1;
                  ungetc(c = getc(f), f);
                  if (!blankchar(c))
                        break;
                  if ((c = readline(f, &line2, &line2size)) < 0)
                        break;
                  rem--;
                  for (cp2 = line2; blankchar(*cp2 & 0377); cp2++);
                  c -= cp2 - line2;
                  if (cp2[0] == '=' && cp2[1] == '?' && c > 8)
                        isenc |= 2;
                  if (cp + c >= *linebuf + *linesize - 2) {
                        size_t diff = cp - *linebuf;
                        size_t colondiff = *colon - *linebuf;
                        *linebuf = srealloc(*linebuf,
                                    *linesize += c + 2);
                        cp = &(*linebuf)[diff];
                        *colon = &(*linebuf)[colondiff];
                  }
                  if (isenc != 3)
                        *cp++ = ' ';
                  memcpy(cp, cp2, c);
                  cp += c;
            }
            *cp = 0;
            if (line2)
                  free(line2);
            return rem;
      }
      /* NOTREACHED */
}

/*
 * Check whether the passed line is a header line of
 * the desired breed.  Return the field body, or 0.
 */
char *
thisfield(const char *linebuf, const char *field)
{
      while (lowerconv(*linebuf&0377) == lowerconv(*field&0377)) {
            linebuf++;
            field++;
      }
      if (*field != '\0')
            return NULL;
      while (blankchar(*linebuf&0377))
            linebuf++;
      if (*linebuf++ != ':')
            return NULL;
      while (blankchar(*linebuf&0377))
            linebuf++;
      return (char *)linebuf;
}

/*
 * Get sender's name from this message.  If the message has
 * a bunch of arpanet stuff in it, we may have to skin the name
 * before returning it.
 */
char *
nameof(struct message *mp, int reptype)
{
      char *cp, *cp2;

      cp = skin(name1(mp, reptype));
      if (reptype != 0 || charcount(cp, '!') < 2)
            return(cp);
      cp2 = strrchr(cp, '!');
      cp2--;
      while (cp2 > cp && *cp2 != '!')
            cp2--;
      if (*cp2 == '!')
            return(cp2 + 1);
      return(cp);
}

/*
 * Start of a "comment".
 * Ignore it.
 */
char *
skip_comment(const char *cp)
{
      int nesting = 1;

      for (; nesting > 0 && *cp; cp++) {
            switch (*cp) {
            case '\\':
                  if (cp[1])
                        cp++;
                  break;
            case '(':
                  nesting++;
                  break;
            case ')':
                  nesting--;
                  break;
            }
      }
      return (char *)cp;
}

/*
 * Return the start of a route-addr (address in angle brackets),
 * if present.
 */
char *
routeaddr(const char *name)
{
      const char  *np, *rp = NULL;

      for (np = name; *np; np++) {
            switch (*np) {
            case '(':
                  np = skip_comment(&np[1]) - 1;
                  break;
            case '"':
                  while (*np) {
                        if (*++np == '"')
                              break;
                        if (*np == '\\' && np[1])
                              np++;
                  }
                  break;
            case '<':
                  rp = np;
                  break;
            case '>':
                  return (char *)rp;
            }
      }
      return NULL;
}

/*
 * Skin an arpa net address according to the RFC 822 interpretation
 * of "host-phrase."
 */
char *
skin(char *name)
{
      int c;
      char *cp, *cp2;
      char *bufend;
      int gotlt, lastsp;
      char *nbuf;

      if (name == NULL)
            return(NULL);
      if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
          && strchr(name, ' ') == NULL)
            return(name);
      gotlt = 0;
      lastsp = 0;
      nbuf = ac_alloc(strlen(name) + 1);
      bufend = nbuf;
      for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
            switch (c) {
            case '(':
                  cp = skip_comment(cp);
                  lastsp = 0;
                  break;

            case '"':
                  /*
                   * Start of a "quoted-string".
                   * Copy it in its entirety.
                   */
                  *cp2++ = c;
                  while ((c = *cp) != '\0') {
                        cp++;
                        if (c == '"') {
                              *cp2++ = c;
                              break;
                        }
                        if (c != '\\')
                              *cp2++ = c;
                        else if ((c = *cp) != '\0') {
                              *cp2++ = c;
                              cp++;
                        }
                  }
                  lastsp = 0;
                  break;

            case ' ':
                  if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
                        cp += 3, *cp2++ = '@';
                  else
                  if (cp[0] == '@' && cp[1] == ' ')
                        cp += 2, *cp2++ = '@';
#if 0
                  /*
                   * RFC 822 specifies spaces are STRIPPED when
                   * in an adress specifier.
                   */
                  else
                        lastsp = 1;
#endif
                  break;

            case '<':
                  cp2 = bufend;
                  gotlt++;
                  lastsp = 0;
                  break;

            case '>':
                  if (gotlt) {
                        gotlt = 0;
                        while ((c = *cp) != '\0' && c != ',') {
                              cp++;
                              if (c == '(')
                                    cp = skip_comment(cp);
                              else if (c == '"')
                                    while ((c = *cp) != '\0') {
                                          cp++;
                                          if (c == '"')
                                                break;
                                          if (c == '\\' && *cp)
                                                cp++;
                                    }
                        }
                        lastsp = 0;
                        break;
                  }
                  /* Fall into . . . */

            default:
                  if (lastsp) {
                        lastsp = 0;
                        *cp2++ = ' ';
                  }
                  *cp2++ = c;
                  if (c == ',' && !gotlt) {
                        *cp2++ = ' ';
                        for (; *cp == ' '; cp++)
                              ;
                        lastsp = 0;
                        bufend = cp2;
                  }
            }
      }
      *cp2 = 0;
      cp = savestr(nbuf);
      ac_free(nbuf);
      return cp;
}

/*
 * Fetch the real name from an internet mail address field.
 */
char *
realname(char *name)
{
      char  *cstart = NULL, *cend = NULL, *cp, *cq;
      char  *rname, *rp;
      struct str  in, out;
      int   quoted, good, nogood;

      if (name == NULL)
            return NULL;
      for (cp = name; *cp; cp++) {
            switch (*cp) {
            case '(':
                  if (cstart)
                        /*
                         * More than one comment in address, doesn't
                         * make sense to display it without context.
                         * Return the entire field,
                         */
                        return mime_fromaddr(name);
                  cstart = cp++;
                  cp = skip_comment(cp);
                  cend = cp--;
                  if (cend <= cstart)
                        cend = cstart = NULL;
                  break;
            case '"':
                  while (*cp) {
                        if (*++cp == '"')
                              break;
                        if (*cp == '\\' && cp[1])
                              cp++;
                  }
                  break;
            case '<':
                  if (cp > name) {
                        cstart = name;
                        cend = cp;
                  }
                  break;
            case ',':
                  /*
                   * More than one address. Just use the first one.
                   */
                  goto brk;
            }
      }
brk:  if (cstart == NULL) {
            if (*name == '<')
                  /*
                   * If name contains only a route-addr, the
                   * surrounding angle brackets don't serve any
                   * useful purpose when displaying, so they
                   * are removed.
                   */
                  return prstr(skin(name));
            return mime_fromaddr(name);
      }
      rp = rname = ac_alloc(cend - cstart + 1);
      /*
       * Strip quotes. Note that quotes that appear within a MIME-
       * encoded word are not stripped. The idea is to strip only
       * syntactical relevant things (but this is not necessarily
       * the most sensible way in practice).
       */
      quoted = 0;
      for (cp = cstart; cp < cend; cp++) {
            if (*cp == '(' && !quoted) {
                  cq = skip_comment(++cp);
                  if (--cq > cend)
                        cq = cend;
                  while (cp < cq) {
                        if (*cp == '\\' && &cp[1] < cq)
                              cp++;
                        *rp++ = *cp++;
                  }
            } else if (*cp == '\\' && &cp[1] < cend)
                  *rp++ = *++cp;
            else if (*cp == '"') {
                  quoted = !quoted;
                  continue;
            } else
                  *rp++ = *cp;
      }
      *rp = '\0';
      in.s = rname;
      in.l = rp - rname;
      mime_fromhdr(&in, &out, TD_ISPR|TD_ICONV);
      ac_free(rname);
      rname = savestr(out.s);
      free(out.s);
      while (blankchar(*rname & 0377))
            rname++;
      for (rp = rname; *rp; rp++);
      while (--rp >= rname && blankchar(*rp & 0377))
            *rp = '\0';
      if (rp == rname)
            return mime_fromaddr(name);
      /*
       * mime_fromhdr() has converted all nonprintable characters to
       * question marks now. These and blanks are considered uninteresting;
       * if the displayed part of the real name contains more than 25% of
       * them, it is probably better to display the plain email address
       * instead.
       */
      good = 0;
      nogood = 0;
      for (rp = rname; *rp && rp < &rname[20]; rp++)
            if (*rp == '?' || blankchar(*rp & 0377))
                  nogood++;
            else
                  good++;
      if (good*3 < nogood)
            return prstr(skin(name));
      return rname;
}

/*
 * Fetch the sender's name from the passed message.
 * Reptype can be
 *    0 -- get sender's name for display purposes
 *    1 -- get sender's name for reply
 *    2 -- get sender's name for Reply
 */
char *
name1(struct message *mp, int reptype)
{
      char *namebuf;
      size_t namesize;
      char *linebuf = NULL;
      size_t linesize = 0;
      char *cp, *cp2;
      FILE *ibuf;
      int first = 1;

      if ((cp = hfield("from", mp)) != NULL && *cp != '\0')
            return cp;
      if (reptype == 0 && (cp = hfield("sender", mp)) != NULL &&
                  *cp != '\0')
            return cp;
      namebuf = smalloc(namesize = 1);
      namebuf[0] = 0;
      if (mp->m_flag & MNOFROM)
            goto out;
      if ((ibuf = setinput(&mb, mp, NEED_HEADER)) == NULL)
            goto out;
      if (readline(ibuf, &linebuf, &linesize) < 0)
            goto out;
newname:
      if (namesize <= linesize)
            namebuf = srealloc(namebuf, namesize = linesize + 1);
      for (cp = linebuf; *cp && *cp != ' '; cp++)
            ;
      for (; blankchar(*cp & 0377); cp++);
      for (cp2 = &namebuf[strlen(namebuf)];
           *cp && !blankchar(*cp & 0377) && cp2 < namebuf + namesize - 1;)
            *cp2++ = *cp++;
      *cp2 = '\0';
      if (readline(ibuf, &linebuf, &linesize) < 0)
            goto out;
      if ((cp = strchr(linebuf, 'F')) == NULL)
            goto out;
      if (strncmp(cp, "From", 4) != 0)
            goto out;
      if (namesize <= linesize)
            namebuf = srealloc(namebuf, namesize = linesize + 1);
      while ((cp = strchr(cp, 'r')) != NULL) {
            if (strncmp(cp, "remote", 6) == 0) {
                  if ((cp = strchr(cp, 'f')) == NULL)
                        break;
                  if (strncmp(cp, "from", 4) != 0)
                        break;
                  if ((cp = strchr(cp, ' ')) == NULL)
                        break;
                  cp++;
                  if (first) {
                        strncpy(namebuf, cp, namesize);
                        first = 0;
                  } else {
                        cp2=strrchr(namebuf, '!')+1;
                        strncpy(cp2, cp, (namebuf+namesize)-cp2);
                  }
                  namebuf[namesize-2]='\0';
                  strcat(namebuf, "!");
                  goto newname;
            }
            cp++;
      }
out:
      if (*namebuf != '\0' || ((cp = hfield("return-path", mp))) == NULL ||
                  *cp == '\0')
            cp = savestr(namebuf);
      if (linebuf)
            free(linebuf);
      free(namebuf);
      return cp;
}

static int 
msgidnextc(const char **cp, int *status)
{
      int   c;

      for (;;) {
            if (*status & 01) {
                  if (**cp == '"') {
                        *status &= ~01;
                        (*cp)++;
                        continue;
                  }
                  if (**cp == '\\') {
                        (*cp)++;
                        if (**cp == '\0')
                              goto eof;
                  }
                  goto dfl;
            }
            switch (**cp) {
            case '(':
                  *cp = skip_comment(&(*cp)[1]);
                  continue;
            case '>':
            case '\0':
            eof:
                  return '\0';
            case '"':
                  (*cp)++;
                  *status |= 01;
                  continue;
            case '@':
                  *status |= 02;
                  /*FALLTHRU*/
            default:
            dfl:
                  c = *(*cp)++ & 0377;
                  return *status & 02 ? lowerconv(c) : c;
            }
      }
}

int 
msgidcmp(const char *s1, const char *s2)
{
      int   q1 = 0, q2 = 0;
      int   c1, c2;

      do {
            c1 = msgidnextc(&s1, &q1);
            c2 = msgidnextc(&s2, &q2);
            if (c1 != c2)
                  return c1 - c2;
      } while (c1 && c2);
      return c1 - c2;
}

/*
 * Count the occurances of c in str
 */
static int 
charcount(char *str, int c)
{
      char *cp;
      int i;

      for (i = 0, cp = str; *cp; cp++)
            if (*cp == c)
                  i++;
      return(i);
}

/*
 * See if the given header field is supposed to be ignored.
 */
int
is_ign(char *field, size_t fieldlen, struct ignoretab ignore[2])
{
      char *realfld;
      int ret;

      if (ignore == NULL)
            return 0;
      if (ignore == allignore)
            return 1;
      /*
       * Lower-case the string, so that "Status" and "status"
       * will hash to the same place.
       */
      realfld = ac_alloc(fieldlen + 1);
      i_strcpy(realfld, field, fieldlen + 1);
      if (ignore[1].i_count > 0)
            ret = !member(realfld, ignore + 1);
      else
            ret = member(realfld, ignore);
      ac_free(realfld);
      return ret;
}

int 
member(char *realfield, struct ignoretab *table)
{
      struct ignore *igp;

      for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
            if (*igp->i_field == *realfield &&
                equal(igp->i_field, realfield))
                  return (1);
      return (0);
}

/*
 * Fake Sender for From_ lines if missing, e. g. with POP3.
 */
char *
fakefrom(struct message *mp)
{
      char *name;

      if (((name = skin(hfield("return-path", mp))) == NULL ||
                        *name == '\0' ) &&
                  ((name = skin(hfield("from", mp))) == NULL ||
                        *name == '\0'))
            name = "-";
      return name;
}

char *
fakedate(time_t t)
{
      char *cp, *cq;

      cp = ctime(&t);
      for (cq = cp; *cq && *cq != '\n'; cq++);
      *cq = '\0';
      return savestr(cp);
}

char *
nexttoken(char *cp)
{
      for (;;) {
            if (*cp == '\0')
                  return NULL;
            if (*cp == '(') {
                  int nesting = 0;

                  while (*cp != '\0') {
                        switch (*cp++) {
                        case '(':
                              nesting++;
                              break;
                        case ')':
                              nesting--;
                              break;
                        }
                        if (nesting <= 0)
                              break;
                  }
            } else if (blankchar(*cp & 0377) || *cp == ',')
                  cp++;
            else
                  break;
      }
      return cp;
}

/*
 * From username Fri Jan  2 20:13:51 2004
 *               |    |    |    |    | 
 *               0    5   10   15   20
 */
time_t
unixtime(char *from)
{
      char  *fp, *xp;
      time_t      t;
      int   i, year, month, day, hour, minute, second;
      int   tzdiff;
      struct tm   *tmptr;

      for (fp = from; *fp && *fp != '\n'; fp++);
      fp -= 24;
      if (fp - from < 7)
            goto invalid;
      if (fp[3] != ' ')
            goto invalid;
      for (i = 0; month_names[i]; i++)
            if (strncmp(&fp[4], month_names[i], 3) == 0)
                  break;
      if (month_names[i] == 0)
            goto invalid;
      month = i + 1;
      if (fp[7] != ' ')
            goto invalid;
      day = strtol(&fp[8], &xp, 10);
      if (*xp != ' ' || xp != &fp[10])
            goto invalid;
      hour = strtol(&fp[11], &xp, 10);
      if (*xp != ':' || xp != &fp[13])
            goto invalid;
      minute = strtol(&fp[14], &xp, 10);
      if (*xp != ':' || xp != &fp[16])
            goto invalid;
      second = strtol(&fp[17], &xp, 10);
      if (*xp != ' ' || xp != &fp[19])
            goto invalid;
      year = strtol(&fp[20], &xp, 10);
      if (xp != &fp[24])
            goto invalid;
      if ((t = combinetime(year, month, day, hour, minute, second)) ==
                  (time_t)-1)
            goto invalid;
      tzdiff = t - mktime(gmtime(&t));
      tmptr = localtime(&t);
      if (tmptr->tm_isdst > 0)
            tzdiff += 3600;
      t -= tzdiff;
      return t;
invalid:
      time(&t);
      return t;
}

time_t
rfctime(char *date)
{
      char *cp = date, *x;
      time_t t;
      int i, year, month, day, hour, minute, second;

      if ((cp = nexttoken(cp)) == NULL)
            goto invalid;
      if (alphachar(cp[0] & 0377) && alphachar(cp[1] & 0377) &&
                        alphachar(cp[2] & 0377) && cp[3] == ',') {
            if ((cp = nexttoken(&cp[4])) == NULL)
                  goto invalid;
      }
      day = strtol(cp, &x, 10);
      if ((cp = nexttoken(x)) == NULL)
            goto invalid;
      for (i = 0; month_names[i]; i++) {
            if (strncmp(cp, month_names[i], 3) == 0)
                  break;
      }
      if (month_names[i] == NULL)
            goto invalid;
      month = i + 1;
      if ((cp = nexttoken(&cp[3])) == NULL)
            goto invalid;
      year = strtol(cp, &x, 10);
      if ((cp = nexttoken(x)) == NULL)
            goto invalid;
      hour = strtol(cp, &x, 10);
      if (*x != ':')
            goto invalid;
      cp = &x[1];
      minute = strtol(cp, &x, 10);
      if (*x == ':') {
            cp = &x[1];
            second = strtol(cp, &x, 10);
      } else
            second = 0;
      if ((t = combinetime(year, month, day, hour, minute, second)) ==
                  (time_t)-1)
            goto invalid;
      if ((cp = nexttoken(x)) != NULL) {
            int sign = -1;
            char buf[3];

            switch (*cp) {
            case '-':
                  sign = 1;
                  /*FALLTHRU*/
            case '+':
                  cp++;
            }
            if (digitchar(cp[0] & 0377) && digitchar(cp[1] & 0377) &&
                        digitchar(cp[2] & 0377) &&
                        digitchar(cp[3] & 0377)) {
                  buf[2] = '\0';
                  buf[0] = cp[0];
                  buf[1] = cp[1];
                  t += strtol(buf, NULL, 10) * sign * 3600;
                  buf[0] = cp[2];
                  buf[1] = cp[3];
                  t += strtol(buf, NULL, 10) * sign * 60;
            }
      }
      return t;
invalid:
      return 0;
}

#define     leapyear(year)    ((year % 100 ? year : year / 100) % 4 == 0)

time_t
combinetime(int year, int month, int day, int hour, int minute, int second)
{
      time_t t;

      if (second < 0 || minute < 0 || hour < 0 || day < 1)
            return -1;
      t = second + minute * 60 + hour * 3600 + (day - 1) * 86400;
      if (year < 70)
            year += 2000;
      else if (year < 1900)
            year += 1900;
      if (month > 1)
            t += 86400 * 31;
      if (month > 2)
            t += 86400 * (leapyear(year) ? 29 : 28);
      if (month > 3)
            t += 86400 * 31;
      if (month > 4)
            t += 86400 * 30;
      if (month > 5)
            t += 86400 * 31;
      if (month > 6)
            t += 86400 * 30;
      if (month > 7)
            t += 86400 * 31;
      if (month > 8)
            t += 86400 * 31;
      if (month > 9)
            t += 86400 * 30;
      if (month > 10)
            t += 86400 * 31;
      if (month > 11)
            t += 86400 * 30;
      year -= 1900;
      t += (year - 70) * 31536000 + ((year - 69) / 4) * 86400 -
            ((year - 1) / 100) * 86400 + ((year + 299) / 400) * 86400;
      return t;
}

void 
substdate(struct message *m)
{
      char *cp;
      time_t now;

      /*
       * Determine the date to print in faked 'From ' lines. This is
       * traditionally the date the message was written to the mail
       * file. Try to determine this using RFC message header fields,
       * or fall back to current time.
       */
      time(&now);
      if ((cp = hfield_mult("received", m, 0)) != NULL) {
            while ((cp = nexttoken(cp)) != NULL && *cp != ';') {
                  do
                        cp++;
                  while (alnumchar(*cp & 0377));
            }
            if (cp && *++cp)
                  m->m_time = rfctime(cp);
      }
      if (m->m_time == 0 || m->m_time > now)
            if ((cp = hfield("date", m)) != NULL)
                  m->m_time = rfctime(cp);
      if (m->m_time == 0 || m->m_time > now)
            m->m_time = now;
}

int
check_from_and_sender(struct name *fromfield, struct name *senderfield)
{
      if (fromfield && fromfield->n_flink && senderfield == NULL) {
            fprintf(stderr, "A Sender: field is required with multiple "
                        "addresses in From: field.\n");
            return 1;
      }
      if (senderfield && senderfield->n_flink) {
            fprintf(stderr, "The Sender: field may contain "
                        "only one address.\n");
            return 2;
      }
      return 0;
}

char *
getsender(struct message *mp)
{
      char  *cp;
      struct name *np;

      if ((cp = hfield("from", mp)) == NULL ||
                  (np = sextract(cp, GEXTRA|GSKIN)) == NULL)
            return NULL;
      return np->n_flink != NULL ? skin(hfield("sender", mp)) : np->n_name;
}

Generated by  Doxygen 1.6.0   Back to index