1 /*                             -*- Mode: C++-C -*-
2  *
3  *		 Copyright 1994 Christopher B. Liebman
4  *
5  *     Permission to use, copy, modify, distribute, and sell this software
6  *     and its documentation for any purpose is hereby granted without fee,
7  *     provided that the above copyright notice appear in all copies and that
8  *     both that copyright notice and this permission notice appear in
9  *     supporting documentation, and that the name Christopher B. Liebman not
10  *     be used in advertising or publicity pertaining to distribution of this
11  *     software without specific, written prior permission.
12  *
13  *    THIS SOFTWARE IS PROVIDED `AS-IS'.  CHRISTOPHER B. LIEBMAN, DISCLAIMS
14  *    ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
15  *    LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16  *    PARTICULAR PURPOSE, OR NONINFRINGEMENT.  IN NO EVENT SHALL CHRISTOPHER
17  *    B. LIEBMAN, BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING SPECIAL,
18  *    INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA, OR
19  *    PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
20  *    WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF
21  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author          : Chris Liebman
24  * Created On      : Tue Jan 11 14:11:30 1994
25  * Last Modified By: Chris Liebman
26  * Last Modified On: Sun Feb 20 13:01:44 1994
27  * Update Count    : 38
28  * Status          : Released
29  *
30  * HISTORY
31  *
32  * PURPOSE
33  * 	Routines to handle mail headers.
34 */
35 
36 #ifndef lint
37 static char *RCSid = "$Id: mail_header.c,v 1.2 1994/02/23 13:17:02 liebman Exp $";
38 #endif
39 
40 #include "faces.h"
41 
42 #define	BUFFER_SIZE	80
43 #define	BUFFER_SIZE_INC	80
44 
45 static char*	buffer = NULL;
46 static int	buffer_size = 0;
47 
48 /*
49  *   Read a mail header line from given file.  Handle line continuations.
50  * If the first char is a newln then there are no more headers.
51 */
52 
53 char*
MailHeaderLineRead()54 MailHeaderLineRead()
55 {
56     int		ch;
57     int		string_length = 0;
58     int		get_more;
59     char*	str;
60 
61     /*
62      *  Look at the first char.  If it is a newln then there are no more
63      * headers and the newln is pushed back.  Also return NULL if end of
64      * file.
65     */
66 
67     ch = MailFileReadChar();
68 
69     if (ch == EOF)
70     {
71 	return NULL;
72     }
73 
74     if (ch == '\n')
75     {
76 	MailFileUnReadChar(ch);
77 	return NULL;
78     }
79 
80     /*
81      * If the buffer has not beed created yet then create it.
82     */
83 
84     if (buffer_size == 0)
85     {
86 	buffer = XtMalloc(BUFFER_SIZE);
87 	buffer_size = BUFFER_SIZE;
88     }
89 
90     /*
91      * Ok, start collecting characters.
92     */
93 
94     do
95     {
96 	get_more = 0;
97 
98 	while((ch != '\n') && (ch != EOF))
99 	{
100 	    if (string_length >= buffer_size)
101 	    {
102 		/*
103 		 * Grow buffer.
104 		*/
105 
106 		buffer = XtRealloc(buffer, buffer_size + BUFFER_SIZE_INC);
107 		buffer_size += BUFFER_SIZE_INC;
108 	    }
109 
110 	    buffer[string_length++] = ch;
111 
112 	    ch = MailFileReadChar();
113 	}
114 
115 	/*
116 	 * Ok, We have gotten to the end of a line.  If the first character
117 	 * on the next line is a tab then it is a continuation of this
118 	 * line and we need to skip the tab and continue reading chars.
119 	*/
120 
121 	if (ch != EOF)
122 	{
123 	    /*
124 	     * Get the next character, and if it is a TAB then we continue
125 	     * the loop.
126 	    */
127 
128 	    ch = MailFileReadChar();
129 	    if ((ch == '\t') || (ch == ' '))
130 	    {
131 		get_more = 1;
132 	    }
133 	    else
134 	    {
135 		/*
136 		 * Not a line continuation, put back.
137 		*/
138 
139 		MailFileUnReadChar(ch);
140 	    }
141 	}
142     } while (get_more);
143 
144     /*
145      * Terminate the string.
146     */
147 
148     buffer[string_length] = '\0';
149 
150     /*
151      *  Allocate a buffer that we can return.
152     */
153 
154     str = XtMalloc(string_length + 1);
155     strcpy(str, buffer);
156 
157     return (str);
158 }
159 
160 /*
161  * Read a header line and create a header struct.
162 */
163 
164 MailHeader*
MailHeaderRead()165 MailHeaderRead()
166 {
167     MailHeader*	header;
168     char*	line;
169     char*	p;
170     int		len;
171 
172     /*
173      *   First read a line.
174     */
175 
176     line = MailHeaderLineRead();
177 
178     /*
179      *  No line means no more headers.
180     */
181 
182     if (!line)
183     {
184 	return NULL;
185     }
186 
187 #ifdef DEBUG
188     fprintf(stderr, "read header: <%s>\n", line);
189 #endif
190 
191     /*
192      *  Allocate the header.
193     */
194 
195     header = (MailHeader*) XtMalloc(sizeof(MailHeader));
196     header->name  = NULL;
197     header->value = NULL;
198     header->line  = NULL;
199     header->next  = NULL;
200     header->prev  = NULL;
201 
202     /*
203      *   Now locate the try to parse out the line.  First skip to the:
204      * at the end of this header name (note that we accept a ':' *or*
205      * a ` ` as the terminator.
206     */
207 
208     for (p = line; *p && *p != ':' && *p != ' '; ++p);
209 
210     if (!*p)
211     {
212 	/*
213 	 * Bogus header!  We failed to parse it.
214 	*/
215 
216 	header->line = line;
217 #ifdef DEBUG
218 	fprintf(stderr, "bogus header: <%s>\n", line);
219 #endif
220 	return header;
221     }
222 
223     ++p;
224 
225     /*
226      *  Allocate the name and value.
227     */
228 
229     len = p - line;
230     header->name = XtMalloc(len + 1);
231     strncpy(header->name, line, len);
232     header->name[len] = '\0';
233 
234     header->value = XtMalloc(strlen(p)+1);
235     strcpy(header->value, p);
236 
237     XtFree(line);
238 
239 #ifdef DEBUG
240     fprintf(stderr, "parsed header: <%s> <%s>\n", header->name, header->value);
241 #endif
242     return header;
243 }
244 
245 /*
246  *   Read in all of the mail headers for a mail messages.
247 */
248 
249 MailHeader*
MailHeaderListRead()250 MailHeaderListRead()
251 {
252     MailHeader	*header_head = NULL;
253     MailHeader	*header_tail = NULL;
254     MailHeader	*header;
255 
256 #ifdef DEBUG
257     fprintf(stderr, "reading mail headers...\n");
258 #endif
259 
260     while((header = MailHeaderRead()) != NULL)
261     {
262 	/*
263 	 * We go in the list at the end so there is no next guy.
264 	*/
265 
266 	header->next = NULL;
267 
268 	/*
269 	 *  The last guy on the list is our prev.
270 	*/
271 
272 	header->prev = header_tail;
273 
274 	/*
275 	 *   If there is a prev guy ne are its next.
276 	*/
277 
278 	if (header->prev != NULL)
279 	{
280 	    header->prev->next = header;
281 	}
282 
283 	/*
284 	 *  If there is no head, we are it. This is the
285 	 * first header.
286 	*/
287 
288 	if (header_head == NULL)
289 	{
290 	    header_head = header;
291 	}
292 
293 	/*
294 	 *   We are the tail.
295 	*/
296 
297 	header_tail = header;
298     }
299 
300     return header_head;
301 }
302 
303 void
MailHeaderFree(header)304 MailHeaderFree(header)
305 MailHeader* header;
306 {
307     if (header->name != NULL)
308     {
309 	XtFree(header->name);
310     }
311 
312     if (header->value != NULL)
313     {
314 	XtFree(header->value);
315     }
316 
317     if (header->line)
318     {
319 	XtFree(header->line);
320     }
321 
322     XtFree((void *)header);
323 }
324 
325 void
MailHeaderListFree(list)326 MailHeaderListFree(list)
327 MailHeader*	list;
328 {
329     MailHeader*	header;
330 
331     while(list != NULL)
332     {
333 	header = list;
334 	list = list->next;
335 	MailHeaderFree(header);
336     }
337 }
338 
339 #define	MKLOWER(c)	isupper(c) ? tolower(c) : c
340 
341 static int
HeaderNameCompare(s1,s2)342 HeaderNameCompare(s1, s2)
343 char*	s1;
344 char*	s2;
345 {
346     int	c1, c2;
347 
348     while ((*s1 != '\0') &&
349 	   (*s2 != '\0'))
350     {
351 	c1 = isupper(*s1) ? tolower(*s1) : *s1;
352 	c2 = isupper(*s2) ? tolower(*s2) : *s2;
353 
354 	if (c1 != c2)
355 	{
356 	    break;
357 	}
358 
359 	++s1;
360 	++s2;
361     }
362 
363     return *s1 - *s2;
364 }
365 
366 
367 /*
368  * Locate the named header in the header list.
369 */
370 
371 MailHeader*
MailHeaderFind(name,list)372 MailHeaderFind(name, list)
373 char*		name;
374 MailHeader*	list;
375 {
376     MailHeader	*header;
377 
378     for(header = list; header != NULL; header = header->next)
379     {
380 	if (header->name != NULL && HeaderNameCompare(name, header->name) == 0)
381 	{
382 	    return header;
383 	}
384     }
385 
386     return NULL;
387 }
388 
389 /*
390  * Compare two mail header lists.
391 */
392 
393 int
MailHeaderListCompare(list1,list2)394 MailHeaderListCompare(list1, list2)
395 MailHeader*	list1;
396 MailHeader*	list2;
397 {
398     MailHeader* header1;
399     MailHeader*	header2;
400 
401     for(header1 = list1, header2 = list2;
402 	header1 != NULL && header2 != NULL;
403 	header1 = header1->next, header2 = header2->next)
404     {
405 	int	name1, name2;
406 	int	value1, value2;
407 	int	line1, line2;
408 
409 	name1 = (header1->name != NULL);
410 	name2 = (header2->name != NULL);
411 	value1 = (header1->value != NULL);
412 	value2 = (header2->value != NULL);
413 	line1 = (header1->line != NULL);
414 	line2 = (header2->line != NULL);
415 
416 	/*
417 	 *   Messages must both have or not have names/values/lines.
418 	*/
419 
420 	if ((name1  != name2)  ||
421 	    (value1 != value2) ||
422 	    (line1  != line2))
423 	{
424 	    break;
425 	}
426 
427 	if (name1  && (strcmp(header1->name,  header2->name)  != 0))
428 	{
429 	    break;
430 	}
431 
432 	if (value1 && (strcmp(header1->value, header2->value) != 0))
433 	{
434 	    break;
435 	}
436 
437 	if (line1 &&  (strcmp(header1->line,  header2->line)  != 0))
438 	{
439 	    break;
440 	}
441     }
442 
443     /*
444      * If we got thru all of the headers and both lists are exausted then
445      * the header lists are identicle.
446     */
447 
448     if (header1 == NULL && header2 == NULL)
449     {
450 	return 1;
451     }
452 
453     /*
454      *   Header lists are different.
455     */
456 
457     return 0;
458 }
459 
460