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