#include <ctype.h>
#include <string.h>

#include <stringtools.h>
#include "mimeparse.h"
#include "rfc822.h"

std::string mimeheader2str(const struct mimeheadert &mimeheader)
 {
  std::string dest=mimeheader.value;

  if(mimeheader.subvalue!="") 
   {
    dest+="/";
    dest+=mimeheader.subvalue;
   }

  for(unsigned i=0; i<mimeheader.attributes.size(); i++)
   {
    dest+="; ";
    dest+=mimeheader.attributes[i].name;
    dest+="=\"";
    dest+=mimeheader.attributes[i].value;
    dest+="\"";
   }

  return dest;
 }

mimestructt::mimestructt()
 {
  headerlen=len=offset=0;
 }

bool mimeheadert::findattribute(std::string &dest, const std::string &name) const
 {
  for(unsigned i=0; i<attributes.size(); i++)
    if(stringcasecmp(attributes[i].name, name)==0)
     {
      dest=attributes[i].value;
      return FALSE;
     }

  dest="";

  return TRUE;
 }
 
void mimestructt::mimeparse(rfcmessaget &rfcm)
 {
  std::string text;

  rfcm.parse();

  headerlen=rfcm.headerlen;
  len=rfcm.len;

  rfcm.findsingleheader(text, "Content-Type");
  if(text=="")
    parse_mime_header("text/plain; charset=us-ascii", content_type);
  else
    parse_mime_header(text, content_type);

  rfcm.findsingleheader(text, "Content-Transfer-Encoding");
  parse_mime_header(text, content_transfer_encoding);
  
  rfcm.findsingleheader(text, "Content-Disposition");
  parse_mime_header(text, content_disposition);

  if(stringcasecmp(content_type.value, "multipart")==0)
   {
    std::string boundary, line, boundary1, boundary2;

    content_type.findattribute(boundary, "Boundary");

    boundary1="--"+boundary;
    boundary2=boundary1+"--";

    const char *ptr=rfcm.data+rfcm.headerlen,
               *previous_line=ptr, 
               *subpart_start=NULL;

    while(!getline(rfcm, line, ptr))
     {
      if(line==boundary1 || line==boundary2)
       {
        if(subpart_start!=NULL)
         {
          rfcmessaget subpartm;
          subpartm.data=subpart_start;
          subpartm.endofmail=subpartm.endoffile=previous_line;
          
          if(subpartm.endofmail>subpartm.data) // ignore empty parts
           {
            mimestructt subpart;
            subpart.offset=subpartm.data-rfcm.data+offset;
            subpart.mimeparse(subpartm);

            sub.push_back(subpart);
           }
         }

        if(line==boundary2) break;

        subpart_start=ptr;
       }

      previous_line=ptr;
     }
   }
 }

void parse_mime_header(const std::string &text,
                       mimeheadert &mimeheader)
 {
  std::vector<rfc822symbolt> symbols;
  unsigned i=0;

  parserfc822symbols(text, symbols, ";=/");

  if(symbols[i].type!=rfc822symbolt::ATOM &&
     symbols[i].type!=rfc822symbolt::QUOTED)
    return;

  mimeheader.value=symbols[i++].text;

  if(symbols[i].type!=rfc822symbolt::SPECIAL)
    return;

  if(symbols[i].text=="/") // subtype
   {
    i++;
    mimeheader.subvalue=symbols[i++].text;

    if(symbols[i].type!=rfc822symbolt::SPECIAL)
      return;
   }

  if(symbols[i++].text!=";") return;

  while(symbols[i].type==rfc822symbolt::ATOM ||
        symbols[i].type==rfc822symbolt::QUOTED)
   {
    mimeattributet attribute;
    attribute.name=symbols[i++].text;
    if(symbols[i].type==rfc822symbolt::SPECIAL &&
       symbols[i].text=="=" &&
       (symbols[i+1].type==rfc822symbolt::ATOM ||
        symbols[i+1].type==rfc822symbolt::QUOTED))
     {
      i++;

      do
        attribute.value+=symbols[i++].text;
      while(symbols[i].type==rfc822symbolt::ATOM ||
            symbols[i].type==rfc822symbolt::QUOTED || 
            (symbols[i].type==rfc822symbolt::SPECIAL &&
             symbols[i].text!=";"));

      mimeheader.attributes.push_back(attribute);
     }

    if(symbols[i].type!=rfc822symbolt::SPECIAL ||
       symbols[i].text!=";")
      return;

    i++;
   }
 }


syntax highlighted by Code2HTML, v. 0.9.1