Beispiel #1
0
static void
append_folded_name (GString *string, size_t *linelen, const char *name)
{
	const char *word, *lwsp;
	size_t len;
	
	word = name;
	
	while (*word) {
		lwsp = word;
		
		if (*word == '"') {
			/* quoted string, don't break these up */
			lwsp++;
			
			while (*lwsp && *lwsp != '"') {
				if (*lwsp == '\\')
					lwsp++;
				
				if (*lwsp)
					lwsp++;
			}
			
			if (*lwsp == '"')
				lwsp++;
		} else {
			/* normal word */
			while (*lwsp && !is_lwsp (*lwsp))
				lwsp++;
		}
		
		len = lwsp - word;
		if (*linelen > 1 && (*linelen + len) > GMIME_FOLD_LEN) {
			linewrap (string);
			*linelen = 1;
		}
		
		g_string_append_len (string, word, len);
		*linelen += len;
		
		word = lwsp;
		while (*word && is_lwsp (*word))
			word++;
		
		if (*word && is_lwsp (*lwsp)) {
			g_string_append_c (string, ' ');
			(*linelen)++;
		}
	}
}
Beispiel #2
0
static void
skip_lwsp (const char **in)
{
	register const char *inptr = *in;
	
	while (*inptr && is_lwsp (*inptr))
		inptr++;
	
	*in = inptr;
}
Beispiel #3
0
/**
 * g_mime_strdup_trim:
 * @str: The string to duplicate and trim
 *
 * Duplicates the given input string while also trimming leading and
 * trailing whitespace.
 *
 * Returns a duplicate string, minus any leading and trailing
 * whitespace that the original string may have contained.
 **/
char *
g_mime_strdup_trim (const char *str)
{
	register const char *inptr = str;
	register const char *end;
	const char *start;
	
	while (is_lwsp (*inptr))
		inptr++;
	
	start = inptr;
	end = inptr;
	
	while (*inptr) {
		if (!is_lwsp (*inptr++))
			end = inptr;
	}
	
	return g_strndup (start, (size_t) (end - start));
}
Beispiel #4
0
static void
copy_atom (const char *src, char *dest, size_t n)
{
	register const char *inptr = src;
	register char *outptr = dest;
	char *outend = dest + n;
	
	while (is_lwsp (*inptr))
		inptr++;
	
	while (is_atom (*inptr) && outptr < outend)
		*outptr++ = *inptr++;
	
	*outptr = '\0';
}
Beispiel #5
0
static InternetAddress *
decode_address (const char **in)
{
	const char *inptr, *start, *word, *comment = NULL;
	InternetAddress *addr = NULL;
	gboolean has_lwsp = FALSE;
	gboolean is_word;
	GString *name;
	
	decode_lwsp (in);
	start = inptr = *in;
	
	name = g_string_new ("");
	
	/* Both groups and mailboxes can begin with a phrase (denoting
	 * the display name for the address). Collect all of the
	 * tokens that make up this name phrase.
	 */
	while (*inptr) {
		if ((word = decode_word (&inptr))) {
			g_string_append_len (name, word, (size_t) (inptr - word));
			
		check_lwsp:
			word = inptr;
			skip_lwsp (&inptr);
			
			/* is the next token a word token? */
			is_word = *inptr == '"' || is_atom (*inptr);
			
			if (inptr > word && is_word) {
				g_string_append_c (name, ' ');
				has_lwsp = TRUE;
			}
			
			if (is_word)
				continue;
		}
		
		/* specials    =  "(" / ")" / "<" / ">" / "@"  ; Must be in quoted-
		 *             /  "," / ";" / ":" / "\" / <">  ;  string, to use
		 *             /  "." / "[" / "]"              ;  within a word.
		 */
		if (*inptr == ':') {
			/* rfc2822 group */
			inptr++;
			addr = decode_group (&inptr);
			decode_lwsp (&inptr);
			if (*inptr != ';')
				w(g_warning ("Invalid group spec, missing closing ';': %.*s",
					     inptr - start, start));
			else
				inptr++;
			break;
		} else if (*inptr == '<') {
			/* rfc2822 angle-addr */
			inptr++;
			
			/* check for obsolete routing... */
			if (*inptr != '@' || decode_route (&inptr)) {
				/* rfc2822 addr-spec */
				addr = decode_addrspec (&inptr);
			}
			
			decode_lwsp (&inptr);
			if (*inptr != '>') {
				w(g_warning ("Invalid rfc2822 angle-addr, missing closing '>': %.*s",
					     inptr - start, start));
				
				while (*inptr && *inptr != '>' && *inptr != ',')
					inptr++;
				
				if (*inptr == '>')
					inptr++;
			} else {
				inptr++;
			}
			
			/* if comment is non-NULL, we can check for a comment containing a name */
			comment = inptr;
			break;
		} else if (*inptr == '(') {
			/* beginning of a comment, use decode_lwsp() to skip past it */
			decode_lwsp (&inptr);
		} else if (*inptr && strchr ("@,;", *inptr)) {
			if (name->len == 0) {
				if (*inptr == '@') {
					GString *domain;
					
					w(g_warning ("Unexpected address: %s: skipping.", start));
					
					/* skip over @domain? */
					inptr++;
					domain = g_string_new ("");
					decode_domain (&inptr, domain);
					g_string_free (domain, TRUE);
				} else {
					/* empty address */
				}
				break;
			} else if (has_lwsp) {
				/* assume this is just an unquoted special that we should
				   treat as part of the name */
				w(g_warning ("Unquoted '%c' in address name: %s: ignoring.", *inptr, start));
				g_string_append_c (name, *inptr);
				inptr++;
				
				goto check_lwsp;
			}
			
		addrspec:
			/* what we thought was a name was actually an addrspec? */
			g_string_truncate (name, 0);
			inptr = start;
			
			addr = decode_addrspec (&inptr);
			
			/* if comment is non-NULL, we can check for a comment containing a name */
			comment = inptr;
			break;
		} else if (*inptr == '.') {
			/* This would normally signify that we are
			 * decoding the local-part of an addr-spec,
			 * but sadly, it is common for broken mailers
			 * to forget to quote/encode .'s in the name
			 * phrase. */
			g_string_append_c (name, *inptr);
			inptr++;
			
			goto check_lwsp;
		} else if (*inptr) {
			/* Technically, these are all invalid tokens
			 * but in the interest of being liberal in
			 * what we accept, we'll ignore them. */
			w(g_warning ("Unexpected char '%c' in address: %s: ignoring.", *inptr, start));
			g_string_append_c (name, *inptr);
			inptr++;
			
			goto check_lwsp;
		} else {
			goto addrspec;
		}
	}
	
	/* Note: will also skip over any comments */
	decode_lwsp (&inptr);
	
	if (name->len == 0 && comment && inptr > comment) {
		/* missing a name, look for a trailing comment */
		if ((comment = memchr (comment, '(', inptr - comment))) {
			const char *cend;
			
			/* find the end of the comment */
			cend = inptr - 1;
			while (cend > comment && is_lwsp (*cend))
				cend--;
			
			if (*cend == ')')
				cend--;
			
			g_string_append_len (name, comment + 1, (size_t) (cend - comment));
		}
	}
	
	if (addr && name->len > 0)
		_internet_address_decode_name (addr, name);
	
	g_string_free (name, TRUE);
	
	*in = inptr;
	
	return addr;
}
/**
 * camel_scalix_stream_next_token:
 * @stream: scalix stream
 * @token: scalix token
 *
 * Reads the next token from the scalix stream and saves it in @token.
 *
 * Returns 0 on success or -1 on fail.
 **/
int
camel_scalix_stream_next_token (CamelSCALIXStream *stream, camel_scalix_token_t *token)
{
	register unsigned char *inptr;
	unsigned char *inend, *start, *p;
	gboolean escaped = FALSE;
	size_t literal = 0;
	guint32 nz_number;
	int ret;
	
	g_return_val_if_fail (CAMEL_IS_SCALIX_STREAM (stream), -1);
	g_return_val_if_fail (stream->mode != CAMEL_SCALIX_STREAM_MODE_LITERAL, -1);
	g_return_val_if_fail (token != NULL, -1);
	
	if (stream->have_unget) {
		memcpy (token, &stream->unget, sizeof (camel_scalix_token_t));
		stream->have_unget = FALSE;
		return 0;
	}
	
	token_clear (stream);
	
	inptr = stream->inptr;
	inend = stream->inend;
	*inend = '\0';
	
	do {
		if (inptr == inend) {
			if ((ret = scalix_fill (stream)) < 0) {
				token->token = CAMEL_SCALIX_TOKEN_ERROR;
				return -1;
			} else if (ret == 0) {
				token->token = CAMEL_SCALIX_TOKEN_NO_DATA;
				return 0;
			}
			
			inptr = stream->inptr;
			inend = stream->inend;
			*inend = '\0';
		}
		
		while (*inptr == ' ' || *inptr == '\r')
			inptr++;
	} while (inptr == inend);
	
	do {
		if (inptr < inend) {
			if (*inptr == '"') {
				/* qstring token */
				escaped = FALSE;
				start = inptr;
				
				/* eat the beginning " */
				inptr++;
				
				p = inptr;
				while (inptr < inend) {
					if (*inptr == '"' && !escaped)
						break;
					
					if (*inptr == '\\' && !escaped) {
						token_save (stream, p, inptr - p);
						escaped = TRUE;
						inptr++;
						p = inptr;
					} else {
						inptr++;
						escaped = FALSE;
					}
				}
				
				token_save (stream, p, inptr - p);
				
				if (inptr == inend) {
					stream->inptr = start;
					goto refill;
				}
				
				/* eat the ending " */
				inptr++;
				
				/* nul-terminate the atom token */
				token_save (stream, "", 1);
				
				token->token = CAMEL_SCALIX_TOKEN_QSTRING;
				token->v.qstring = stream->tokenbuf;
				
				d(fprintf (stderr, "token: \"%s\"\n", token->v.qstring));
				
				break;
			} else if (strchr ("+*()[]\n", *inptr)) {
				/* special character token */
				token->token = *inptr++;
				
				if (camel_debug ("scalix:stream")) {
					if (token->token != '\n')
						fprintf (stderr, "token: %c\n", token->token);
					else
						fprintf (stderr, "token: \\n\n");
				}
				
				break;
			} else if (*inptr == '{') {
				/* literal identifier token */
				if ((p = strchr (inptr, '}')) && strchr (p, '\n')) {
					inptr++;
					
					while (isdigit ((int) *inptr) && literal < UINT_MAX / 10)
						literal = (literal * 10) + (*inptr++ - '0');
					
					if (*inptr != '}') {
						if (isdigit ((int) *inptr))
							g_warning ("illegal literal identifier: literal too large");
						else if (*inptr != '+')
							g_warning ("illegal literal identifier: garbage following size");
						
						while (*inptr != '}')
							inptr++;
					}
					
					/* skip over '}' */
					inptr++;
					
					/* skip over any trailing whitespace */
					while (*inptr == ' ' || *inptr == '\r')
						inptr++;
					
					if (*inptr != '\n') {
						g_warning ("illegal token following literal identifier: %s", inptr);
						
						/* skip ahead to the eoln */
						inptr = strchr (inptr, '\n');
					}
					
					/* skip over '\n' */
					inptr++;
					
					token->token = CAMEL_SCALIX_TOKEN_LITERAL;
					token->v.literal = literal;
					
					d(fprintf (stderr, "token: {%zu}\n", literal));
					
					stream->mode = CAMEL_SCALIX_STREAM_MODE_LITERAL;
					stream->literal = literal;
					stream->eol = FALSE;
					
					break;
				} else {
					stream->inptr = inptr;
					goto refill;
				}
			} else if (*inptr >= '0' && *inptr <= '9') {
				/* number token */
				*inend = '\0';
				nz_number = strtoul ((char *) inptr, (char **) &start, 10);
				if (start == inend)
					goto refill;
				
				if (*start == ':' || *start == ',') {
					/* workaround for 'set' tokens (APPENDUID / COPYUID) */
					goto atom_token;
				}
				
				inptr = start;
				token->token = CAMEL_SCALIX_TOKEN_NUMBER;
				token->v.number = nz_number;
				
				d(fprintf (stderr, "token: %u\n", nz_number));
				
				break;
			} else if (is_atom (*inptr)) {
			atom_token:
				/* simple atom token */
				start = inptr;
				
				while (inptr < inend && is_atom (*inptr))
					inptr++;
				
				if (inptr == inend) {
					stream->inptr = start;
					goto refill;
				}
				
				token_save (stream, start, inptr - start);
				
				/* nul-terminate the atom token */
				token_save (stream, "", 1);
				
				if (!strcmp (stream->tokenbuf, "NIL")) {
					/* special atom token */
					token->token = CAMEL_SCALIX_TOKEN_NIL;
					d(fprintf (stderr, "token: NIL\n"));
				} else {
					token->token = CAMEL_SCALIX_TOKEN_ATOM;
					token->v.atom = stream->tokenbuf;
					d(fprintf (stderr, "token: %s\n", token->v.atom));
				}
				
				break;
			} else if (*inptr == '\\') {
				/* possible flag token ("\" atom) */
				start = inptr++;
				
				while (inptr < inend && is_atom (*inptr))
					inptr++;
				
				if (inptr == inend) {
					stream->inptr = start;
					goto refill;
				}
				
				/* handle the \* case */
				if ((inptr - start) == 1 && *inptr == '*')
					inptr++;
				
				if ((inptr - start) > 1) {
					token_save (stream, start, inptr - start);
					
					/* nul-terminate the flag token */
					token_save (stream, "", 1);
					
					token->token = CAMEL_SCALIX_TOKEN_FLAG;
					token->v.atom = stream->tokenbuf;
					d(fprintf (stderr, "token: %s\n", token->v.atom));
				} else {
					token->token = '\\';
					d(fprintf (stderr, "token: %c\n", token->token));
				}
				break;
			} else if (is_lwsp (*inptr)) {
				inptr++;
			} else {
				/* unknown character token? */
				token->token = *inptr++;
				d(fprintf (stderr, "token: %c\n", token->token));
				break;
			}
		} else {
		refill:
			token_clear (stream);
			
			if (scalix_fill (stream) <= 0) {
				token->token = CAMEL_SCALIX_TOKEN_ERROR;
				return -1;
			}
			
			inptr = stream->inptr;
			inend = stream->inend;
			*inend = '\0';
		}
	} while (inptr < inend);
	
	stream->inptr = inptr;
	
	return 0;
}