static char rcsid[] = "@(#)$Id: mailto.c,v 1.6 2006/06/25 10:41:05 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.6 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* or Kari Hurtta <elm@elmme-mailer.org>
*****************************************************************************/
#include "def_url.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"url");
static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
char *str;
{
return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static CONST unsigned char *cs2us P_((const char *str));
static CONST unsigned char *cs2us(str)
CONST char *str;
{
return (CONST unsigned char *)str;
}
#define URL_mailto_magic 0xEC06
struct url_mailto {
unsigned short magic; /* URL_mailto_magic */
struct url_element * addr;
struct url_header {
header_ptr header_name;
struct url_element * header_body;
} * hdrs;
int hdrs_count;
struct url_element * body;
};
#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif
S_(uh_init_url uh_init_mailto)
static void uh_init_mailto P_((struct url *url));
static void uh_init_mailto(url)
struct url *url;
{
url->u.mailto = safe_malloc (sizeof (* url->u.mailto));
/* bzero is defined hdrs/defs.h */
bzero((void *)url->u.mailto,sizeof (* url->u.mailto));
url->u.mailto->magic = URL_mailto_magic;
url->u.mailto->addr = NULL;
url->u.mailto->hdrs = NULL;
url->u.mailto->hdrs_count = 0;
url->u.mailto->body = NULL;
}
S_(uh_free_url uh_free_mailto)
static void uh_free_mailto P_((struct url *url));
static void uh_free_mailto(url)
struct url *url;
{
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_free_mailto",
"bad magic number",0);
if (url->u.mailto->addr)
free_url_element(& (url->u.mailto->addr));
if (url->u.mailto->hdrs) {
int i;
for (i = 0; i < url->u.mailto->hdrs_count; i++) {
if (url->u.mailto->hdrs[i].header_body)
free_url_element(& (url->u.mailto->hdrs[i].header_body));
url->u.mailto->hdrs[i].header_name = NULL;
}
free(url->u.mailto->hdrs);
url->u.mailto->hdrs = NULL;
}
url->u.mailto->hdrs_count = 0;
if (url->u.mailto->body)
free_url_element(& (url->u.mailto->body));
url->u.mailto->magic = 0; /* Invalidate */
free(url->u.mailto);
url->u.mailto = NULL;
}
/* RFC 2368:
Following the syntax conventions of RFC 1738 [RFC1738], a "mailto"
URL has the form:
mailtoURL = "mailto:" [ to ] [ headers ]
to = #mailbox
headers = "?" header *( "&" header )
header = hname "=" hvalue
hname = *urlc
hvalue = *urlc
"#mailbox" is as specified in RFC 822 [RFC822]. This means that it
consists of zero or more comma-separated mail addresses, possibly
including "phrase" and "comment" components. Note that all URL
reserved characters in "to" must be encoded: in particular,
parentheses, commas, and the percent sign ("%"), which commonly occur
in the "mailbox" syntax.
"hname" and "hvalue" are encodings of an RFC 822 header name and
value, respectively. As with "to", all URL reserved characters must
be encoded.
The special hname "body" indicates that the associated hvalue is the
body of the message. The "body" hname should contain the content for
the first text/plain body part of the message. The mailto URL is
primarily intended for generation of short text messages that are
actually the content of automatic processing (such as "subscribe"
messages for mailing lists), not general MIME bodies.
Within mailto URLs, the characters "?", "=", "&" are reserved.
*/
S_(uh_parse_url_not_path uh_parse_mailto_not_path)
static int uh_parse_mailto_not_path P_((struct url *url,
struct string *scheme_pesifix,
struct header_errors **header_error));
static int uh_parse_mailto_not_path(url,scheme_pesifix,header_error)
struct url *url;
struct string *scheme_pesifix;
struct header_errors **header_error;
{
CONST struct string * X = NULL;
int len,x;
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_parse_mailto_not_path",
"bad magic number",0);
url->u.mailto->addr = element_from_raw(scheme_pesifix);
X = parsed_from_element(url->u.mailto->addr,header_error);
if (!X) {
DPRINT(Debug,10,(&Debug,
"uh_parse_mailto_not_path: parsed_from_element failed\n"));
return 0;
}
len = string_len(X);
for (x = 0; x < len; x++) {
uint16 ch = give_unicode_from_string(X,x);
if (0x0040 /* @ */ == ch)
goto found;
}
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToAt,
"At (@) character required on URL mailto address: %S"),
X);
DPRINT(Debug,10,(&Debug,
"uh_parse_mailto_not_path: No @ -character\n"));
return 0;
found:
return 1;
}
S_(uh_dup_url_not_path uh_dup_mailto_not_path)
static int uh_dup_mailto_not_path P_((struct url *url,
struct url *source));
static int uh_dup_mailto_not_path(url,source)
struct url *url;
struct url *source;
{
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_dup_mailto_not_path",
"bad magic number (url)",0);
if (URL_mailto_magic != source->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_dup_mailto_not_path",
"bad magic number (source)",0);
if (source->u.mailto->addr)
url->u.mailto->addr = dup_url_element(url->u.mailto->addr);
return 0;
}
S_(uh_parse_url_params uh_parse_mailto_params)
static int uh_parse_mailto_params P_((struct url *url,
struct string *scheme_pesifix,
struct header_errors **header_error));
static int uh_parse_mailto_params(url,scheme_pesifix,header_error)
struct url *url;
struct string *scheme_pesifix;
struct header_errors **header_error;
{
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_parse_mailto_params",
"bad magic number",0);
/* No params? */
return 0;
}
S_(uh_dup_url_params uh_dup_mailto_params)
static int uh_dup_mailto_params P_((struct url *url,
struct url *source));
static int uh_dup_mailto_params(url,source)
struct url *url;
struct url *source;
{
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_dup_mailto_params",
"bad magic number (url)",0);
if (URL_mailto_magic != source->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_dup_mailto_params",
"bad magic number (source)",0);
/* No params? */
return 0;
}
S_(uh_parse_url_query uh_parse_mailto_query)
static int uh_parse_mailto_query P_((struct url *url,
struct string *scheme_pesifix,
struct header_errors **header_error));
static int uh_parse_mailto_query(url,scheme_pesifix,header_error)
struct url *url;
struct string *scheme_pesifix;
struct header_errors **header_error;
{
int len = string_len(scheme_pesifix);
int X = 0;
char * buffer;
int ret = 0;
int count = 1;
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_parse_mailto_query",
"bad magic number",0);
if (len < 1)
return 1; /* Silently accept */
for (X = 0; X < len; X++) {
uint16 ch = give_unicode_from_string(scheme_pesifix,X);
if (0x0026 /* & */ == ch)
count++;
}
DPRINT(Debug,9,(&Debug,
"uh_parse_mailto_query: %d headers\n",count));
url->u.mailto->hdrs = safe_malloc(count * sizeof (url->u.mailto->hdrs[0]));
/* bzero is defined hdrs/defs.h */
bzero((void *) url->u.mailto->hdrs,
count * sizeof (url->u.mailto->hdrs[0]));
/* This code assumes that code charset is ASCII */
buffer = malloc(len);
X = 0;
while (X < len) {
uint16 ch = 0;
int startpos = X;
struct string * raw_header_name = NULL;
struct string * raw_header_value = NULL;
struct string * decoded_header_name = NULL;
int L;
int have_failed = 0;
int Y,L1;
/* Scan for name */
/* check for header name */
for (; X < len; X++) {
ch = give_unicode_from_string(scheme_pesifix,X);
if (0x003A /* : */ == ch ||
0x0026 /* & */ == ch ||
0x0080 <= ch) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Failed to parse mailto headers: %S",
scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToHeaders,
"Failed to parse mailto headers: %S"),
scheme_pesifix);
goto fail_headers;
}
if (0x003D /* = */ == ch)
break;
}
if (0x003D /* = */ != ch) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Failed to parse mailto headers: %S",
scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToHeaders,
"Failed to parse mailto headers: %S"),
scheme_pesifix);
goto fail_headers;
}
L = X - startpos;
DPRINT(Debug,9,(&Debug,
"uh_parse_mailto_query: %d - %d (len=%d) header name found\n",
X,startpos,L));
raw_header_name = clip_from_string(scheme_pesifix,&startpos,L);
if (startpos != X)
panic("URL PANIC",__FILE__,__LINE__,"uh_parse_mailto_query",
"Clipping Error (header name -part)",0);
DPRINT(Debug,11,(&Debug,
"uh_parse_mailto_query: raw header name=%S\n",raw_header_name));
startpos = ++X;
ch = 0;
/* check for header value */
for (; X < len; X++) {
ch = give_unicode_from_string(scheme_pesifix,X);
if (0x0026 /* & */ == ch ||
0x003D /* = */ == ch)
break;
}
if (X < len &&
0x0026 /* & */ != ch) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Failed to parse mailto headers: %S",
scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToHeaders,
"Failed to parse mailto headers: %S"),
scheme_pesifix);
goto fail_headers;
}
L = X - startpos;
DPRINT(Debug,9,(&Debug,
"uh_parse_mailto_query: %d - %d (len=%d) header value found\n",
X,startpos,L));
raw_header_value = clip_from_string(scheme_pesifix,&startpos,L);
if (startpos != X)
panic("URL PANIC",__FILE__,__LINE__,"uh_parse_mailto_query",
"Clipping Error (header value -part)",0);
DPRINT(Debug,11,(&Debug,
"uh_parse_mailto_query: raw header value=%S\n",raw_header_value));
decoded_header_name = raw_to_parsed(raw_header_name,header_error);
if (!decoded_header_name) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Failed to parse mailto headers: %S",
scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToHeaders,
"Failed to parse mailto headers: %S"),
scheme_pesifix);
goto fail_headers;
}
L1 = string_len(decoded_header_name);
if (!L1) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Failed to parse mailto headers: %S",
scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToHeaders,
"Failed to parse mailto headers: %S"),
scheme_pesifix);
goto fail_headers;
}
for (Y = 0; Y < L1; Y++) {
uint16 ch1 = give_unicode_from_string(decoded_header_name,Y);
if (0x0061 /* a */ <= ch1 && ch1 <= 0x007A /* z */ ||
0x0030 /* 0 */ <= ch1 && ch1 <= 0x0039 /* 9 */ ||
0x002B /* + */ == ch1 ||
0x002E /* . */ == ch1 ||
0x002D /* - */ == ch1 ||
0x0041 /* A */ <= ch1 && ch1 <= 0x005A /* Z */)
buffer[Y] = ch1;
else {
DPRINT(Debug,9,(&Debug,
"uh_parse_mailto_query: [%d] ch=%04x not valid for header = decoded =%S\n",
Y,ch1,decoded_header_name));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToHeaders,
"Failed to parse mailto headers: %S"),
scheme_pesifix);
goto fail_headers;
}
}
buffer[Y] = '\0';
if (0 == istrcmp(buffer,"body")) {
if (url->u.mailto->body) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Duplicate mail body on mailto ignored: %S",
scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToDuplicateBody,
"Duplicate mail body on mailto ignored: %S"),
scheme_pesifix);
} else
url->u.mailto->body = element_from_raw(raw_header_value);
} else {
header_ptr hdr = find_header(buffer,0);
if (! hdr ||
0 == strincmp(buffer,"Resent-",7) ||
0 == istrcmp(buffer,"Return-path") ||
0 == istrcmp(buffer,"Reply-To") ||
0 == istrcmp(buffer,"From") ||
0 == istrcmp(buffer,"Sender") ||
! is_mailing_header(hdr)) {
DPRINT(Debug,2,(&Debug,
"uh_parse_mailto_query: Header %s on mailto ignored: %S",
buffer,scheme_pesifix));
process_header_error(header_error,
CATGETS(elm_msg_cat, MeSet,
MeURLMailToIgnoredHeader,
"Header %s on mailto ignored: %S"),
buffer,scheme_pesifix);
} else {
if (url->u.mailto->hdrs_count >= count)
panic("URL PANIC",__FILE__,__LINE__,"uh_parse_mailto_query",
"header index overflow",0);
url->u.mailto->hdrs[url->u.mailto->hdrs_count].header_name = hdr;
url->u.mailto->hdrs[url->u.mailto->hdrs_count].header_body =
element_from_raw(raw_header_value);
url->u.mailto->hdrs_count++;
}
}
if (0) {
fail_headers:
have_failed = 1;
}
if (decoded_header_name)
free_string(& decoded_header_name);
if (raw_header_name)
free_string(& raw_header_name);
if (raw_header_value)
free_string(& raw_header_value);
if (have_failed)
goto fail;
/* Skip & */
X++;
}
ret = 1;
DPRINT(Debug,9,(&Debug,
"uh_parse_mailto_query: %d headers parsed\n",
url->u.mailto->hdrs_count));
fail:
free(buffer);
return ret;
}
S_(uh_dup_url_query uh_dup_mailto_query)
static int uh_dup_mailto_query P_((struct url *url,
struct url *source));
static int uh_dup_mailto_query(url,source)
struct url *url;
struct url *source;
{
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_dup_mailto_query",
"bad magic number (url)",0);
if (URL_mailto_magic != source->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_dup_mailto_query",
"bad magic number (source)",0);
if (source->u.mailto->hdrs &&
source->u.mailto->hdrs_count > 0) {
int i;
url->u.mailto->hdrs = safe_malloc( source->u.mailto->hdrs_count *
sizeof (url->u.mailto->hdrs[0]));
for (i = 0; i < source->u.mailto->hdrs_count; i++) {
if (source->u.mailto->hdrs[i].header_body)
url->u.mailto->hdrs[i].header_body =
dup_url_element(source->u.mailto->hdrs[i].header_body);
else
source->u.mailto->hdrs[i].header_body = NULL;
url->u.mailto->hdrs[i].header_name =
source->u.mailto->hdrs[i].header_name;
}
url->u.mailto->hdrs_count = i;
}
if (source->u.mailto->body)
url->u.mailto->body = dup_url_element(source->u.mailto->body);
return 1;
}
S_(uh_set_mailing_headers_from_url uh_set_mailing_headers_from_mailto)
static int uh_set_mailing_headers_from_mailto P_((struct mailing_headers *hdrs,
const struct url *url,
struct mailer_info
*mailer_info));
static int uh_set_mailing_headers_from_mailto(hdrs,url,mailer_info)
struct mailing_headers *hdrs;
CONST struct url *url;
struct mailer_info *mailer_info;
{
CONST struct string * X = NULL;
int i;
int ok;
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,
"uh_set_mailing_headers_from_mailto",
"bad magic number (url)",0);
if (! url->u.mailto->addr) {
DPRINT(Debug,7,(&Debug,
" uh_set_mailing_headers_from_mailto: No address\n"));
return 0;
}
X = parsed_from_element(url->u.mailto->addr,NULL);
if (!X) {
DPRINT(Debug,7,(&Debug,
" uh_set_mailing_headers_from_mailto: parsed_from_element failed\n"));
return 0;
}
/* FIXME -- this also split addresses on spaces */
update_expanded_from_edit_buffer(& (hdrs->to),X,mailer_info,
NULL /* Do not expand aliases */);
ok = 1;
for (i = 0; i < url->u.mailto->hdrs_count; i++) {
CONST struct string * decoded = NULL;
unsigned char * stream = NULL;
if (! url->u.mailto->hdrs[i].header_body) {
ok = 0;
continue;
}
decoded = parsed_from_element(url->u.mailto->hdrs[i].header_body,
NULL);
if (! decoded) {
ok = 0;
continue;
}
stream = stream_from_string(decoded,0,NULL);
if (! add_to_mailing_header(hdrs,
url->u.mailto->hdrs[i].header_name,
us2s(stream),
1,
decoded->string_type,
0)) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeFailedAddMailHeader,
"Failed to add mail header: %s: %S"),
give_header_name(url->u.mailto->hdrs[i].header_name),
decoded);
ok = 0;
}
free(stream);
}
return ok;
}
S_(uh_get_body_string_from_url uh_get_body_string_from_mailto)
static CONST struct string * uh_get_body_string_from_mailto P_((const struct
url *url,
int *errors));
static CONST struct string * uh_get_body_string_from_mailto(url,errors)
CONST struct url *url;
int *errors;
{
CONST struct string * ret;
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,
"uh_get_body_string_from_mailto",
"bad magic number (url)",0);
if (! url->u.mailto->body)
return NULL;
ret = parsed_from_element(url->u.mailto->body,NULL);
if (!ret)
*errors = 1;
return ret;
}
S_(uh_not_path_to_raw_url uh_not_path_to_raw_mailto)
static struct string * uh_not_path_to_raw_mailto P_((const struct url *url));
static struct string * uh_not_path_to_raw_mailto(url)
CONST struct url *url;
{
CONST struct string *S;
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_not_path_to_raw_mailto",
"bad magic number",0);
if (! url->u.mailto->addr)
return NULL;
S = raw_from_element(url->u.mailto->addr);
if (!S) {
DPRINT(Debug,12,(&Debug,
"uh_not_path_to_raw_mailto: Failed to get addr\n"));
return NULL;
}
return dup_string(S);
}
S_(uh_params_to_raw_url uh_params_to_raw_mailto)
static int uh_params_to_raw_mailto P_((const struct url *url,
struct string **result));
static int uh_params_to_raw_mailto(url,result)
CONST struct url *url;
struct string **result;
{
*result = NULL;
return 0;
}
S_(uh_query_to_raw_url uh_query_to_raw_mailto)
static int uh_query_to_raw_mailto P_((const struct url *url,
struct string **result));
static int uh_query_to_raw_mailto(url,result)
CONST struct url *url;
struct string **result;
{
int i;
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
if (URL_mailto_magic != url->u.mailto->magic)
panic("URL PANIC",__FILE__,__LINE__,"uh_query_to_raw_mailto",
"bad magic number",0);
if (!ascii_ptr)
panic("CHARSET PANIC",__FILE__,__LINE__,"uh_query_to_raw_mailto",
"US-ASCII not found",0);
*result = NULL;
if (url->u.mailto->body) {
CONST struct string * S = raw_from_element(url->u.mailto->body);
if (!S) {
DPRINT(Debug,12,(&Debug,
"uh_query_to_raw_mailto: Failed to get body\n"));
goto failure;
}
*result = new_string(ascii_ptr);
add_ascii_to_string(*result,s2us("body="));
append_string(result,S);
}
for (i = 0; i < url->u.mailto->hdrs_count; i++) {
CONST struct string * S = raw_from_element(url->u.mailto->hdrs[i].
header_body);
if (!S) {
DPRINT(Debug,12,(&Debug,
"uh_query_to_raw_mailto: Failed to get header\n"));
goto failure;
}
if (*result)
add_ascii_to_string(*result,s2us("&"));
else
*result = new_string(ascii_ptr);
add_ascii_to_string(*result,
cs2us(give_header_name(url->u.mailto->hdrs[i].
header_name)));
add_ascii_to_string(*result,s2us("="));
append_string(result,S);
}
return 1;
failure:
if (*result)
free_string(result);
return 0;
}
S_(uh_get_folder_from_url uh_get_folder_from_mailto)
static struct folder_info * uh_get_folder_from_mailto P_((const struct url *url,
verify_remote_url_f * verify_remote));
static struct folder_info * uh_get_folder_from_mailto(url,verify_remote)
const struct url *url;
verify_remote_url_f * verify_remote;
{
return NULL;
}
struct url_handler URL_mailto_handler = {
URL_handler_magic,
URLFLAG_query,
url_mailing,
uh_init_mailto,
uh_free_mailto,
uh_parse_mailto_not_path,
uh_dup_mailto_not_path,
uh_parse_mailto_params,
uh_dup_mailto_params,
uh_parse_mailto_query,
uh_dup_mailto_query,
uh_set_mailing_headers_from_mailto,
uh_get_body_string_from_mailto,
uh_not_path_to_raw_mailto,
uh_params_to_raw_mailto,
uh_query_to_raw_mailto,
uh_get_folder_from_mailto,
get_url_type_default
};
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1