+void
+build_attribute_subpkt(PKT_user_id *uid,byte type,
+ const void *buf,u32 buflen,
+ const void *header,u32 headerlen)
+{
+ byte *attrib;
+ int idx;
+
+ if(1+headerlen+buflen>8383)
+ idx=5;
+ else if(1+headerlen+buflen>191)
+ idx=2;
+ else
+ idx=1;
+
+ /* realloc uid->attrib_data to the right size */
+
+ uid->attrib_data=xrealloc(uid->attrib_data,
+ uid->attrib_len+idx+1+headerlen+buflen);
+
+ attrib=&uid->attrib_data[uid->attrib_len];
+
+ if(idx==5)
+ {
+ attrib[0]=255;
+ attrib[1]=(1+headerlen+buflen) >> 24;
+ attrib[2]=(1+headerlen+buflen) >> 16;
+ attrib[3]=(1+headerlen+buflen) >> 8;
+ attrib[4]=1+headerlen+buflen;
+ }
+ else if(idx==2)
+ {
+ attrib[0]=(1+headerlen+buflen-192) / 256 + 192;
+ attrib[1]=(1+headerlen+buflen-192) % 256;
+ }
+ else
+ attrib[0]=1+headerlen+buflen; /* Good luck finding a JPEG this small! */
+
+ attrib[idx++]=type;
+
+ /* Tack on our data at the end */
+
+ if(headerlen>0)
+ memcpy(&attrib[idx],header,headerlen);
+ memcpy(&attrib[idx+headerlen],buf,buflen);
+ uid->attrib_len+=idx+headerlen+buflen;
+}
+
+/* Returns a human-readable string corresponding to the notation.
+ This ignores notation->value. The caller must free the result. */
+static char *
+notation_value_to_human_readable_string (struct notation *notation)
+{
+ if(notation->bdat)
+ /* Binary data. */
+ {
+ size_t len = notation->blen;
+ int i;
+ char preview[20];
+
+ for (i = 0; i < len && i < sizeof (preview) - 1; i ++)
+ if (isprint (notation->bdat[i]))
+ preview[i] = notation->bdat[i];
+ else
+ preview[i] = '?';
+ preview[i] = 0;
+
+ return xasprintf (_("[ not human readable (%zu bytes: %s%s) ]"),
+ len, preview, i < len ? "..." : "");
+ }
+ else
+ /* The value is human-readable. */
+ return xstrdup (notation->value);
+}
+
+/* Turn the notation described by the string STRING into a notation.
+
+ STRING has the form:
+
+ - -name - Delete the notation.
+ - name@domain.name=value - Normal notation
+ - !name@domain.name=value - Notation with critical bit set.
+
+ The caller must free the result using free_notation(). */
+struct notation *
+string_to_notation(const char *string,int is_utf8)
+{
+ const char *s;
+ int saw_at=0;
+ struct notation *notation;
+
+ notation=xmalloc_clear(sizeof(*notation));
+
+ if(*string=='-')
+ {
+ notation->flags.ignore=1;
+ string++;
+ }
+
+ if(*string=='!')
+ {
+ notation->flags.critical=1;
+ string++;
+ }
+
+ /* If and when the IETF assigns some official name tags, we'll have
+ to add them here. */
+
+ for( s=string ; *s != '='; s++ )
+ {
+ if( *s=='@')
+ saw_at++;
+
+ /* -notationname is legal without an = sign */
+ if(!*s && notation->flags.ignore)
+ break;
+
+ if( !*s || !isascii (*s) || (!isgraph(*s) && !isspace(*s)) )
+ {
+ log_error(_("a notation name must have only printable characters"
+ " or spaces, and end with an '='\n") );
+ goto fail;
+ }
+ }
+
+ notation->name=xmalloc((s-string)+1);
+ strncpy(notation->name,string,s-string);
+ notation->name[s-string]='\0';
+
+ if(!saw_at && !opt.expert)
+ {
+ log_error(_("a user notation name must contain the '@' character\n"));
+ goto fail;
+ }
+
+ if (saw_at > 1)
+ {
+ log_error(_("a notation name must not contain more than"
+ " one '@' character\n"));
+ goto fail;
+ }
+
+ if(*s)
+ {
+ const char *i=s+1;
+ int highbit=0;
+
+ /* we only support printable text - therefore we enforce the use
+ of only printable characters (an empty value is valid) */
+ for(s++; *s ; s++ )
+ {
+ if ( !isascii (*s) )
+ highbit=1;
+ else if (iscntrl(*s))
+ {
+ log_error(_("a notation value must not use any"
+ " control characters\n"));
+ goto fail;
+ }
+ }
+
+ if(!highbit || is_utf8)
+ notation->value=xstrdup(i);
+ else
+ notation->value=native_to_utf8(i);
+ }
+
+ return notation;
+
+ fail:
+ free_notation(notation);
+ return NULL;
+}
+
+/* Like string_to_notation, but store opaque data rather than human
+ readable data. */
+struct notation *
+blob_to_notation(const char *name, const char *data, size_t len)
+{
+ const char *s;
+ int saw_at=0;
+ struct notation *notation;
+
+ notation=xmalloc_clear(sizeof(*notation));
+
+ if(*name=='-')
+ {
+ notation->flags.ignore=1;
+ name++;
+ }
+
+ if(*name=='!')
+ {
+ notation->flags.critical=1;
+ name++;
+ }
+
+ /* If and when the IETF assigns some official name tags, we'll have
+ to add them here. */
+
+ for( s=name ; *s; s++ )
+ {
+ if( *s=='@')
+ saw_at++;
+
+ /* -notationname is legal without an = sign */
+ if(!*s && notation->flags.ignore)
+ break;
+
+ if (*s == '=')
+ {
+ log_error(_("a notation name may not contain an '=' character\n"));
+ goto fail;
+ }
+
+ if (!isascii (*s) || (!isgraph(*s) && !isspace(*s)))
+ {
+ log_error(_("a notation name must have only printable characters"
+ " or spaces\n") );
+ goto fail;
+ }
+ }
+
+ notation->name=xstrdup (name);
+
+ if(!saw_at && !opt.expert)
+ {
+ log_error(_("a user notation name must contain the '@' character\n"));
+ goto fail;
+ }
+
+ if (saw_at > 1)
+ {
+ log_error(_("a notation name must not contain more than"
+ " one '@' character\n"));
+ goto fail;
+ }
+
+ notation->bdat = xmalloc (len);
+ memcpy (notation->bdat, data, len);
+ notation->blen = len;
+
+ notation->value = notation_value_to_human_readable_string (notation);