Commit a9a11cf9 a9a11cf95bbfad541ae242cffecb963065621fa1 by Alain Magloire

Updates from Sam Roberts.

1 parent 3e158c93
......@@ -33,28 +33,54 @@
/* Get email address from rfc822 address. */
int
address_create (address_t *a, const char *p)
address_create (address_t *a, const char *s)
{
/* 'paddress' must exist, and can't already have been initialized
*/
int status;
char *s; /* FIXME: Remove when done, see below */
const char *e;
const char *save;
char *fb;
if (!a)
return EINVAL;
*a = NULL;
save = s;
e = &s[strlen (s)];
fb = calloc (1, 1);
/* FIXME: parse822 does not seem to like '\n' in the field body
take care of it here until the proper fix. */
s = strdup (p);
/* We need to unfold the string. Do the same thing as parse822_field_body()
but we have to be more flexible in allowing bare '\n' as CRLF. */
for (;;)
{
char *nl = s;
while ((nl = strchr (nl, '\n')))
*nl++ = ' ';
const char *eol = s;
size_t len = strlen (fb);
while (eol != e)
{
/* if (eol[0] == '\r' && (eol+1) != e && eol[1] == '\n') */
if (*eol == '\n')
break;
++eol;
}
fb = realloc (fb, len + (eol - s) + 1);
memcpy (fb + len , s, eol - s);
fb[len + (eol - s)] = '\0';
s = eol;
s += 2;
if (s == e)
break; /* no more, so we're done */
/* check if next line is a continuation line */
if (*s != ' ' && *s != '\t')
break;
}
status = parse822_address_list (a, (char*) s);
status = parse822_address_list (a, (char*) fb);
free (fb);
if (status == 0)
{
/* And address-list may contain 0 addresses but parse correctly.
......@@ -62,15 +88,13 @@ address_create (address_t *a, const char *p)
if (!*a)
return ENOENT;
(*a)->addr = strdup (s);
(*a)->addr = strdup (save);
if (!(*a)->addr)
{
address_destroy (a);
return ENOMEM;
}
}
/* FIXME: part of the hack/fix above remove when done. */
free (s);
return status;
}
......
......@@ -23,6 +23,8 @@
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
......@@ -35,52 +37,268 @@
# define _PATH_MAILDIR "/usr/spool/mail"
#endif
int
mailbox_create_default (mailbox_t *pmbox, const char *mail)
/* Is this a security risk? */
#define USE_ENVIRON 1
static char * tilde_expansion __P ((const char *));
static char * plus_equal_expansion __P ((const char *));
static char * get_cwd __P ((void));
static char * get_full_path __P ((const char *));
static const char * get_homedir __P ((const char *));
/* Do + and = expansion to ~/Mail, if necessary. */
static char *
plus_equal_expansion (const char *file)
{
const char *user = NULL;
char *p = NULL;
if (file && (*file == '+' || *file == '='))
{
char *folder;
/* Skip '+' or '='. */
file++;
folder = tilde_expansion ("~/Mail");
if (folder)
{
p = malloc (strlen (folder) + 1 + strlen (file) + 1);
if (p)
sprintf(p, "%s/%s", folder, file);
free (folder);
}
}
if (pmbox == NULL)
return EINVAL;
if (!p)
p = strdup (file);
return p;
}
if (mail == NULL)
mail = getenv ("MAIL");
static const char *
get_homedir (const char *user)
{
const char *homedir = NULL;
struct passwd *pw = NULL;
if (user)
{
pw = getpwnam (user);
if (pw)
homedir = pw->pw_dir;
}
else
{
#ifdef USE_ENVIRON
/* NOTE: Should we honor ${HOME}? */
homedir = getenv ("HOME");
if (homedir == NULL)
{
pw = getpwuid (getuid ());
if (pw)
homedir = pw->pw_dir;
}
#else
pw = getpwuid (getuid ());
if (pw)
homedir = pw->pw_dir;
#endif
}
return homedir;
}
if (mail)
/* Do ~ , if necessary. We do not use $HOME. */
static char *
tilde_expansion (const char *file)
{
char *p = NULL;
const char *homedir = NULL;
const char delim = '/'; /* Not portable. */
if (file && *file == '~')
{
/* Skip the tilde. */
file++;
/* This means we have ~ or ~/something. */
if (*file == delim || *file == '\0')
{
/* Is it a fullpath ? */
if (mail[0] != '/')
homedir = get_homedir (NULL);
if (homedir)
{
/* Is it a URL ? */
if (strchr (mail, ':') == NULL)
p = calloc (strlen (homedir) + strlen (file) + 1, 1);
if (p)
{
/* A user name. */
user = mail;
mail = NULL;
strcpy (p, homedir);
strcat (p, file);
}
}
}
/* Means we have ~user or ~user/something. */
else
{
const char *s = file;
if (mail == NULL)
/* Move to the first delim. */
while (*s && *s != delim) s++;
/* Get the username homedir. */
{
char *name;
name = calloc (s - file + 1, 1);
if (name)
{
memcpy (name, file, s - file);
name [s - file] = '\0';
}
homedir = get_homedir (name);
free (name);
}
if (homedir)
{
p = calloc (strlen (homedir) + strlen (s) + 1, 1);
if (p)
{
strcpy (p, homedir);
strcat (p, s);
}
}
}
}
if (!p)
p = strdup (file);
return p;
}
static char *
get_cwd ()
{
char *ret;
unsigned path_max;
char buf[128];
errno = 0;
ret = getcwd (buf, sizeof (buf));
if (ret != NULL)
return strdup (buf);
if (errno != ERANGE)
return NULL;
path_max = 128;
path_max += 2; /* The getcwd docs say to do this. */
for (;;)
{
char *cwd = (char *) malloc (path_max);
errno = 0;
ret = getcwd (cwd, path_max);
if (ret != NULL)
return ret;
if (errno != ERANGE)
{
int save_errno = errno;
free (cwd);
errno = save_errno;
return NULL;
}
free (cwd);
path_max += path_max / 16;
path_max += 32;
}
/* oops? */
return NULL;
}
static char *
get_full_path (const char *file)
{
char *p = NULL;
if (!file)
p = get_cwd ();
else if (*file != '/')
{
char *cwd = get_cwd ();
if (cwd)
{
p = calloc (strlen (cwd) + 1 + strlen (file) + 1, 1);
if (p)
sprintf (p, "%s/%s", cwd, file);
free (cwd);
}
}
if (!p)
p = strdup (file);
return p;
}
/* We are trying to be smart about the location of the mail.
mailbox_create() is not doing this.
~/file --> /home/user/file
~user/file --> /home/user/file
+file --> /home/user/Mail/file
=file --> /home/user/Mail/file
*/
int
mailbox_create_default (mailbox_t *pmbox, const char *mail)
{
char *mbox = NULL;
int status;
/* Sanity. */
if (pmbox == NULL)
return EINVAL;
/* Other utilities may not understand GNU mailutils url namespace, so
use FOLDER instead, to not confuse others by using MAIL. */
if (mail == NULL)
mail = getenv ("FOLDER");
/* Fallback to wellknown environment. */
if (mail == NULL)
mail = getenv ("MAIL");
/* FIXME: This is weak, it would be better to check
for all the known schemes to detect presence of URLs. */
if (mail && *mail && strchr (mail, ':') == NULL)
{
char *mail0;
if (user == NULL)
char *mail2;
mail0 = tilde_expansion (mail);
mail2 = plus_equal_expansion (mail0);
free (mail0);
mbox = get_full_path (mail2);
free (mail2);
}
/* Search the spooldir. */
if (mbox == NULL)
{
const char *user = NULL;
#ifdef USE_ENVIRON
user = (getenv ("LOGNAME")) ? getenv ("LOGNAME") : getenv ("USER");
#endif
if (user == NULL)
{
struct passwd *pw;
pw = getpwuid (getuid ());
if (pw)
user = pw->pw_name;
else
{
mu_error ("Who am I ?\n");
return EINVAL;
}
}
mail0 = malloc (strlen (user) + strlen (_PATH_MAILDIR) + 2);
if (mail0 == NULL)
mbox = malloc (strlen (user) + strlen (_PATH_MAILDIR) + 2);
if (mbox == NULL)
return ENOMEM;
sprintf (mail0, "%s/%s", _PATH_MAILDIR, user);
status = mailbox_create (pmbox, mail0);
free (mail0);
return status;
sprintf (mbox, "%s/%s", _PATH_MAILDIR, user);
}
return mailbox_create (pmbox, mail);
status = mailbox_create (pmbox, mbox);
free (mbox);
return status;
}
......
......@@ -211,12 +211,53 @@ int parse822_is_smtp_q(char c)
/***** From RFC 822, 3.3 Lexical Tokens *****/
int parse822_skip_ws(const char** p, const char* e)
int parse822_skip_crlf(const char** p, const char* e)
{
while((*p != e) && parse822_is_lwsp_char(**p)) {
*p += 1;
const char* s = *p;
if(
(&s[1] < e) &&
s[0] == '\r' &&
s[1] == '\n'
)
{
*p += 2;
return EOK;
}
return EPARSE;
}
int parse822_skip_lwsp_char(const char** p, const char* e)
{
if(*p < e && parse822_is_lwsp_char(**p)) {
*p += 1;
return EOK;
}
return EPARSE;
}
int parse822_skip_lwsp(const char** p, const char* e)
{
/*
* linear-white-space = 1*([CRLF] LWSP-char)
*/
int space = 0;
while(*p != e) {
const char* save = *p;
if(parse822_skip_lwsp_char(p, e) == EOK) {
space = 1;
continue;
}
if(parse822_skip_crlf(p, e) == EOK) {
if(parse822_skip_lwsp_char(p, e) == EOK) {
continue;
}
*p = save;
return EPARSE;
}
break;
}
return space ? EOK : EPARSE;
}
int parse822_skip_comments(const char** p, const char* e)
......@@ -258,7 +299,7 @@ int parse822_digits(const char** p, const char* e,
int parse822_special(const char** p, const char* e, char c)
{
parse822_skip_ws(p, e); /* not comments, they start with a special... */
parse822_skip_lwsp(p, e); /* not comments, they start with a special... */
if((*p != e) && **p == c) {
*p += 1;
......@@ -694,7 +735,7 @@ int parse822_mail_box(const char** p, const char* e, address_t* a)
/* -> addr-spec */
if((rc = parse822_addr_spec(p, e, a)) == EOK) {
parse822_skip_ws(p, e);
parse822_skip_lwsp(p, e);
/* yuck. */
if((rc = parse822_comment(p, e, &(*a)->personal)) == EPARSE) {
......@@ -1087,20 +1128,18 @@ int parse822_domain_literal(const char** p, const char* e, char** domain_literal
return rc;
}
#if 0
/***** From RFC 822, 3.2 Header Field Definitions *****/
int parse822_field_name(const char** p, const char* e, char** fieldname)
{
/* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */
Ptr save = p;
const char *save = *p;
Rope fn;
char *fn = NULL;
while(*p != e) {
char c = *p;
char c = **p;
if(!parse822_is_char(c))
break;
......@@ -1112,66 +1151,67 @@ int parse822_field_name(const char** p, const char* e, char** fieldname)
if(c == ':')
break;
fn.append(c);
str_append_char(&fn, c);
*p += 1;
}
/* must be at least one char in the field name */
if(fn.empty()) {
p = save;
return 0;
if(!fn) {
*p = save;
return EPARSE;
}
parse822_skip_comments(p, e);
if(!parse822_special(p, e, ':')) {
p = save;
return 0;
*p = save;
if (fn)
free (fn);
return EPARSE;
}
fieldname = fn;
*fieldname = fn;
return 1;
return EOK;
}
int parse822_field_body(const char** p, const char* e, Rope& fieldbody)
int parse822_field_body(const char **p, const char *e, char** fieldbody)
{
/* field-body = *text [CRLF lwsp-char field-body] */
Ptr save = p;
/*const char *save = *p; */
Rope fb;
char *fb = NULL;
for(;;)
{
Ptr eol = p;
const char *eol = *p;
while(eol != e) {
char c = *eol;
/*char c = *eol; */
if(eol[0] == '\r' && (eol+1) != e && eol[1] == '\n')
break;
++eol;
}
fb.append(p, eol);
p = eol;
str_append_range(&fb, *p, eol);
*p = eol;
if(eol == e)
break; /* no more, so we're done */
assert(p[0] == '\r');
assert(p[1] == '\n');
/*assert(p[0] == '\r'); */
/*assert(p[1] == '\n'); */
p += 2;
*p += 2;
if(*p == e)
break; /* no more, so we're done */
/* check if next line is a continuation line */
if(*p != ' ' && *p != '\t')
if(**p != ' ' && **p != '\t')
break;
}
fieldbody = fb;
*fieldbody = fb;
return 1;
return EOK;
}
#endif
/***** RFC 822 Quoting Functions *****/
......