#define DMID 14
// Text & html message processing & formatting functions moved from sw_prcc to sam so can be used both from 
// surgeweb and iphone code

#ifdef __XCODE__
#include "xcode_quiet.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "debug.h"
#include "lib.h"
#include "libwebio.h"
#include "lprintf.h"
#include "parts.h"
#include "prcc.h"
#include "rstring.h"
#include "mime.h"
#include "miconv.h"
#include "decode.h"
#include "defines.h"

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

extern int emsg(const char * arg_list, ...);
extern int dmsg(const char * arg_list, ...);

static int (*imsg)(const char *, ...);
void prcc_set_imsg(int (*fn)(const char *, ...)) 
{
	imsg = fn;
}
static char* (*prcc_tmpfile)(void*,char *);
void prcc_set_tmpfile(char* (*fn)(void*,char *)) 
{
	prcc_tmpfile = fn;
}

// Convert a message text part to to be displayed as html
//  - with reply chevrons stripped, format flowed, paragraph indentation etc
FILE *prcc_wash_fordisplay_text(void *d, FILE *f, int keep_open, char *flow_header)
{
	int n, i, continue_flow=FALSE, new_level, cur_level;
	FILE *f2;
	char bf[BFSZ],bf2[BFSZ],bf_enc[BFSZ],*p,*s,*upto,more[BFSZ];
    int max_len = 200;
#ifdef IS_IOS
    max_len = 57;
#endif        

	if (!f) return NULL;

	// flow_header -> some variables
	new_level=cur_level=0;

	imsg("'text wash' the part for display - starting");

	more[0]=0;
	f2=fopen(prcc_tmpfile(d, bf),"w+b");
	if(!f2){
		emsg("surgeweb: prcc_wash_fordisplay_text failed to open output file [%s]",bf);
		return f;
	}
	for (;!feof(f) || more[0];) {
		
		// Get next line "Dealing with and correcting" plain '\r' characters in our input file
		// Can only hapen if we are dealign with say a QP encoded pard that was originally badly encoded.
		if(more[0]){
			ncpy(bf,more,BFSZ-1);
			more[0]=0;
		} else if (!fgets(bf,BFSZ-1,f)) break;
		s=strchr(bf,'\r');
		if(s && *(s+1)!=0 && *(s+1)!='\n'){
			ncpy(more,s+1,BFSZ-1);
			*s=0;
		}
		// NOTE: Leaving the line feeds in place adds spaces characters in the browser following all lines of text!!!
		lib_strip_crlf_atend(bf);	

		if(strcmp(bf,"-- ")==0){
			fwrite("-- <br>",1,7,f2);
			continue;
		}

		p=s=bf;

		new_level=0;
		if (flow_header!=NULL){
			// Try and "flow" text according to format-flowed
			//  http://www.ietf.org/rfc/rfc3676.txt
			while(*p=='>'){
				p++; s++;
				new_level++;
			}
			n=lib_strlen(bf);
			continue_flow=(n>1&& bf[n-1]==' ');
		}else{
			// indent much like thunderbird and osx mail but no reflow (not to any specification that I know of)
			while(*p=='>'){
				p++; s++;
				new_level++;
				if(strncmp(p," >",2)==0) {
					p++; s++;
				}
			}
		}
		if(cur_level!=new_level){
			while(new_level>cur_level) {
				fwrite("<blockquote type=\"cite\">",1,24,f2);
				cur_level++;
			}
			while(new_level<cur_level){
				fwrite("</blockquote>",1,13,f2);
				cur_level--;
			}
		}
		
		// Make sure spaces at the start of lines are maintained
		if (*p==' ' && *(p+1)==' '){
			while(*p==' '){
				fwrite("&nbsp;",1,6,f2);
				p++;
			}
		}

		// Look for links to make clickable - still need a tidier solution... 
		//		currently does not work for links that cross a 1KB paragraph boundary
		while(*p){
			int len;
			if (!(strncmp(p,"http://",7)==0 || strncmp(p,"https://",7)==0 || strncmp(p,"ftp://",6)==0 || strncmp(p,"ftps://",7)==0 || strncmp(p,"www.",4)==0)){
				p++; continue;
			}
			// Output the stuff we already know about.
			len = (int)(p-s);
			ncpy(bf2,s,(int)(p-s)); 
			for(i=web_encode_real2(bf_enc,bf2,&upto,BFSZ);i;i=web_encode_real2(bf_enc,NULL,&upto,BFSZ))
				fwrite(bf_enc,1,i,f2);
			// Look for end of link			
			s=p;
			while(!(*p==' ' || *p=='\t' || *p=='\0' || *p=='"'|| *p=='\'' || *p=='<' || *p=='>' || *p==')'))p++;
			if(*(p-1)=='.') p--;

			// Output the link
			ncpy(bf2,(strncmp(s,"www.",4)==0)?"http://":"",BFSZ-1); 
			len = (int)(p-s)+lib_strlen(bf2);
			if(len>BFSZ-1) len = BFSZ-1;
			ncat(bf2,s,len); 
			web_encode_real2(bf_enc,bf2,&upto,BFSZ);	// Will trucate any really long URLS (thats ok though for now)

			fprintf(f2,"<a %s href=\"%.900s\">","target=_blank",bf_enc);	// Marijn: 25/5/20 lengthened actual url part (460 -> 900)
            if((int)lib_strlen(bf2)>max_len){
                bf2[max_len]=0;
                ncat(bf2,"...",BFSZ-1); 
                web_encode_real2(bf_enc,bf2,&upto,BFSZ);
            }
			fprintf(f2,"%.460s",bf_enc);
			fprintf(f2,"</a>");
			s=p;
		}	
		// Output everything we have left
		for(i=web_encode_real2(bf_enc,s,&upto,BFSZ);i;i=web_encode_real2(bf_enc,NULL,&upto,BFSZ))
			fwrite(bf_enc,1,i,f2);
		
		if(continue_flow) continue;

		if(lib_strlen(bf)<BFSZ-2)
			fwrite("<br>",1,4,f2);
	}
	while(cur_level>0){
		fwrite("</blockquote>",1,13,f2);
		cur_level--;
	}
	
	if(keep_open){
		fseek(f,0,SEEK_SET);
	}else{
		fclose(f); f=NULL;
	}
	fflush(f2);
	fseek(f2,0,SEEK_SET);

	imsg("text wash complete (? changes made)");

	return f2;
}


FILE *prcc_save_part_as_msg(void *d, FILE *f, SwPart *part, char* raw, int rawsize)
{
	FILE *f2;
	char bf[BFSZ],tmp[BFSZ],*s;
	
	f2=fopen(prcc_tmpfile(d,bf), "w+b");
	fprintf(f2,"MIME-Version: 1.0\r\n");
	lprintf(bf,BFSZ,"%s",part->type);
	ncat_sep(bf,"/",nullok(part->subtype),BFSZ-1);
	s=pair_find(part->hdrs,"charset");
	if(lib_strlen(s)>0){
		lprintf(tmp,BFSZ,"charset=\"%s\"",s);
		ncat_sep(bf,"; ",tmp,BFSZ-1);
	}
	fprintf(f2,"Content-Type: %s\r\n",bf);
	fprintf(f2,"Content-Transfer-Encoding: %s\r\n",part->encoding);
	fprintf(f2,"\r\n");

	if(f){
		for(;!feof(f);){
			if (!fgets(bf,BFSZ,f)) break;
			fprintf(f2,"%s",bf);
		}
		fclose(f);
	}else if(raw){
		fwrite(raw,1,rawsize,f2);
	}else{
		emsg("prcc_save_part_as_msg No data!");
	}
	fflush(f2);
	fseek(f2,0,SEEK_SET);
	return f2;
}

FILE *prcc_save_data_to_msg(void *d, char* raw, int rawsize)
{
	FILE *f2;
	char bf[BFSZ];//,tmp[BFSZ],*s;
	
	f2=fopen(prcc_tmpfile(d,bf), "w+b");
	if(raw){
		fwrite(raw,1,rawsize,f2);
	}else{
		emsg("prcc_save_data_to_msg No data!");
	}
	fflush(f2);
	fseek(f2,0,SEEK_SET);
	return f2;
}

void prcc_find_boundary(char *txt, char *bf)
{
	char *s;
	char *find="boundary=";
	s=strstrnc(txt,find);
	if(!s) return;
	*bf=0;
	s+=strlen(find);
	if(*s=='\"') s++;
	ncpy(bf,s,BFSZ-1);
	s=strchr(bf,'\"');
	if(s) *s=0;
}

// Simplified in momory mime scanner
enum hdr_type {Header_Unwanted, Content_Type, Content_Transfer_Encoding, Content_Disposition};
char *hdr_texts[]={"","Content-Type:", "Content-Transfer-Encoding:", "Content-Disposition", 0};
int hdr_types[]={Header_Unwanted,Content_Type, Content_Transfer_Encoding, Content_Disposition,0};
typedef struct MIMESCAN {
	int inhdr;
	int scanning;
	int isbase64, isquoted, istext, ishtml, isattach;
	int discard_previous;
	char boundary[BFSZ];
} MimeScan;
void mscan_init(MimeScan *ms)
{
	memset(ms, 0, sizeof(MimeScan));
	ms->inhdr = true;
}
int mscan_header_type(char *s, int scanning)
{
	int i;
	if(sisspace(*s)) return scanning;
	scanning=Header_Unwanted;
	for(i=1;hdr_texts[i];i++){
		if(strncmpnc(s,hdr_texts[i],strlen(hdr_texts[i]))!=0) continue;
		scanning=hdr_types[i];
	}
	return scanning;
}
void mscan_process_line(MimeScan *ms, char *s)
{
	if(!ms->inhdr && strlen(ms->boundary)>0 && strstr(s,ms->boundary)!=NULL) {
		//if((ms->istext || ms->ishtml) && strlen(tmp2)>0){
		//	// Ok snippet is complete
		//	break;
		//}
		ms->inhdr=TRUE;
		ms->istext=ms->ishtml=ms->isbase64=ms->isquoted=FALSE;
		ms->isattach=FALSE;
		return;
	}

	if (iseol(*s)) {
		ms->inhdr=FALSE;
		return;
	}
	ms->scanning = mscan_header_type(s, ms->scanning);
	if (ms->scanning == Content_Transfer_Encoding) {
		if (strstrnc(s,"base64")!=NULL) ms->isbase64 = TRUE;
		if (strstrnc(s,"quoted-printable")!=NULL) ms->isquoted = TRUE;
	} else if (ms->scanning == Content_Type){
		if (strstrnc(s,"text/plain")!=NULL) { 
			ms->discard_previous=TRUE;
			ms->istext = TRUE; 
		}
		if (strstrnc(s,"text/html")!=NULL) { 
			if(!ms->istext){
				ms->discard_previous=TRUE;
			}
			ms->istext = FALSE; 
			ms->ishtml = TRUE; 
		}
		prcc_find_boundary(s,ms->boundary);
	} else if (ms->scanning == Content_Disposition){
		if (strstrnc(s,"attachment")!=NULL) { ms->isattach=TRUE;}
	}
}


// snippet handling		// MAX = chars wanted in output. NOT BFSZ!!  (out=BFSZ)
int prcc_snippet_from_text(char *out, int max, char *hdr_in, int hdr_len, char *body_in, int body_len, char *dbg_email, char *dbg_fld, int dbg_uid)
{
	char *pin,*pout,*prcc_start;
	int last_space=TRUE;
	int last_eol=TRUE;
	int ate_some=FALSE;
	int count=0, line_count=0;
	char tmp1[BFSZ+1], tmp2[BFSZ*2+1];
	int len,inhdr=FALSE,scanning=0;
	MimeScan ms;
	tmp2[BFSZ * 2 + 1 - 1] = 'a';
	tmp1[BFSZ + 1 - 1] = 'a';

	if (FALSE) { // chrisp debugging.  
		FILE *f;
		f = fopen("prcc.tmp","wb");
		if (f!=NULL) {
			fprintf(f,"Parameters: max=%d hdr_len=%d body_len=%d\r\n",max,hdr_len,body_len);
			fwrite(hdr_in,1,hdr_len,f);
			fwrite(body_in,1,body_len,f);
			fclose(f);
		}
	}
// chrisp removed some snkppet -- logging just doing general logging tidy up 
	imsg("prcc_snippet_from_text: start %s %s %d", dbg_email, dbg_fld, dbg_uid);
	imsg("prcc_snippet_from_text: hdr_len=%d body_len=%d",hdr_len,body_len);

	out[0]=tmp1[0]=tmp2[0]=0;

	if(!hdr_in || hdr_len==0) return FALSE;
	if(!body_in || body_len==0) return FALSE;

//	imsg("snippet in_len=%d want=%d", body_len, max);

	{
		char *s, boundary[BFSZ], *p1, *p2;
		Strlines lines;
		int x,bflen=BFSZ;
		int stripping_html=FALSE, stripping_css=FALSE;
		int is_body_text=FALSE, done=FALSE, valid_snippet=FALSE;
		boundary[0] = 0;

		mscan_init(&ms);
		str_lines_start(&lines,hdr_in,hdr_len);
		line_count=0;
		//imsg("prcc_snippet_from_text phase 1 uid=%d", dbg_uid);
		while(s = str_lines_next_crlf(&lines,&x)) {
			line_count++;
			//imsg("prcc_snippet_from_text line_count=%d", line_count);
			mscan_process_line(&ms, s);
			if(!ms.inhdr) break;
		}	

		//imsg("prcc_snippet_from_text phase 2");
		str_lines_start(&lines,body_in,body_len);
		while(s = str_lines_next_crlf(&lines,&x)) {
			line_count++;
			//imsg("prcc_snippet_from_text line_count=%d", line_count);

			if (!ms.inhdr && strlen(ms.boundary)>0 && strstr(s,ms.boundary)!=NULL) {
				if((ms.istext || ms.ishtml) && strlen(tmp2)>0){
					// Ok snippet is complete
					break;
				}
			}

			mscan_process_line(&ms, s);
			if (ms.inhdr) continue;
			if (ms.isattach) break;
			if (ms.discard_previous) {
				tmp2[0]=0;
				ms.discard_previous = FALSE;
			}
			if (iseol(*s)) continue;
			if (!(ms.istext || ms.ishtml)) continue;

			if (ms.isquoted) {
				len = mime_decode_quoted(s,tmp1,BFSZ-1); 
				tmp1[len] = 0;
			} else if(ms.isbase64){
				len = mime_decode_base64(s,tmp1,BFSZ-1);
				tmp1[len] = 0;
			} else {
				ncpy(tmp1,s,BFSZ-1);
			}

			// kinda need charset decoding too. maybe add sometime?
			
			// simple, fast in memory html/css stripping
			//	has known limits in terms of chunking possibly breaking it
			//  of that becomes an issue use something more like sw_prcc_wash_fordisplay_html but should keep memory 
			//  based for speed purposes
			if(ms.ishtml){
				char *find;
				p2=tmp2+strlen(tmp2);
				
				for(p1=tmp1; *p1; p1++){
					if(stripping_css){
						find="</style";
						if(strncmp(p1,find,strlen(find))==0) {
							stripping_css = false;
						}
					}
					if(stripping_html){
						if(*p1!='>') {
							continue;
						}
						p1++;
						stripping_html=false;
					}
					if(*p1=='<'){
						find="<style";
						if(strncmp(p1,find,strlen(find))==0) {
							stripping_css = true;
						}
						stripping_html=true;
						continue;
					}
					find="&nbsp;";
					if(strncmp(p1,find,strlen(find))==0) {
						p1+=strlen(find)-1; continue;
					}
					if(stripping_css) continue;
					if (p2 - tmp2 >= BFSZ * 2 - 1) { // Chrisp fix to prevent overrun on 'tmp2' buffer.
						imsg("snippet truncated\n");
						break;
					}
					else {
						*p2++ = *p1;
					}
				}
				*p2=0;

			}else{
				ncat(tmp2, tmp1, BFSZ*2-1);
			}
		}	
	}

	//imsg("prcc_snippet_from_text phase 3");

	// Now lets actually consolidate the text we have
	prcc_start = tmp2;
	for(pin=prcc_start,pout=out;*pin;pin++) {
		count++;
		if((pin-prcc_start)>body_len) break;
		if(count%3000==0) imsg("snippet prcc %d", count); // chrisp increased to 3000 as log was full of it...
		if((pout-out)>=(max-12)){  // was 3, didn't leave space for null. or larger example with [] or case where it adds [] at th eend...
			strcpy(pout,"..."); pout+=3;
			break;	// the loop
		}
		if(last_eol){
			if(*pin=='>' || sw_isreply_line(pin)){
				for(;!iseol(*pin);pin++){}
				if(*pin=='\0') break;
				ate_some=TRUE;
			}
			last_eol=FALSE;
		}
        
        // Test early as test below may not always get hit (eg >3 consecutive \n characters)
        if(*pin=='\r' || *pin=='\n') {
            last_eol=TRUE;
        }
        
        // remove excess if more than 3 consecutive characters of any kind
        if(pin>prcc_start+3 && *pin==*(pin-1) && *pin==*(pin-2) && *pin==*(pin-3)){
            while(*pin==*(pin+1)){
                pin++;
            }
            continue;
        }

		switch(*pin) {
		case '\r': 
		case '\n': 
			last_eol=TRUE;
		case '\t':
		case ' ':
			if(last_space) break;
			*pout++=' ';
			last_space=TRUE;
			break;

		default:
				
			if(ate_some){strcpy(pout,"[...] "); pout+=6; ate_some=FALSE;}
			last_space=FALSE;
			*pout++=*pin;
			break;
		}
	}
	//imsg("prcc_snippet_from_text phase 4");

    if(ate_some){
        strcpy(pout,"[...]"); 
        pout+=5; 
        ate_some=FALSE;
    }
	*pout++='\0';
	// Guard checks, lets see which string it is
	if (tmp2[BFSZ * 2 + 1 - 1] != 'a') lib_abort(); // crashing here! 
	if (tmp1[BFSZ + 1 - 1] != 'a') lib_abort();

	return TRUE;
}

int prcc_clean_quoted(char *out, char *in, int max)	// MAX chars wanted in output. NOT BFSZ!!  (out=BFSZ)
{
	char *pin,*pout;
	int last_space=TRUE;
	int last_eol=TRUE, last2_eol=FALSE;
	int ate_some=FALSE;
    int multiple_reply_lines=FALSE;
	
	ncpy(out,"",BFSZ-1);
	if(!in) return FALSE;
	for(pin=in,pout=out;*pin;pin++) {
		if((pout-out)>=(max-3)){
			strcpy(pout,"..."); pout+=3;
			break;	// the loop
		}
		if(last_eol){
			if(*pin=='>' || sw_isreply_line(pin)){
                if(multiple_reply_lines){
                    for(;!iseol(*pin);pin++){}
                    ate_some=TRUE;
                    if(*pin=='\r') pin++;
    //				if(*pin=='\n') pin++;
                    last_eol=TRUE;
                    continue;
                }else{
                    multiple_reply_lines = TRUE;
                }
			}else{
                multiple_reply_lines = FALSE;
            }
		}
		
		switch(*pin) {
			case '\n': 
				if (last2_eol) break;
				if (last_eol) last2_eol=TRUE;
				last_eol=TRUE;
				last_space=FALSE;
				*pout++=*pin;
				break;
			case '\r': 
				if (last2_eol) break;
				last_space=FALSE;
				*pout++=*pin;
				break;

			case '\t':
			case ' ':
				*pout++=' ';
				last_space=TRUE;
				break;
				
			default:				
				if(ate_some){strcpy(pout,"\r\n[...]\r\n\r\n"); pout+=11; ate_some=FALSE;}
				last_space=FALSE;
				last_eol=last2_eol=FALSE;
				*pout++=*pin;
				break;
		}
	}
	if(ate_some){strcpy(pout,"[...] "); pout+=6; ate_some=FALSE;}
	*pout++='\0';
	return TRUE;
}


int prcc_snippet_from_file(char *out, FILE *f, int max)	// MAX chars wanted in output. NOT BFSZ!!  (out=BFSZ)
{
	return prcc_snippet_from_file_keepf(out, f, max, FALSE);
}
int prcc_snippet_from_file_keepf(char *out, FILE *f, int max, int keepf)	// MAX chars wanted in output. NOT BFSZ!!  (out=BFSZ)
{
	char *pin,*pout, bf[BFSZ];
	int last_space=TRUE;
	int ate_some=FALSE;
	int done=FALSE;

	pout=out;
	for (;!feof(f);) {
		if (!fgets(bf,BFSZ-1,f)) break;
		lib_strip_crlf(bf);
		if (lib_strlen(bf)==0) continue;
		if(bf[0]=='>' || (bf[0]==' ' && bf[1]=='>') || sw_isreply_line2(bf)){
			ate_some=TRUE;
			continue;
		}
		if(!last_space){
			*pout++=' ';
			last_space=TRUE;
		}
		for(pin=bf;*pin;pin++) {
			if((pout-out)>=(max-3)){
				strcpy(pout,"..."); pout+=3;
				goto done;
			}
			switch(*pin) {
			case '\t':
			case ' ':
				if(last_space) break;
				*pout++=' ';
				last_space=TRUE;
				continue;
			default:
				if(ate_some){strcpy(pout,"[...] "); pout+=6; ate_some=FALSE;}
				last_space=FALSE;
				*pout++=*pin;
				break;
			}
		}
	}
	*pout++='\0';
done:
	if(keepf){
		fseek(f,0,SEEK_SET);
	}else{
		fclose(f); f=NULL;
	}
	return TRUE;
}

// Catch "replied to" lines in plain text emails
int sw_isreply_line(char *pin)
{
	char in_bf[BFSZ],line1[BFSZ], line2[BFSZ], *p, *s;
	int syntax1, syntax2, count=0;

	ncpy(in_bf, pin, BFSZ-1);
	
	for(p=in_bf,s=line1;*p&&!(iseol(*p));*s++=*p++){}
	*s='\0';
	for(;*p&&iseol(*p);p++){}
	for(s=line2;*p&&!(iseol(*p));*s++=*p++){}
	*s='\0';
	if(!p) return FALSE;
	if(line2[0]!='>') return FALSE;
	// SYNTAX1:  On Tuesday 31/08/2010 at 9:40 am, Chrisp wrote:
	syntax1 = (strstr(line1,"On ")!=0 && strchr(line1,',') && strstr(line1,"wrote:"));
	// SYNTAX2:  Marijn wrote at 9:39 am on Tue, Aug 31 2010:
	syntax2 = (strstr(line1,"wrote at")!=0 && strchr(line1,',') && strchr(line1,':'));
	if(!syntax1&&!syntax2) return FALSE;
	return TRUE;
}
// Catch "replied to" lines in line by line basis (possibly need to make more reliable through read ahead)
int sw_isreply_line2(char *pin)
{
	char tmp[BFSZ], line[BFSZ];
	int syntax1, syntax2;

	ncpy(tmp,pin,BFSZ-1);
	lib_strip_crlf(tmp);
	lib_trim_spaces(tmp,line);

	// SYNTAX1:  On Tuesday 31/08/2010 at 9:40 am, Chrisp wrote:
	syntax1 = (lib_starts_with(line,"On ")!=0 && strchr(line,',') && lib_ends_with(line,"wrote:") && (strchr(line,'.')==NULL));
	// SYNTAX2:  Marijn wrote at 9:39 am on Tue, Aug 31 2010:
	syntax2 = (strstr(line,"wrote at")!=0 && strchr(line,',') && lib_ends_with(line,":") && (strchr(line,'.')==NULL));
	if(!syntax1&&!syntax2) return FALSE;
	return TRUE;
}

int prcc_file_to_mem(FILE *f, char **bf, int *out_size)
{
	unsigned int size;
	*out_size=0;
	
	size=lib_file_osize(f);
	*bf=calloc(1,size+1);
	if(!*bf) return FALSE;
	
	if(fread(*bf, 1, size, f)!=size){
		free(*bf);
		*bf=NULL;
		return FALSE;
	}
	
	*out_size=size;
	return TRUE;
}
int prcc_fname_to_mem(char *fname, char **bf, int *out_size)
{
	unsigned int size;
	int ret=FALSE;
	FILE *f;
	*out_size=0;

	f=fopen(fname,"rb");
	if(!f) return FALSE;
	
	size=lib_file_osize(f);
	*bf=calloc(1,size+1);
	if(!*bf) goto done;

	if(fread(*bf, 1, size, f)!=size){
		free(*bf);
		*bf=NULL;
		goto done;
	}
	*out_size=size;
	ret=TRUE;
done:
	fclose(f);		
	return ret;
}

// Copy of cimap_decode_content (logic NOT rewritten or checked)  also see prcc_decode_content2
int prcc_decode_content(SwPart *prt, char *content)
{
//	int i;
//	char var[BFSZ];
//	char val[BFSZ];
	char content_copy[BFSZ];
	char bf[BFSZ];
	char *p[101];
	char *s;
	int np;
//	char *e;

	ncpy(content_copy,content,BFSZ-1);
	np = token_split(content_copy,p,";",100);
	if (np<1) return FALSE;
	
	/* Get type and subtype e.g. text/plain */
	ncpy(bf,p[0],BFSZ-1);
	lib_strip_crlf(bf);
	s = strchr(bf,' '); if (s!=NULL) *s = 0;
	s = strchr(bf,'"'); if (s!=NULL) *s = 0;
	s = strchr(bf,'/');
	strupr(bf);
	if (s!=NULL) {
		*s = 0;
		ffree(prt->subtype);
		prt->subtype=strdup(s+1);
	}
	ffree(prt->type);
	prt->type=strdup(bf);
//	imsg(im,"part (%s) (%s)\n",prt->type,prt->subtype);
//printf("part (%s) (%s)\n",prt->type,prt->subtype);

	/* Now get list of 'pairs' remove quotes and add to pair array.*/
/*	for (i=1; i<np; i++) {
		s = p[i];
		for (;*s==' ' || *s=='\t';s++) ;
		ncpy(var,s,BFSZ-1);
		s = strchr(var,'=');
		if (s!=NULL) {
			*s = 0;
			s++;
			for (;*s==' ' || *s=='\t';s++) ;
			if (*s=='"') {
				s++;
				e = strchr(s,'"'); if (e!=NULL) *e = 0;
			} else {
				e = strchr(s,' '); if (e!=NULL) *e = 0;
			}
			ncpy(val,s,BFSZ-1);
		}
		s = strchr(var,' '); if (s!=NULL) *s = 0;
		pair_add(&prt->info,var,val);
	}
*/
	return TRUE;	
}
// Copy of cimap_decode_content (logic NOT rewritten or checked) also see prcc_decode_content
int prcc_decode_content2(Pair **pr, char *content)
{
	char bf[BFSZ];
	char *p[101];
	char *s;
	int np;

	np = token_split(content,p,";",100);
	if (np<1) return FALSE;
	
	/* Get type and subtype e.g. text/plain */
	ncpy(bf,p[0],BFSZ-1);
	lib_strip_crlf(bf);
	s = strchr(bf,' '); if (s!=NULL) *s = 0;
	s = strchr(bf,'"'); if (s!=NULL) *s = 0;
	s = strchr(bf,'/');
	strupr(bf);
	if (s!=NULL) {
		*s = 0;
		pair_add(pr,"subtype",s+1);
	}
	pair_add(pr,"type",bf);

	return TRUE;
}

// Much like sw_extract_part but without iconv currently... may still want to combine??
FILE *prcc_extract_part(void *d, FILE *f, char *part, Pair**prt_hdrs, int decode, char *fout_name)
{
    return prcc_extract_part_keepf(d, f, part, prt_hdrs, decode, fout_name, FALSE);
}

FILE *prcc_extract_part_keepf(void *d, FILE *f, char *part, Pair**prt_hdrs, int decode, char *fout_name, int keepf)
{
	Mime *m = NULL;
	Miconv *ic=NULL;
	char raw[BFSZ],bin[BFSZ],*s;
	int k,len,x;
	FILE *f2=NULL;
	int count=0;
	char bf[BFSZ],tmp[BFSZ],tmp2[BFSZ];

	imsg("extracting message part (%s) to temp file", part);

	mime_new(&m);
	ic=miconv_new("UTF-8");
	dmsg("looking for correct part");
	// Looking for part
	m->append_lines = TRUE;
	while(k = mime_line(m,f,raw,bin,&len,BFSZ-1)) {
		mime_log("mime input :",raw,k,dmsg);
		switch(k) {
		case MIME_END:
			break;
		case MIME_HEADER_END:		// End of top level headers or inner headers
			break;
		case MIME_CONTENT:			// "Content-Type" header outer or inner level
			break;
		case MIME_HEADER:
			break;					// Any other outer or inner header
		case MIME_BODY:
			break;
		case MIME_BOUNDARY:			// Actual boundary line, from here onwards the m->part is valid
			break;
		}
		if (strncmp(m->part,part,lib_strlen(part)) == 0) 
			break;
	}
	dmsg("In theory we are at the correct part");

	f2=fopen(fout_name!=NULL?fout_name:prcc_tmpfile(d, bf),"w+b");
	if(!f2){
		emsg("surgeweb: Could not save file in prcc_extract_part");
		fseek(f,0,SEEK_SET);
		return NULL;
	}

	// Part found, now dealing with the stuff we actually want
	while(k = mime_line(m,f,raw,bin,&len,BFSZ-1)) {
		mime_log("mime input :",raw,k,dmsg);
		if (strncmp(m->part,part,lib_strlen(part)) != 0){ 
			dmsg("breaking out of mime loop");
			break;
		}
		switch(k) {
		case MIME_CONTENT:
		case MIME_HEADER:
			s = raw;
			lib_copy_upto(&s,':',bf,BFSZ);
			if (*s == ':'){
				if (prt_hdrs){
					ncpy(tmp,m->content,BFSZ-1);
					lib_strip_crlf(tmp);
					mime_header_decode(tmp,tmp2,BFSZ-1);
					pair_add(prt_hdrs,bf,tmp2);
					if (strcmpnc(bf,"Content-Type")==0 || strcmpnc(bf,"Content-Disposition")==0){
						prcc_decode_content2(prt_hdrs, tmp);
						if (m->fname && m->fname[0]){
							mime_header_decode(m->fname,tmp2,BFSZ-1);
							pair_add(prt_hdrs,"name",tmp2);
						}
					}
				}
				if (strcmpnc(bf,"Content-Type")==0 && prcc_parse_charset(s+1,bf,BFSZ)){
					miconv_set(ic,bf); // possibly use miconv_set2
				}
			}
			break;
		case MIME_BOUNDARY:
			break;
		case MIME_END:
			break;
		case MIME_BODY:
			break;
		}

		if (k == MIME_HEADER) {
		
		}

		s = bin;
		if (len) {
			if (decode && (x = miconv(ic,bin,len)) != 0) {
				s = miconv_res(ic);
				len = x;
			}
		}
		mime_log("mime output:",s,k,dmsg);
		fwrite(s,1,len,f2);
	}
	miconv_free(&ic);
	mime_free(&m);
	// if fout_name is specified do not do the filehandle shuffle
	dmsg("Done extracting message part");
	if(fout_name){
		fseek(f,0,SEEK_SET);
		fclose(f2); f2=NULL;
		return NULL;
	}else{
		fclose(f); f=NULL;
		fflush(f2);
		fseek(f2,0,SEEK_SET);
		return f2;
	}
}

int prcc_parse_charset(char *content, char *res, int bfsz)
{
	char *p = strstrnc(content,"charset");
	if (!p) return FALSE;
	p+=7;
	while(sisspace(*p)) p++;
	if(*p!='=') return FALSE;
	p++;
	while(sisspace(*p)) p++;
	if (*p == '\"') {p++; lib_copy_upto_any(&p,"\";\r\n",res,bfsz);}
	else lib_copy_upto_any(&p," ;\r\n",res,bfsz);
	
	if (strcmpnc(res,"iso-8859-1")==0)
		ncpy(res,"windows-1252",bfsz-1);
	
	return TRUE;
}

//int prcc_set_iconv()

// TODO: Turn into a lib function / or use existing??
char *mystrtok_ex(char *start, char *toks, char **upto)
{
	char *s=start;
	int in_quoted=FALSE;
	if (start!=NULL && upto) *upto = NULL;
	if (s==NULL && upto) s = *upto;
	if (s==NULL) return NULL;
	for (;*s!=0;s++) {
		if (strchr(toks,*s)==NULL) break;
	}
	if (*s==0) return NULL;
	start = s;
	for (;*s!=0;s++) {
		if (*s=='"') in_quoted = !in_quoted;
		if (in_quoted) continue;
		if (strchr(toks,*s)!=NULL) break;
	}
	if (*s==0) {
		if (upto) *upto = NULL;
		return start;
	}
	*s = 0;
	if (upto) *upto = s+1;
	return start;
}

int prcc_addresses(Pair **rcpts, char *txt, int for_display)
{
	char *tmp, *s, *upto, bf2[BFSZ], *p;
	char from_email[BFSZ], from_name[BFSZ];
	int i=0,len;

	tmp=strdup(txt);
	// marijn: (12/12/17) Removed this cleanup code as ? are valid inside double quotes and 
	// it means we don't pass the test on https://www.mailsploit.com/index
	// not sure what it was originally for... I believe Q/B encoding bug that was fixed years ago
	//s=strchr(tmp,'?');
	//if(s && (s>tmp+1) && *(s-1)!='=') *s=0; 
	i=lib_strlen(tmp);
	for(s = mystrtok_ex(tmp,",;\r\n\t",&upto); s; s = mystrtok_ex(NULL,",;\r\n\t",&upto)) {
		for(p=s;*p&&strchr("\r\n\t ",*p);p++){}
		lib_split_email_name(p,from_email,from_name,BFSZ-1);

		len=lib_strlen(from_email);
		if(len==0) continue;
		if(len>200) {
			from_email[200]=0;
			len=200;
		}

		// Also strip single quotes from 'Email name'
		len=lib_strlen(from_name);
		if(len>200) {
			from_name[200]=0;
			len=200;
		}
		if(from_name[0]=='\'' && from_name[len-1]=='\''){
			ncpy(bf2,from_name,BFSZ-1);
			bf2[len-1]='\0';
			ncpy(from_name,bf2+1,BFSZ-1);
		}
		
		// SEARCH: COMMA IN ADDRESS
		if(for_display && lib_strlen(from_name)>0 && (strchr(from_name,',')!=NULL || strchr(from_name,';')!=NULL))
			lprintf(bf2,BFSZ,"\"%s\"",from_name);
		else
			lprintf(bf2,BFSZ,"%s",from_name);
		pair_add_atend(rcpts,from_email,bf2);
	}
	free(tmp);
	return TRUE;
}

// Encode suitably for email (short mime encoded strings)
// Previously only used for text, now to be used for html as well.
FILE *prcc_mime_encode_qp(void *d, FILE *f, int *prcc)
{
	int last_blank=FALSE, remain=0, eol, len;
	char bf[BFSZ],bf2[BFSZ*3],*s, *start=NULL;
	FILE *f2;

	f2=fopen(prcc_tmpfile(d, bf),"w+b");
	if(!f2){
		emsg("surgeweb: prcc_mime_encode_qp failed to open output file [%s]",bf);
		return f;
	}
	for (;!feof(f);) {
		if (!fgets(bf,BFSZ-1-remain,f)) break;
		if (bf[0]=='\0' && last_blank) continue;
		eol=lib_strip_crlf_x(bf);
		mime_encode_quoted_real(bf,lib_strlen(bf),bf2+remain,BFSZ*3-1-remain,prcc);
		// Now split it into short quoted printable encoded chunks
		for (s=start=bf2;*s;s++){
			if(s-start<75) continue;
			if(*(s+1)=='\0') break;
			while(*(s)=='=' || *(s-1)=='='){ s--; }	// Make sure we do not fall within encoded characters
			ncpy(bf,start,(int)(s-start)+1);
			fprintf(f2,"%s=\r\n",bf);
			start=s+1;
		}
		if (!eol){	// Buffer size hit so don't output
			remain=lib_strlen(start);
			if(bf2!=start)
				safe_memmove(bf2,start,remain+1,bf2,BFSZ*3);
		}else{
			len=lib_strlen(start);
			if(len>0 && start[len-1]==' '){
				strcpy(&start[len-1],"=20");	// Forcibly keep trailing spaces to keep these (per RFC and for format=flowed)
			}
			fprintf(f2,"%s\r\n",start);
			remain=0;
		}
		if (bf[0]=='\0') last_blank=TRUE;
	}
	if(remain){
		fprintf(f2,"%s\r\n",start);	
	}
	fclose(f); f=NULL;
	fflush(f2);
	fseek(f2,0,SEEK_SET);
	return f2;
}

FILE *prcc_base64_mime(void *d, FILE *f)
{
	char bf[BFSZ], data[BFSZ];
	int len;
	FILE *f2;

	f2=fopen(prcc_tmpfile(d, bf),"w+b");
	if(!f2){
		emsg("surgeweb: prcc_base64_mime failed to open output file [%s]",bf);
		return f;
	}
	for (;!feof(f);) {
		len = (int)fread(data,1,57,f);
		if (len<=0) break;
		encode_base64(data,bf,len+1);
		fprintf(f2,"%s\r\n",bf);
	}
	fclose(f); f=NULL;
	fflush(f2);
	fseek(f2,0,SEEK_SET);
	dmsg("Done converting to base64");
	return f2;
}

// Reflow processing ** begin **
int prcc_reflow_output_qdepth(FILE *f, int depth)
{
	char bf[BFSZ];
	int i;

	if(depth==0) return TRUE;

	for (i=0;i<depth;i++){
		bf[i]='>';
		if(i>=MAX_QUOTE_DEPTH) break; 
	}
	bf[i]='\0';
	fprintf(f,"%s",bf);
	return TRUE;
}
int prcc_reflow_write_line(Reflow *ff, char *cur, int type)
{
    //imsg("FF: write [%s]", ff->start);
	char *space_stuff=" ", *end_line="\r\n";
	if (ff == NULL) lib_abort();
	if(type==REFLOW_FLOWED){
		end_line=" \r\n";
	}else if(type==REFLOW_FIXED){
		// No spaces can exist at end of fixed line as per RFC
		while(*ff->end==' ' && ff->end > ff->start){
			ff->end='\0';
			ff->end--;
		}
	}
	if(type!=REFLOW_FLOWED && ff->has_crlf_last==FALSE){
		// No prefix required
	}else{
		prcc_reflow_output_qdepth(ff->f2, ff->qdepth_cur);
		if( *ff->start!='\0'&&ff->qdepth_cur>0 || *ff->start=='>' )
			fwrite(space_stuff,1,lib_strlen(space_stuff),ff->f2);
	}
	fwrite(ff->start, 1, cur - ff->start, ff->f2);
	if(type!=REFLOW_NOCRLF){
		fwrite(end_line,1,lib_strlen(end_line),ff->f2);
	}
	if(type==REFLOW_FIXED || type==REFLOW_NOCRLF){
		ff->start=ff->end=ff->buf;
		ff->buf[0]='\0';
	}else{
		ff->start=cur+1;
	}
	fflush(ff->f2);

	return TRUE;
}
int prcc_reflow_write_flush(Reflow *ff)	// Flush by definition means it has not been flowed and is of type REFLOW_FIXED
{	
	char  *space_stuff=" ", *end_line="\r\n";
	if(ff->start==ff->end) 
		return TRUE;	// nothing to flush
	// As per RFC strip of any end of line spaces of a fixed line in format-flowed (else it would become a flowed line!)
	while(*(ff->end-1)==' ' && ff->end-1 > ff->start) 
		ff->end--;
	prcc_reflow_output_qdepth(ff->f2, ff->qdepth_cur);
	if(ff->qdepth_cur>0 && *ff->start!='>')
		fwrite(space_stuff,1,lib_strlen(space_stuff),ff->f2);
	fwrite(ff->start, 1, ff->end - ff->start, ff->f2);
	fwrite(end_line,1,lib_strlen(end_line),ff->f2);
	fflush(ff->f2);

	ff->buf[0]='\0';
	ff->start=ff->end=ff->buf;
	return TRUE;
}
int reflow_has_char(char* s)
{
	for(;*s;s++){
		if(sisspace(*s))
			continue;
		return TRUE;
	}
	return FALSE;
}

// Encode as suitably format flowed (short mime encoded strings)
FILE *prcc_reflow(void *d, FILE *f, int *too_wide)
{
    return prcc_reflow_real(d, f, too_wide, FALSE);
}
FILE *prcc_reflow_real(void *d, FILE *f, int *too_wide, int top_level_unflowed)
{
	int last_blank=FALSE, remain=0, qdepth;
	char bf[BFSZ],*s;
	Reflow rf, *ff=&rf;

	imsg("prcc_reflow start");
	memset(ff, 0, sizeof(Reflow));
	ff->has_crlf=TRUE;
	ff->start=ff->end=ff->buf;
	ff->flowed_some=FALSE;
	ff->f2=fopen(prcc_tmpfile(d, bf),"w+b");
	if(!ff->f2){
		emsg("surgeweb: prcc_reflow failed to open output file [%s]",bf);
		return f;
	}
	for (;!feof(f);) {
		// Read input line
		if (!fgets(bf,BFSZ-1,f)) break;
        s=bf;   // for the mac debugger ;-)
		ff->has_crlf_last=ff->has_crlf;
		ff->has_crlf=lib_strip_crlf_x(bf);

		//if (bf[0]=='\0' && last_blank) continue; // Strip out multitudes of blank lines (probably this should actually be part of another routing)
		imsg("prcc_reflow chunk read");
		
		if(!ff->has_crlf_last){
			// keep exsting quotation depth etc if chunk is part of same paragraph
			s=bf;
		}else{
			// Start of line Work out quote level
			for (s=bf,qdepth=0;s&&qdepth<MAX_QUOTE_DEPTH; s++){
				if(*s!='>') break;
				qdepth++;
			}
			// Remove space stuffing as per RFC (our internal ipnut format does not use space stuffing but that is compatible)
			if (qdepth>0 && *s==' ')
				s++;
		}

		// deal with changes in quotation level
		if(ff->qdepth_cur!=qdepth)
			prcc_reflow_write_flush(ff);
		ff->qdepth_cur=qdepth;

		// We get chunks of BFSZ coming in, but need to know "what comes next" when writing a FF line so use our own bigger buffer
		// saves messing around with retry loops etc :-) At the end of wrapping loop there should NEVER be more than BFSZ in ff->buf
		ncpy( ff->end, s, (BFSZ*2-1)-(int)(ff->end-ff->buf));
		ff->end+=lib_strlen(s);
		ff->flowed_some=FALSE;
        
        //imsg("FF1: %d [%s]", lib_strlen(ff->start), ff->start);

		if(ff->end==ff->start){
			// Empty line
			prcc_reflow_write_line(ff,ff->start, REFLOW_FIXED);
			continue;
		}

		//imsg("prcc_reflow trying reflow");

		// step through character by character reflowing if we can
		for(s=ff->start; s<(ff->buf+BFSZ*2-1); s++){

			// end of buffer
			if(*s=='\0'){
				if(!ff->has_crlf) 
					break;	// try for more
				if(s==ff->start || (*(s-1)==' ' && !top_level_unflowed && qdepth!=0))
					break;	// try for more
				if(ff->flowed_some){
//					imsg("flowed some?");
// MW: BAD this is catching normal format flowed lines in html messages during send!!!
// Not sure exactly what condition I was trying to catch. Lets remove completely again for now
//					break;	// try for more
				}
				// Output our "fixed" line
				prcc_reflow_write_flush(ff);
				break;
			}

            //imsg("FF2: %d [%s]", lib_strlen(s), s);

			// no need to wrap or reflow yet...
			if(s-ff->start<70)
				continue;

			if(!reflow_has_char(s))
				continue;

            //imsg("FF3: %d [%s]", lib_strlen(s), s);

			//imsg("prcc_reflow actioning reflow 1");

			// step backwards (looking for first natural space to break on)
			while(*s!=' ' && s>ff->start+1)
				s--;
			if (*s==' ') {
				// wordbreak found, output flowedline and reset ff->start
				prcc_reflow_write_line(ff,s, REFLOW_FLOWED);
				ff->flowed_some=TRUE;
				continue;
			} 

            //imsg("FF4: %d [%s]", lib_strlen(s), s);

			imsg("prcc_reflow actioning reflow 2");

			// No short words so try for a long word no wider that 997 chars
			while(*s!=' ' && s<bf+BFSZ*2-1){
				if(*s=='\0') break;
				if(s-ff->start>997){
					*too_wide=TRUE;
				}
				s++;
			}

			imsg("prcc_reflow actioning reflow 3");

			if (*s==' ' && *(s+1)!='\0') {
				// wordbreak found, output long word flowedline and reset ff->start
				prcc_reflow_write_line(ff,s, REFLOW_FLOWED);
				continue;
			} 

			imsg("prcc_reflow actioning reflow 4");

			*too_wide=TRUE;

            //imsg("FF5: %d [%s]", lib_strlen(s), s);

			// end of buffer hit, means there should be more to come so output but do not flow the line
			prcc_reflow_write_line(ff,s, !ff->has_crlf ? REFLOW_NOCRLF : (*s==' ' ? REFLOW_FLOWED : REFLOW_FIXED));
			break;
		}
		if (ff->end - ff->start > BFSZ){
			// text that cannot be reflowed. Just output it (message itself will get QP encoded) so we can continue flowed processing
			prcc_reflow_write_line(ff,s+1, REFLOW_NOCRLF);
			*too_wide=TRUE;
		}
		if (ff->end - ff->start > 0){
			safe_memmove(ff->buf,ff->start,(int)(ff->end-ff->start),ff->buf,BFSZ);
			ff->end=ff->buf+(ff->end - ff->start);
			ff->start=ff->buf;
			*ff->end='\0';
		}else if(ff->end==ff->start && ff->start!=ff->buf){
			ff->start = ff->end = ff->buf;
			*ff->end='\0';
		}
	}

	// Flush the output buffer;
	prcc_reflow_write_flush(ff);

	imsg("prcc_reflow end");

	fclose(f); f=NULL;
	fflush(ff->f2);
	fseek(ff->f2,0,SEEK_SET);
	return ff->f2;
}

// Reflow processing ** end **

int prcc_count_chars(FILE *f, int *total, int *high)
{
	unsigned char bf[BFSZ];
	int len;

	for (;!feof(f);) {
		if (!fgets(bf,BFSZ-1,f)) break;
		for (len=lib_strlen(bf)-1;len>=0;len--){
//			if(sisprint(bf[len])){
			if(bf[len]>0x7f){
				(*high)++;
			}
			(*total)++;
		}
	}
	
	fseek(f,0,SEEK_SET);
	return TRUE;
}

// MW: I don't seem to be able fnd an existing function to 
char *strip_nbsp(char *out, char *s, int bfsz) {
	int i;

	for(i = 0; i < bfsz && *s; i++, s++) {
		if (*s == '&') {
			if (strncmp(s,"&nbsp;",6)==0) {
				out[i] = ' ';
				s += 5;
			}else{
				out[i] = *s;
			}
		}
		else out[i] = *s;
	}
	out[i] = '\0';
	return out;
}
char *to_nbsp(char *out, char *s, int bfsz) {
	int i;
	for(i = 0; i < bfsz && *s; i++, s++) {
		if (*s==-96 || sisspace(*s)) {
			ncpy(out+i,"&nbsp;",bfsz-i);
			i += 5;
		}
		else out[i] = *s;
	}
	out[i] = '\0';
	return out;
}

// This routine is getting a bit ugly, but it is only a processing step tying other
// other more standard processing actions together and it is not used that often...
FILE *prcc_web_cleanup(void *d, FILE *f)
{
	char bf[BFSZ],bf2[BFSZ];
	int len,eol;
	FILE *f2;

	f2=fopen(prcc_tmpfile(d, bf),"w+b");
	if(!f2){
		emsg("surgeweb: sw_prcc_web_cleanup failed to open output file [%s]",bf);
		return f;
	}
	for (;!feof(f);) {
		if (!fgets(bf,BFSZ-1,f)) break;
		eol=lib_strip_crlf_x(bf);
		strip_nbsp(bf2,bf,BFSZ);
		len=lib_strlen(bf2);
		if(len<BFSZ-100)
			len=lib_trim_spaces_end(bf2);

		fwrite(bf2,1,len,f2);
		if(eol)
			fwrite("\n",1,1,f2);
	}
	
	fclose(f); f=NULL;
	fflush(f2);
	fseek(f2,0,SEEK_SET);
	return f2;
}
FILE *prcc_msg_to_ical(void *d, FILE *f)
{
	return prcc_msg_to_ical_raw(d, f, TRUE);
}
FILE *prcc_msg_to_ical_raw(void *d, FILE *f, int close)
{
	Mime *m = NULL;
	Miconv *ic=NULL;
	char raw[BFSZ],bin[BFSZ];
	int k,len;
	FILE *f2=NULL;
	int count=0, cal_found = FALSE, cal_prcc = FALSE;
	char bf[BFSZ], *fout_name=NULL;

	f2=fopen(fout_name!=NULL?fout_name:prcc_tmpfile(d, bf),"w+b");
	if(!f2){
		emsg("surgeweb: Could not save file in prcc_msg_to_ical");
		fclose(f); f=NULL;
		return NULL;
	}

	mime_new(&m);
	while(k = mime_line(m,f,raw,bin,&len,BFSZ-1)) {
		switch(k){
			case MIME_CONTENT: {
				if((strstrnc(raw, "content-type")!=0) && (strstrnc(raw, "text/calendar")!=0)){
					cal_prcc = true;
				}
			} break;
			case MIME_BODY: {
				if(cal_prcc){
					fwrite(bin, 1, len, f2);				
					cal_found = true;
				}
			} break;
			case MIME_HEADER: {
				if(cal_found){
					cal_prcc = false;
				}
			} break;
		}
	}

	if(close){
		fclose(f); f=NULL;
	}
	fflush(f2);
	fseek(f2,0,SEEK_SET);
	return f2;
}
