summaryrefslogtreecommitdiff
blob: 38b0bf3fd427174b60a5cbd0d2ceaa96ed771832 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "substdio.h"
#include "seek.h"
#include "get_header.h"
#include "stralloc.h"
#include "errtxt.h"
#include "strerr.h"

#define FATAL "get_header: fatal: "

static stralloc line = {0};

static void die_nomem()
{
      strerr_die2x(111,FATAL,ERR_NOMEM);
}

/**
 * This function assumes that input is at the begining of the file;
 * and it returns input to that state when the function has completed.
 * The return is 0 if the header was not found, and 1 otherwise.  If
 * found, the header will be stored in the value stralloc struct.
 */
int get_header(input, name, value)
substdio *input;
char *name;
stralloc *value;
{
  int match = 0;
  int found_start = 0;
  unsigned int len;
  char *cp;

  for (;;) {
    if (getln(input, &line, &match, '\n') == -1)
      strerr_die2sys(111, FATAL,ERR_READ_INPUT);
    if (!match) break;
    if (line.len == 1) break;
    cp = line.s ; len = line.len;
    if (found_start) {
      if ((*cp == ' ' || *cp == '\t')) {
        if (!stralloc_catb(value, cp, len - 1)) die_nomem();
      } else {
        break;
      }
    } else {
      if (case_startb(cp,len,"from:")) {
        if (!stralloc_copyb(value, cp, len - 1)) die_nomem();
        found_start = 1;
      }
    }
  }

  if (seek_begin(input->fd) == -1)
    strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);

  return found_start;
}

/**
 * This function makes the same assumptions about input as get_header :
 * it should be at the begining of the file, and once done, seek will
 * be used to return it there.  The return value is an e-mail address if
 * one can be found, or null otherwise.  No attempt is made to validate
 * the email address, and the work done for parsing it is relatively 
 * simplistic; it will handle the following forms as shown:
 *
 * username@domain                             => username@domain
 * "Name <username@domain>"                    => username@domain
 * username1@domain, username2@domain          => username1@domain
 * username1@domain, "Name <username2@domain>" => username2@domain
 *
 * If junk is present in the From: header, this will return that.  This
 * function may not be appropriate if a valid e-mail address is required.
 */
char *get_from(input)
substdio *input;
{
  stralloc from_header = {0};
  int from_complete = 0, i;
  char *from_addr = (char *) 0;

  if (!get_header(input, "from:", &from_header))
    return (char *) 0;

  /* issub uses a char *, and stralloc structures aren't null
   * terminated -- they're ... 'Z' terminated ...
   * but the stuff in from_header is a copy anyway ... we'll modify it so
   * we don't have to do strcpy or somesuch.
   */
  for (i = strlen("from:") ; i < from_header.len ; ++i) {
    if (*(from_header.s + i) == '<') {
      from_addr = from_header.s + (i + 1);
    } else if (from_addr && *(from_header.s + i) == '>') {
      from_complete = 1;
      *(from_header.s+i) = '\0'; /* null terminate so from_addr is valid */
      break;
    }
  }
  if (!from_complete) { /* <...> not found ... assume a simpler format */
    for(i = strlen("from:") ; i < from_header.len ; ++i) {
      if (!from_addr && *(from_header.s + i) != ' ') {
        from_addr = from_header.s + i;
      } else if (from_addr && isspace(*(from_header.s + i)) ||
          *(from_header.s + i) == ',') {
        break;
      }
    }
    *(from_header.s + i) = '\0'; /* this is safe even if i == from_header.len */
                                 /* because strallocs have an extra char      */
  }
  return from_addr;
}