/* * parser_rfc822.c * * Copyright (C) 2003 Bastian Blank * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include int di_parser_rfc822_read (char *begin, size_t size, di_parser_info *info, di_parser_read_entry_new entry_new, di_parser_read_entry_finish entry_finish, void *user_data) { char *cur, *end; char *field_begin, *field_end; #if MODIFIER char *field_modifier_begin, *field_modifier_end; #endif char *value_begin, *value_end; #ifndef HAVE_MEMRCHR char *temp; #endif int nr = 0; size_t readsize; size_t field_size; #if MODIFIER size_t field_modifier_size; #endif size_t value_size; const di_parser_fieldinfo *fip = NULL; di_rstring field_string; di_rstring field_modifier_string; di_rstring value_string; void *act = NULL; cur = begin; end = begin + size; while (cur < end) { if (*cur == '\n') { cur++; continue; } nr++; if (entry_new) act = entry_new (user_data); else act = NULL; while (1) { field_begin = cur; readsize = end - field_begin; if (!readsize) break; field_end = memchr (cur, ':', readsize); #if MODIFIER field_modifier_end = field_end; #endif if (!field_end) { di_warning ("parser_rfc822: Iek! Don't find end of field!"); return -1; } field_size = field_end - field_begin; #if MODIFIER #ifdef HAVE_MEMRCHR if ((field_modifier_begin = memrchr (field_begin, '-', field_end - field_begin))) field_modifier_begin++; if (field_modifier_begin) #else field_modifier_begin = field_begin; while ((temp = memchr (field_modifier_begin, '-', field_end - field_modifier_begin))) field_modifier_begin = temp + 1; if (field_modifier_begin != field_begin) #endif { field_modifier_size = field_modifier_end - field_modifier_begin; } else { field_modifier_begin = 0; field_modifier_size = 0; } #endif value_begin = field_end + 1; while (value_begin < end && (*value_begin == ' ' || *value_begin == '\t')) value_begin++; readsize = end - field_begin; value_end = memchr (field_begin, '\n', readsize); if (!value_end) { di_warning ("parser_rfc822: Iek! Don't find end of value!"); return -1; } if (value_end < field_end) { di_warning ("parser_rfc822: Iek! Don't find end of field, it seems to be after the end of the line!"); return -1; } /* while (isblank (value_end[1])) FIXME: C99 */ while (value_end[1] == ' ' || value_end[1] == '\t') { readsize = end - value_end + 1; if ((value_end = memchr (value_end + 1, '\n', readsize)) == NULL) { di_warning ("Iek! Don't find end of large value\n"); return -1; } } value_size = value_end - value_begin; field_string.string = field_begin; field_string.size = field_size; value_string.string = value_begin; value_string.size = value_size; fip = di_hash_table_lookup (info->table, &field_string); if (fip) { fip->read (&act, fip, NULL, &value_string, user_data); goto next; } #if MODIFIER if (info->wildcard) goto wildcard; else if (!info->modifier) goto next; field_string.size = field_size - field_modifier_size - 1; fip = di_hash_table_lookup (info->table, &field_string); if (fip) { field_modifier_string.string = field_modifier_begin; field_modifier_string.size = field_modifier_size; fip->read (&act, fip, &field_modifier_string, &value_string, user_data); goto next; } #endif if (!info->wildcard) goto next; #if MODIFIER wildcard: #endif field_string.size = 0; fip = di_hash_table_lookup (info->table, &field_string); if (fip) { field_modifier_string.string = field_begin; field_modifier_string.size = field_size; fip->read (&act, fip, &field_modifier_string, &value_string, user_data); } next: cur = value_end + 1; if (cur >= end || *cur == '\n') break; } if (entry_finish && entry_finish (act, user_data)) return -1; } return nr; } int di_parser_rfc822_read_file (const char *file, di_parser_info *info, di_parser_read_entry_new entry_new, di_parser_read_entry_finish entry_finish, void *user_data) { struct stat statbuf; char *begin; int fd, ret = -1; if ((fd = open (file, O_RDONLY)) < 0) return ret; if (fstat (fd, &statbuf)) goto cleanup; if (!statbuf.st_size) { ret = 0; goto cleanup; } begin = mmap (NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (begin == MAP_FAILED) goto cleanup; madvise (begin, statbuf.st_size, MADV_SEQUENTIAL); ret = di_parser_rfc822_read (begin, statbuf.st_size, info, entry_new, entry_finish, user_data); munmap (begin, statbuf.st_size); cleanup: close (fd); return ret; } static void callback (const di_rstring *field, const di_rstring *value, void *data) { FILE *f = data; fwrite (field->string, field->size, 1, f); fputs (": ", f); fwrite (value->string, value->size, 1, f); fputs ("\n", f); } int di_parser_rfc822_write_file (const char *file, di_parser_info *info, di_parser_write_entry_next entry_next, void *user_data) { int nr = 0; const di_parser_fieldinfo *fip; void *act = NULL, *state_data = NULL; di_slist_node *node; FILE *f; char tmpfile[PATH_MAX]; if (!strncmp (file, "-", 1)) { tmpfile[0] = '\0'; f = stdout; } else { snprintf (tmpfile, sizeof (tmpfile), "%s.tmp", file); f = fopen (tmpfile, "w"); } if (!f) return -1; while (1) { act = entry_next (&state_data, user_data); if (!act) break; nr++; for (node = info->list.head; node; node = node->next) { fip = node->data; if (fip->write) fip->write (&act, fip, callback, f, user_data); } fputc ('\n', f); } if (*tmpfile) { fclose (f); if (rename (tmpfile, file)) return -1; } return nr; }