+/*************************************************
+* Decode URI encoded string *
+*************************************************/
+
+/*
+Arguments:
+ str URI encoded string
+
+Returns
+ 0 Decoding successful
+ -1 Encoding error
+*/
+
+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
+
+Returns
+ 1 URI is syntactically OK
+ -1 syntax error
+*/
+
+int parse_mailto_uri(struct Sieve *filter, const uschar *uri, string_item **recipient, struct String *body)
+{
+const uschar *start;
+struct String to,hname,hvalue;
+int capacity;
+string_item *new;
+
+if (*uri && *uri!='?')
+ for (;;)
+ {
+ /* match to */
+ for (start=uri; *uri && *uri!='?' && (*uri!='%' || *(uri+1)!='2' || tolower(*(uri+2))!='c'); ++uri);
+ if (uri>start)
+ {
+ capacity=0;
+ to.character=(uschar*)0;
+ to.length=0;
+ to.character=string_cat(to.character,&capacity,&to.length,start,uri-start);
+ to.character[to.length]='\0';
+ if (uri_decode(&to)==-1)
+ {
+ filter->errmsg=US"Invalid URI encoding";
+ return -1;
+ }
+ new=store_get(sizeof(string_item));
+ new->text=store_get(to.length+1);
+ 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)
+ {
+ capacity=0;
+ hname.character=(uschar*)0;
+ hname.length=0;
+ hname.character=string_cat(hname.character,&capacity,&hname.length,start,uri-start);
+ hname.character[hname.length]='\0';
+ 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)
+ {
+ capacity=0;
+ hvalue.character=(uschar*)0;
+ hvalue.length=0;
+ hvalue.character=string_cat(hvalue.character,&capacity,&hvalue.length,start,uri-start);
+ hvalue.character[hvalue.length]='\0';
+ if (uri_decode(&hvalue)==-1)
+ {
+ filter->errmsg=US"Invalid URI encoding";
+ return -1;
+ }
+ }
+ if (hname.length==2 && strcmp(hname.character,"to")==0)
+ {
+ new=store_get(sizeof(string_item));
+ new->text=store_get(hvalue.length+1);
+ 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 && strcmp(hname.character,"body")==0)
+ *body=hvalue;
+ if (*uri=='&') ++uri;
+ else break;
+ }
+ }
+if (*uri)
+ {
+ filter->errmsg=US"Syntactically invalid URI";
+ return -1;
+ }
+return 1;
+}
+