%%{
  machine content_type_parser;

  action Disposition_Start {
  }

  action Disposition_End {
  }

  action Disposition_Inline {
    cd->type = RSPAMD_CT_INLINE;
  }

  action Disposition_Attachment {
    cd->type = RSPAMD_CT_ATTACHMENT;
  }

  action Param_Name_Start {
    qstart = NULL;
    qend = NULL;
    pname_start = p;
    pname_end = NULL;
  }

  action Param_Name_End {
    if (qstart) {
      pname_start = qstart;
    }
    if (qend && qend >= qstart) {
      pname_end = qend;
    }
    else if (p >= pname_start) {
      pname_end = p;
    }
    qstart = NULL;
    qend = NULL;
  }


  action Param_Value_Start {
    qstart = NULL;
    qend = NULL;

    if (pname_end) {
      pvalue_start = p;
      pvalue_end = NULL;
    }
  }


  action Param_Value_End {
    if (pname_end) {
      if (qstart) {
        pvalue_start = qstart;
      }
      if (qend && qend >= qstart) {
        pvalue_end = qend;
      }
      else if (p >= pvalue_start) {
        pvalue_end = p;
      }
      qstart = NULL;
      qend = NULL;

      if (pvalue_end && pvalue_end > pvalue_start && pname_end > pname_start) {
        rspamd_content_disposition_add_param (pool, cd, pname_start, pname_end, pvalue_start, pvalue_end);
      }
    }

    pname_start = NULL;
    pname_end = NULL;
    pvalue_start = NULL;
    pvalue_end = NULL;
    qend = NULL;
    qstart = NULL;
  }

  action Quoted_Str_Start {
    qstart = p;
    qend = NULL;
  }

  action Quoted_Str_End {
    if (qstart) {
      qend = p;
    }
  }

  include smtp_base "smtp_base.rl";
  include content_disposition "content_disposition.rl";

  main := content_disposition;

}%%

#include "smtp_parsers.h"
#include "content_type.h"

%% write data;

gboolean
rspamd_content_disposition_parser (const char *data, size_t len, struct rspamd_content_disposition *cd, rspamd_mempool_t *pool)
{
  const char *p = data, *pe = data + len, *eof, *qstart = NULL, *qend = NULL,
    *pname_start = NULL, *pname_end = NULL, *pvalue_start = NULL, *pvalue_end = NULL;
  int cs, *stack = NULL;
  gsize top = 0;
  struct _ragel_st_storage {
    int *data;
    gsize size;
  } st_storage;

  memset (&st_storage, 0, sizeof (st_storage));
  memset (cd, 0, sizeof (*cd));
  eof = pe;

  %% write init;
  %% write exec;

  if (st_storage.data) {
    free (st_storage.data);
  }

  return cd->type != RSPAMD_CT_UNKNOWN;
}
