static char rcsid[] = "@(#)$Id: mparse.c,v 1.3 2006/04/09 07:37:08 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.3 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 *                      (was hurtta+elm@ozone.FMI.FI)
 *
 *  Based on mime_parse.c, which is initially 
 *     written by: Michael Elkins <elkins@aero.org>, 1995
 *  Based on parse_util.c (rfc822_reap_comments)
 *****************************************************************************/

#include "headers.h"

DEBUG_VAR(Debug,__FILE__,"config");

char * mime_parse_content_opts (str, walk)
     char *str;
     char **walk;
{
    /* A routine for parsing the options in a Content-Type: - like field.  
     * The important point here is to skip the semi-colon if it appears
     * inside of quotes.  This works sort of like strtok, except that
     * the token is already known.
     */
    char *ptr  = *walk;
    char *ret;
    int in_quote = 0;
    
    /* This is the initialization call */
    if (str) {
	DPRINT(Debug,20,(&Debug, 
			"mime_parse_content_opts: string=%s\n",
		   str));
	ptr = str;
    }    
    /* skip leading spaces */
    while (*ptr && isascii(*ptr) && isspace (*ptr))
	ptr++;

    if (*ptr == '\0') {
	DPRINT(Debug,20,(&Debug, "mime_parse_content_opts=NULL: EOS\n"));
	*walk = ptr;
	return NULL;
    }
    
    ret = ptr;
    while (*ptr) {
	if (*ptr == '\\' && in_quote) {		  
	    /* \ escapes next character  
	     * (not allowed outside of quotes) */
	    ptr++;
	    if (*ptr == '\0')
		break;
	} else if (*ptr == '\"') {
	    if (in_quote)
		in_quote = 0;
	    else
		in_quote = 1;
	}
	else if (! in_quote) {
	    if (*ptr == ';') {
		*ptr++ = '\0';
		DPRINT(Debug,20,(&Debug, "mime_parse_content_opts=%s (token)\n",
				 ret));
		*walk = ptr;
		return (ret);
	    }
	} 
	ptr++;
    }
    DPRINT(Debug,20,(&Debug, "mime_parse_content_opts=%s (token)\n",
		     ret));
    *walk = ptr;
    return (ret);
}

/* Used to get charset argument */
int mime_get_param (name, value, opts, size)
     char *value;
     CONST char *opts, *name;
     int size;
{
    char *c, tmp[VERY_LONG_STRING];
    int i = 0, quoted = FALSE, found = FALSE;
    
    char * WALK = NULL;

    value[0] = '\0';
    
    if (!opts) {
	DPRINT(Debug,20,(&Debug, 
			 "mime_get_param: name=\"%s\", opts=NULL\n",
			 name));
	return 0;
    }

    DPRINT(Debug,20,(&Debug, "mime_get_param: name=\"%s\", opts=\"%s\"\n",
		     name,opts));
    
    /* Make sure not to harm opts */
    strfcpy (tmp, opts, sizeof (tmp));
    rfc822_reap_comments (tmp, NULL, 0);
    
    c = tmp;
    while ((c = mime_parse_content_opts (c, &WALK)) != NULL && !found) {
	char * d  = strchr(c,'=');
	char * d2 = d;
	if (!d) {
	    c = NULL;
	    continue;    /* bad paramater */
	}
	while (d2 > c && (whitespace (*(d2-1))))
	    d2--;
	*d2 = '\0';
	
	while (*c && whitespace(*c))
	    c++;
	
	if (istrcmp (c, name) == 0) {
	    found = TRUE;
	    
	    c = d+1;
	    while (*c && whitespace(*c))
		c++;
	    if (*c == '"') {
		c++;
		quoted = TRUE;
	    }
	    /* Either look for a trailing quoted (if quoted==TRUE) or a SPACE */
	    while (*c && ((quoted && *c != '"') || (!quoted && *c != ' '))) {
		if (*c == '\\' && quoted) {
		    /* \ escapes next character */
		    c++;
		    if (!*c)
			break;
		}
		if (i >= size-1)
		    break;    /* Avoid buffer overflow */
		value[i++] = *c++;
	    }
	    value[i] = '\0';
	    break;
	}
	c = NULL;
    }
    
    DPRINT(Debug,20,(&Debug, 
		     "mime_get_param: found=%d, value=%s\n",found,value));
    
    return found;
}

/* Removes comments from string */
void rfc822_reap_comments (ptr, comments, size) 
     char *ptr, *comments;
     int size;
{
    char *w_ptr = ptr, *c_ptr = comments;
    int comment_level = 0, saved_level = 0;
    int in_quote = 0;
  
    while (*ptr) {
	if (*ptr == '\\' && (in_quote || comment_level > 0)) {		  
	    /* \ escapes next character  
	     * (not allowed outside of quotes or comments) */
	    ptr++;
	    if (*ptr == '\0')
		break;
	    if (comment_level > 0 && comments) {
		if (c_ptr < comments + size - saved_level -3) {
		    *c_ptr++ = '\\';
		    *c_ptr++ = *ptr;
		}
	    }
	    if (comment_level == 0) {
		*w_ptr++ = '\\';
		*w_ptr++ = *ptr;
	    }
	    ptr++;
	    continue;
	} else if (comment_level > 0) {
	    if (*ptr == ')')
		comment_level --;
	    if (*ptr == '(')
		comment_level ++;
	    if (comments && c_ptr < comments + size - saved_level -3) {
		*c_ptr++ = *ptr;
		saved_level = comment_level;
	    }
	} else if (*ptr == '\"') {
      if (in_quote)
	  in_quote = 0;
      else
	  in_quote = 1;
	} else if (!in_quote && *ptr == '(') {
	    comment_level ++;
	    if (comments && c_ptr < comments + size - saved_level -4) {
		if (c_ptr != comments)
		    *c_ptr++ = ' ';
		*c_ptr++ = *ptr;
		saved_level = comment_level;
	    }
	    *w_ptr++ = ' ';  /* RFC 822 (STD 11) says that 
				comments represents one space */
	}
	if (comment_level == 0 && (in_quote || *ptr != ')'))
	    *w_ptr++ = *ptr;
	ptr++;
    }
    while (comments && saved_level > 0) {
	*c_ptr++ = ')';
	saved_level--;
    }
    
    if (comments)
	*c_ptr = '\0';
    *w_ptr = '\0';
}

/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1