1 
2 #ifndef _mime_h
3 #define _mime_h
4 
5 /* This is a simple general MIME parsing/interpreting structure.
6 
7    Given an iostream, we can parse out the header, and recursively
8    create the MIME entity datastructures.
9  */
10 
11 #include "md5.h"
12 #include "list.tmpl"
13 #include "hash.tmpl"
14 #include "iobottle.h"
15 
16 
17 /* This class encapsulates a MIME entity */
18 class MIME_body {
19 
20 public:
21 	MIME_body(IObottle *RawFile, char *endstrings[],
22 						MIME_body *lineage = NULL);
23 	~MIME_body();
24 
25 	/* Decode a raw header line */
26 	static char *DecodeLine(const char *line);
27 
28 	/* Tell the native character set */
29 	static void MIME_Charset(char *charset);
30 
31 	/* Tell which MIME content-types to ignore */
32 	static void MIME_Ignore(char *ignorelist);
33 
Parent(void)34 	MIME_body *Parent(void) {
35 		return(parent);
36 	}
Content(void)37 	const char *Content(void) {
38 		return(content);
39 	}
IsHTML()40 	bool IsHTML() {
41 		return (strstr(content, "text/html") != NULL);
42 	}
Encoding(void)43 	const char *Encoding(void) {
44 		return(encoding);
45 	}
Name(void)46 	const char *Name(void) {
47 		return(name);
48 	}
NumParts(void)49 	int NumParts(void) {
50 		return(multipart ? 1+multipart->Size() : 1);
51 	}
52 	int AddPart(const char *file, int is_mime = 0);
GetPart(unsigned int which)53 	MIME_body *GetPart(unsigned int which) {
54 		MIME_body **retptr = NULL;
55 
56 		/* We ARE the first part */
57 		if ( which <= 1 )
58 			return(this);
59 
60 		if ( ! multipart )
61 			return(NULL);
62 
63 		multipart->InitIterator();
64 		while ( --which ) {
65 			if ( ! (retptr=multipart->Iterate()) )
66 				break;
67 		}
68 		return(retptr ? *retptr : (MIME_body *)0);
69 	}
70 	int CurrentPart(int which = -1) {
71 		if ( (which > 0) &&
72 			(which <= (1+(multipart ? multipart->Size() : 0))) ) {
73 			currentpart = (which-1);
74 		}
75 		return(currentpart+1);
76 	}
ByName(char * whatname)77 	MIME_body *ByName(char *whatname) {
78 		MIME_body **retptr;
79 		MIME_body  *okay;
80 
81 		/* Base case -- ourselves */
82 		if ( name && (strcmp(name, whatname) == 0) )
83 			return(this);
84 
85 		/* Depth first recursive search on our bodies */
86 		if ( ! multipart )
87 			return(NULL);
88 
89 		multipart->InitIterator();
90 		okay = NULL;
91 		while ( (retptr=multipart->Iterate()) ) {
92 			okay = *retptr;
93 			if ( (okay=okay->ByName(whatname)) )
94 				break;
95 		}
96 		return(okay ? okay : (MIME_body *)0);
97 	}
RawPath(void)98 	const char *RawPath(void) {
99 		return(rawfile->Path());
100 	}
File(void)101 	char *File(void) {
102 		if ( decoded == NULL )
103 			(void) Open();
104 		++bodyref;
105 		return(decoded);
106 	}
FreeFile(void)107 	int FreeFile(void) {
108 		MIME_body **retptr;
109 
110 		/* Decrement reference count on file */
111 		--bodyref;
112 		if ( bodyref > 0 ) { /* File is still in use */
113 			return(0);
114 		}
115 		bodyref = 0;
116 
117 		/* Unlink it */
118 		if ( decoded ) {
119 			(void) unlink(decoded);
120 			decoded = NULL;
121 		}
122 		if ( ! multipart )
123 			return(1);
124 
125 		multipart->InitIterator();
126 		while ( (retptr=multipart->Iterate()) ) {
127 			while ( (*retptr)->FreeFile() == 0 ) {
128 				/* Force the multipart body to close */;
129 			}
130 		}
131 		return(1);
132 	}
133 	int Save(char *filename, int overwrite);
134 
135 	/* Header stuff */
136 	char *GetHeader(char **keyholder);
137 	const char *GetField(const char *str);
138 	void NewField(const char *name, const char *value);
139 
140 	/* Allow searching of MIME bodies */
141 	MIME_body *Search(const char *pattern);
142 
143 	/* Two MIME bodies are equivalent iff they have the same MD5 checksum */
144 	int operator == (MIME_body &other) {
145 		for ( int i=0; i<16; ++i ) {
146 			if ( md5sum[i] != other.md5sum[i] )
147 				return(0);
148 		}
149 		return(1);
150 	}
151 	int operator != (MIME_body &other) {
152 		return( ! (*this == other));
153 	}
154 
155 private:
156 	static char *mime_charset;
157 	static char **mime_ignore;
158 	IObottle *rawfile;		/* The raw MIME data file */
159 	MIME_body *parent;		/* The body of our parent */
160 	Hash<char *> fieldtab;		/* Header fields */
161 	const char *version;		/* MIME version header info */
162 	const char *content;		/* MIME content header info */
163 	const char *encoding;		/* MIME encoding header info */
164 	      char *name;		/* Name associated with MIME body */
165 	long  hstart;			/* Offset of header in file */
166 	long  bstart;			/* Offset of body in file */
167 	char **endstrings;		/* MIME body boundaries */
168 	int   *endlens;			/* Boundary lengths */
169 	int    numends;			/* Number of boundaries */
170 
171 	unsigned char md5sum[16];	/* MD5 Checksum of the MIME body */
172 	char *decoded;			/* The name of the decoded file */
173 	int   bodyref;			/* Reference count on decoded file */
174 	List<MIME_body *> *multipart;
175 	List<IObottle *>  *addedparts;	/* Temp files of parts added */
176 	int   currentpart;		/* The "current" MIME body part */
177 
178 	/* Decode a message creating the 'multipart' list */
179 	int  ParseMulti(MD5_CTX *md5ctx);
180 	void GetWord(const char *src, char **dst);
181 
182 	/* Change this MIME body into a multipart message */
183 	int MultipartMe(char **boundaryptr);
184 
185 	/* Decode the raw body to 'decoded' */
186 	int Open(void);
187 };
188 
189 #endif /* _mime_h */
190