+/*************************************************
+* Check mail address for correct syntax *
+*************************************************/
+
+/*
+Check mail address for being syntactically correct.
+
+Arguments:
+ filter points to the Sieve filter including its state
+ address String containing one address
+
+Returns
+ 1 Mail address is syntactically OK
+ -1 syntax error
+*/
+
+int check_mail_address(struct Sieve *filter, const struct String *address)
+{
+int start, end, domain;
+uschar *error,*ss;
+
+if (address->length>0)
+ {
+ ss = parse_extract_address(address->character, &error, &start, &end, &domain,
+ FALSE);
+ if (ss == NULL)
+ {
+ filter->errmsg=string_sprintf("malformed address \"%s\" (%s)",
+ address->character, error);
+ return -1;
+ }
+ else
+ return 1;
+ }
+else
+ {
+ filter->errmsg=CUS "empty address";
+ return -1;
+ }
+}
+
+
+/*************************************************
+* Decode URI encoded string *
+*************************************************/
+
+/*
+Arguments:
+ str URI encoded string
+
+Returns
+ 0 Decoding successful
+ -1 Encoding error
+*/
+
+#ifdef ENOTIFY
+static int
+uri_decode(struct String *str)
+{
+uschar *s,*t,*e;
+
+if (str->length==0) return 0;
+for (s=str->character,t=s,e=s+str->length; s<e; )
+ if (*s=='%')
+ {
+ if (s+2<e && isxdigit(*(s+1)) && isxdigit(*(s+2)))
+ {
+ *t++=((isdigit(*(s+1)) ? *(s+1)-'0' : tolower(*(s+1))-'a'+10)<<4)
+ | (isdigit(*(s+2)) ? *(s+2)-'0' : tolower(*(s+2))-'a'+10);
+ s+=3;
+ }
+ else return -1;
+ }
+ else
+ *t++=*s++;
+
+*t='\0';
+str->length=t-str->character;
+return 0;
+}
+
+
+/*************************************************
+* Parse mailto URI *
+*************************************************/
+
+/*
+Parse mailto-URI.
+
+ mailtoURI = "mailto:" [ to ] [ headers ]
+ to = [ addr-spec *("%2C" addr-spec ) ]
+ headers = "?" header *( "&" header )
+ header = hname "=" hvalue
+ hname = *urlc
+ hvalue = *urlc
+
+Arguments:
+ filter points to the Sieve filter including its state
+ uri URI, excluding scheme
+ recipient
+ body
+
+Returns
+ 1 URI is syntactically OK
+ 0 Unknown URI scheme
+ -1 syntax error
+*/
+
+static int
+parse_mailto_uri(struct Sieve *filter, const uschar *uri,
+ string_item **recipient, struct String *header, struct String *subject,
+ struct String *body)
+{
+const uschar *start;
+struct String to, hname;
+struct String hvalue = {.character = NULL, .length = 0};
+string_item *new;
+
+if (Ustrncmp(uri,"mailto:",7))
+ {
+ filter->errmsg=US "Unknown URI scheme";
+ return 0;
+ }
+
+uri+=7;
+if (*uri && *uri!='?')
+ for (;;)
+ {
+ /* match to */
+ for (start=uri; *uri && *uri!='?' && (*uri!='%' || *(uri+1)!='2' || tolower(*(uri+2))!='c'); ++uri);
+ if (uri>start)
+ {
+ gstring * g = string_catn(NULL, start, uri-start);
+
+ to.character = string_from_gstring(g);
+ to.length = g->ptr;
+ if (uri_decode(&to)==-1)
+ {
+ filter->errmsg=US"Invalid URI encoding";
+ return -1;
+ }
+ new=store_get(sizeof(string_item), FALSE);
+ new->text = store_get(to.length+1, is_tainted(to.character));
+ if (to.length) memcpy(new->text, to.character, to.length);
+ new->text[to.length]='\0';
+ new->next=*recipient;
+ *recipient=new;
+ }
+ else
+ {
+ filter->errmsg=US"Missing addr-spec in URI";
+ return -1;
+ }
+ if (*uri=='%') uri+=3;
+ else break;
+ }
+if (*uri=='?')
+ {
+ ++uri;
+ for (;;)
+ {
+ /* match hname */
+ for (start=uri; *uri && (isalnum(*uri) || strchr("$-_.+!*'(),%",*uri)); ++uri);
+ if (uri>start)
+ {
+ gstring * g = string_catn(NULL, start, uri-start);
+
+ hname.character = string_from_gstring(g);
+ hname.length = g->ptr;
+ if (uri_decode(&hname)==-1)
+ {
+ filter->errmsg=US"Invalid URI encoding";
+ return -1;
+ }
+ }
+ /* match = */
+ if (*uri=='=')
+ ++uri;
+ else
+ {
+ filter->errmsg=US"Missing equal after hname";
+ return -1;
+ }
+ /* match hvalue */
+ for (start=uri; *uri && (isalnum(*uri) || strchr("$-_.+!*'(),%",*uri)); ++uri);
+ if (uri>start)
+ {
+ gstring * g = string_catn(NULL, start, uri-start);
+
+ hname.character = string_from_gstring(g);
+ hname.length = g->ptr;
+ if (uri_decode(&hvalue)==-1)
+ {
+ filter->errmsg=US"Invalid URI encoding";
+ return -1;
+ }
+ }
+ if (hname.length==2 && strcmpic(hname.character, US"to")==0)
+ {
+ new=store_get(sizeof(string_item), FALSE);
+ new->text = store_get(hvalue.length+1, is_tainted(hvalue.character));
+ if (hvalue.length) memcpy(new->text, hvalue.character, hvalue.length);
+ new->text[hvalue.length]='\0';
+ new->next=*recipient;
+ *recipient=new;
+ }
+ else if (hname.length==4 && strcmpic(hname.character, US"body")==0)
+ *body=hvalue;
+ else if (hname.length==7 && strcmpic(hname.character, US"subject")==0)
+ *subject=hvalue;
+ else
+ {
+ static struct String ignore[]=
+ {
+ {US"date",4},
+ {US"from",4},
+ {US"message-id",10},
+ {US"received",8},
+ {US"auto-submitted",14}
+ };
+ static struct String *end=ignore+sizeof(ignore)/sizeof(ignore[0]);
+ struct String *i;
+
+ for (i=ignore; i<end && !eq_asciicase(&hname,i,0); ++i);
+ if (i==end)
+ {
+ gstring * g;
+
+ if (header->length==-1) header->length = 0;
+
+ g = string_catn(NULL, header->character, header->length);
+ g = string_catn(g, hname.character, hname.length);
+ g = string_catn(g, CUS ": ", 2);
+ g = string_catn(g, hvalue.character, hvalue.length);
+ g = string_catn(g, CUS "\n", 1);
+
+ header->character = string_from_gstring(g);
+ header->length = g->ptr;
+ }
+ }
+ if (*uri=='&') ++uri;
+ else break;
+ }
+ }
+if (*uri)
+ {
+ filter->errmsg=US"Syntactically invalid URI";
+ return -1;
+ }
+return 1;
+}
+#endif
+
+